diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 8 | ||||
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 10 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp | 4 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp | 2 | ||||
-rw-r--r-- | test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp | 2 |
6 files changed, 49 insertions, 13 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e5bba692a0..d45f87cf36 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4045,6 +4045,14 @@ let CategoryName = "Lambda Issue" in { def ext_lambda_default_arguments : ExtWarn< "C++11 forbids default arguments for lambda expressions">, InGroup<LambdaExtensions>; + def err_noreturn_lambda_has_return_expr : Error< + "lambda declared 'noreturn' should not return">; + def warn_maybe_falloff_nonvoid_lambda : Warning< + "control may reach end of non-void lambda">, + InGroup<ReturnType>; + def warn_falloff_nonvoid_lambda : Warning< + "control reaches end of non-void lambda">, + InGroup<ReturnType>; } def err_operator_arrow_circular : Error< diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 71bf3359ea..2d609001d4 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -218,7 +218,8 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_HasNoReturn; unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; - bool funMode; + enum { Function, Block, Lambda } funMode; + bool IsLambda; SourceLocation FuncLoc; static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { @@ -250,7 +251,7 @@ struct CheckFallThroughDiagnostics { else D.diag_NeverFallThroughOrReturn = 0; - D.funMode = true; + D.funMode = Function; return D; } @@ -266,13 +267,28 @@ struct CheckFallThroughDiagnostics { diag::err_falloff_nonvoid_block; D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_block; - D.funMode = false; + D.funMode = Block; + return D; + } + + static CheckFallThroughDiagnostics MakeForLambda() { + CheckFallThroughDiagnostics D; + D.diag_MaybeFallThrough_HasNoReturn = + diag::err_noreturn_lambda_has_return_expr; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::warn_maybe_falloff_nonvoid_lambda; + D.diag_AlwaysFallThrough_HasNoReturn = + diag::err_noreturn_lambda_has_return_expr; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::warn_falloff_nonvoid_lambda; + D.diag_NeverFallThroughOrReturn = 0; + D.funMode = Lambda; return D; } bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, bool HasNoReturn) const { - if (funMode) { + if (funMode == Function) { return (ReturnsVoid || D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) == DiagnosticsEngine::Ignored) @@ -284,9 +300,9 @@ struct CheckFallThroughDiagnostics { == DiagnosticsEngine::Ignored); } - // For blocks. - return ReturnsVoid && !HasNoReturn - && (!ReturnsVoid || + // For blocks / lambdas. + return ReturnsVoid && !HasNoReturn + && ((funMode == Lambda) || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) == DiagnosticsEngine::Ignored); } @@ -888,7 +904,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() - : CheckFallThroughDiagnostics::MakeForFunction(D)); + : (isa<CXXMethodDecl>(D) && + cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && + cast<CXXMethodDecl>(D)->getParent()->isLambda()) + ? CheckFallThroughDiagnostics::MakeForLambda() + : CheckFallThroughDiagnostics::MakeForFunction(D)); CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index a163779959..afbabacc73 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1857,12 +1857,18 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { QualType FnRetType = CurCap->ReturnType; assert(!FnRetType.isNull()); - if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) + if (BlockScopeInfo *CurBlock = dyn_cast<BlockScopeInfo>(CurCap)) { if (CurBlock->FunctionType->getAs<FunctionType>()->getNoReturnAttr()) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); return StmtError(); } - // FIXME: [[noreturn]] for lambdas! + } else { + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap); + if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){ + Diag(ReturnLoc, diag::err_noreturn_lambda_has_return_expr); + return StmtError(); + } + } // Otherwise, verify that this result type matches the previous one. We are // pickier with blocks than for normal functions because we don't have GCC diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp index a67b5c01fd..68460f0354 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp @@ -3,7 +3,9 @@ // An attribute-specifier-seq in a lambda-declarator appertains to the // type of the corresponding function call operator. void test_attributes() { - auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}} + auto nrl = [](int x) -> int { if (x > 0) return x; }; // expected-warning{{control may reach end of non-void lambda}} + + auto nrl2 = []() [[noreturn]] { return; }; // expected-error{{lambda declared 'noreturn' should not return}} } template<typename T> diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp index 627071343e..9dbe2e189f 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p7.cpp @@ -2,7 +2,7 @@ // Check that analysis-based warnings work in lambda bodies. void analysis_based_warnings() { - (void)[]() -> int { }; // expected-warning{{control reaches end of non-void function}} + (void)[]() -> int { }; // expected-warning{{control reaches end of non-void lambda}} } // Check that we get the right types of captured variables (the diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp index baa29ea944..14491cc3b2 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -2,7 +2,7 @@ template<typename T> void test_attributes() { - auto nrl = []() [[noreturn]] {}; // expected-warning{{function declared 'noreturn' should not return}} + auto nrl = []() [[noreturn]] {}; // expected-error{{lambda declared 'noreturn' should not return}} } template void test_attributes<int>(); // expected-note{{in instantiation of function}} |