c++14 vs c++17 different ast for lambda?

Hi,

I am trying to investigate bug in the tool based on
libclang. The problem is that with -std=c++14 and -std=c++17
for code like this:

#define signals public
class QObject {
signals:
        void destroyed();
public:
        template<typename F>
        static void connect(QObject *, void (QObject::*mf)(void), F f) {}
        void deleteLater();
};

void test(QObject *o1, QObject *o2)
{
    QObject::connect(o1, &QObject::destroyed,
                    [=] { o2->deleteLater(); });
}

clang dumps different AST. Is this intentional because of
difference in handling of lambdas in c++14 and c++17 or this is
some kind of bug?

In case of -std=c++14 (clang++ -std=c++14 -Xclang -ast-dump -c test.cpp)
3rd argument (lambda) passed to QObject::connect looks like this:
CXXConstructExpr 0x5589e3278970 <line:14:21, col:46> '(lambda at test.cpp:14:21)':'(lambda at test.cpp:14:21)' 'void ((lambda at test.cpp:14:21) &&) noexcept' elidable
          `-MaterializeTemporaryExpr 0x5589e3275cd0 <col:21, col:46> '(lambda at test.cpp:14:21)' xvalue
            `-LambdaExpr

in case of -std=c++17 lambda looks like this:
   `-LambdaExpr 0x5641f55db880 <line:14:21, col:46> '(lambda at test.cpp:14:21)'

I think this is intentional: a lambda expression returns a prvalue, which is

1. then used to copy-construct the argument in C++14, but
2. directly initialized the argument (guaranteed copy elision) in C++ 17

Jesse

I'm not sure what "the tool" is, but there are multiple places where clang generates a different AST based on the C++ dialect, including simple implicit constructions. See

https://clang.llvm.org/docs/LibASTMatchersReference.html#traverse-mode

and

https://steveire.wordpress.com/2021/02/14/ast-matchmaking-made-easy/

If you are not using AST Matchers, you might find it useful to call `Expr::IgnoreUnlessSpelledInSource()`.

Thanks,

Stephen.

I'm not sure what "the tool" is,

clazy https://invent.kde.org/sdk/clazy
I am not author of it, just user who found out that it doesn't produce
some warnings in case of "-std=c++17".

It tries match LambdaExpr as argument of function call via traverse of
clang::Stmt childs, but doesn't expect it in the "parent stmt":
https://invent.kde.org/sdk/clazy/-/blob/0dbfa9f3a715924d8fd315897228bfe415afb92b/src/checks/level1/connect-3arg-lambda.cpp#L76
https://invent.kde.org/sdk/clazy/-/blob/0dbfa9f3a715924d8fd315897228bfe415afb92b/src/HierarchyUtils.h#L112

but there are multiple places where clang
generates a different AST based on the C++ dialect, including simple
implicit constructions. See

https://clang.llvm.org/docs/LibASTMatchersReference.html#traverse-mode

and

https://steveire.wordpress.com/2021/02/14/ast-matchmaking-made-easy/

If you are not using AST Matchers, you might find it useful to call
`Expr::IgnoreUnlessSpelledInSource()`.

What about MaterializeTemporaryExpr? In other "checks" it is used,
to catch when implicitly shared object used in expression where
it can be "deep copied" by accident.

Looks like your fix has been merged! :slight_smile: