Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -59,23 +59,62 @@ : public StmtVisitor { Expr *DefaultArg; Sema *S; + bool CompoundStmtSeen; + + // The set of variables declared in this default argument expression. + llvm::SmallPtrSet Decls; + + template + bool VisitFunctionDecl(FuncDeclTy *Func) { + for (ParmVarDecl *PD : Func->parameters()) + Decls.insert(PD); + return Visit(Func->getBody()); + } public: CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) - : DefaultArg(defarg), S(s) {} + : DefaultArg(defarg), S(s), CompoundStmtSeen(false) {} bool VisitExpr(Expr *Node); + bool VisitStmt(Stmt *Node); + bool VisitCompoundStmt(CompoundStmt *Node); + bool VisitDeclStmt(DeclStmt *Node); bool VisitDeclRefExpr(DeclRefExpr *DRE); bool VisitCXXThisExpr(CXXThisExpr *ThisE); + bool VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node); + bool VisitGenericSelectionExpr(GenericSelectionExpr *Node); bool VisitLambdaExpr(LambdaExpr *Lambda); + bool VisitBlockExpr(BlockExpr *Block); bool VisitPseudoObjectExpr(PseudoObjectExpr *POE); }; /// VisitExpr - Visit all of the children of this expression. bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { + return VisitStmt(Node); + } + + bool CheckDefaultArgumentVisitor::VisitStmt(Stmt *Node) { + bool IsInvalid = false; + for (Stmt *SubStmt : Node->children()) + IsInvalid |= Visit(SubStmt); + return IsInvalid; + } + + bool CheckDefaultArgumentVisitor::VisitCompoundStmt(CompoundStmt *Node) { + CompoundStmtSeen = true; + return VisitStmt(Node); + } + + bool CheckDefaultArgumentVisitor::VisitDeclStmt(DeclStmt *Node) { bool IsInvalid = false; + + for (const auto *D : Node->decls()) + if (const auto *VD = dyn_cast(D)) + Decls.insert(VD); + for (Stmt *SubStmt : Node->children()) IsInvalid |= Visit(SubStmt); + return IsInvalid; } @@ -84,6 +123,11 @@ /// argument expression. bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { NamedDecl *Decl = DRE->getDecl(); + + if (auto *VD = dyn_cast(Decl)) + if (Decls.count(VD)) + return false; + if (ParmVarDecl *Param = dyn_cast(Decl)) { // C++ [dcl.fct.default]p9 // Default arguments are evaluated each time the function is @@ -119,6 +163,26 @@ << ThisE->getSourceRange(); } + bool CheckDefaultArgumentVisitor::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *Node) { + // Ignore unevaluated expressions such as sizeof. + return false; + } + + bool CheckDefaultArgumentVisitor::VisitGenericSelectionExpr( + GenericSelectionExpr *Node) { + // Ignore the controlling expression and all the association expressions + // except the result expression. Those expressions are unevaluated. + if (!Node->isResultDependent()) + return Visit(Node->getResultExpr()); + + bool IsInvalid = false; + for (Expr *AE : Node->getAssocExprs()) + IsInvalid |= Visit(AE); + + return IsInvalid; + } + bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) { bool Invalid = false; for (PseudoObjectExpr::semantics_iterator @@ -140,11 +204,22 @@ // C++11 [expr.lambda.prim]p13: // A lambda-expression appearing in a default argument shall not // implicitly or explicitly capture any entity. - if (Lambda->capture_begin() == Lambda->capture_end()) - return false; + // Lambda expressions in a block scope can have captures. + if (!CompoundStmtSeen && Lambda->capture_begin() != Lambda->capture_end()) + return S->Diag(Lambda->getLocStart(), + diag::err_lambda_capture_default_arg); + + if (CXXMethodDecl *CO = Lambda->getCallOperator()) + return VisitFunctionDecl(CO); + + return false; + } - return S->Diag(Lambda->getLocStart(), - diag::err_lambda_capture_default_arg); + bool CheckDefaultArgumentVisitor::VisitBlockExpr(BlockExpr *Block) { + if (BlockDecl *BD = Block->getBlockDecl()) + return VisitFunctionDecl(BD); + + return false; } } Index: test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp =================================================================== --- test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp +++ test/CXX/dcl.decl/dcl.meaning/dcl.fct.default/p7.cpp @@ -1,7 +1,10 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// expected-no-diagnostics void h() { int i; - extern void h2(int x = sizeof(i)); // expected-error {{default argument references local variable 'i' of enclosing function}} + // Do not warn about local variables referenced in default arguments if it is + // in an unevaluated expression. + extern void h2(int x = sizeof(i)); } Index: test/SemaCXX/default1.cpp =================================================================== --- test/SemaCXX/default1.cpp +++ test/SemaCXX/default1.cpp @@ -78,3 +78,60 @@ void PR20769_b(int = 1); void PR20769_b() { void PR20769_b(int = 2); } + +#if __cplusplus >= 201103L // C++11 or later +struct S2 { + template + S2(T&&) {} +}; + +template +void func0(int a0, S2 a1 = [](){ (void)&a0; }); // expected-error {{default argument references parameter 'a0'}} + +template +void func1(T a0, int a1, S2 a2 = _Generic((a0), default: [](){ (void)&a1; }, int: 0)); // expected-error {{default argument references parameter 'a1'}} + +template +void func2(S2 a0 = [](){ + int t; [&t](){ (void)&t;}(); +}); + +template +void func3(int a0, S2 a1 = [](){ + [=](){ (void)&a0;}(); // expected-error {{default argument references parameter 'a0'}} +}); + +double d; + +void test1() { + int i; + float f; + void foo0(int a0 = _Generic((f), double: d, float: f)); // expected-error {{default argument references local variable 'f' of enclosing function}} + void foo1(int a0 = _Generic((d), double: d, float: f)); + void foo2(int a0 = _Generic((i), int: d, float: f)); + void foo3(int a0 = _Generic((i), default: d, float: f)); + + void foo4(S2 a0 = [&](){ (void)&i; }); // expected-error {{lambda expression in default argument cannot capture any entity}} + void foo5(S2 a0 = [](){ + // No warning about capture list of a lambda expression defined in a block scope. + int t; [&t](){ (void)&t;}(); + }); + void foo6(int a0, S2 a1 = [](){ + // No warning about local variables or parameters referenced by an + // unevaluated expression. + int t = sizeof({i, a0;}); + }); + void foo6(S2 a0 = [](){ + int i; // expected-note {{'i' declared here}} + void foo7(int a0, // expected-note {{'a0' declared here}} + S2 a1 = [](){ (void)&a0; }); // expected-error {{variable 'a0' cannot be implicitly captured in a lambda with no capture-default specified}} expected-error {{default argument references parameter 'a0'}} expected-note {{lambda expression begins here}} + void foo8(S2 a0 = [](){ (void)&i; }); // expected-error {{variable 'i' cannot be implicitly captured in a lambda with no capture-default specified}} expected-error {{default argument references local variable 'i' of enclosing function}} expected-note {{lambda expression begins here}} + }); + + func0(1); // expected-error {{no matching function for call to 'func0'}} + func1(1); // expected-error {{no matching function for call to 'func1'}} + func2(); + func3(1); // expected-error {{no matching function for call to 'func3'}} +} + +#endif Index: test/SemaObjCXX/blocks.mm =================================================================== --- test/SemaObjCXX/blocks.mm +++ test/SemaObjCXX/blocks.mm @@ -169,3 +169,17 @@ return b; // expected-error {{no viable conversion from returned value of type 'MoveBlockVariable::B0' to function return type 'MoveBlockVariable::B1'}} } } + +namespace DefaultArg { +void test() { + id x; + void func0(id a0, id a1 = ^{ (void)&a0; }); // expected-error {{default argument references parameter 'a0'}} + void func1(id a0, id a1 = ^{ (void)&x; }); // expected-error {{default argument references local variable 'x' of enclosing function}} + void func2(id a0, id a1 = ^{ (void)sizeof(a0); }); + void func3(id a0 = ^{ (void)sizeof(x); }); + void func4(id a0, id a1 = ^{ + ^{ (void)&a0; }(); // expected-error {{default argument references parameter 'a0'}} + [=](){ (void)&a0; }(); // expected-error {{default argument references parameter 'a0'}} + }); +} +}