From: David Majnemer Date: Fri, 25 Oct 2013 09:12:52 +0000 (+0000) Subject: Sema: Do not allow lambda expressions to appear inside of constant expressions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9d33c40838367ffcc3206a7120a0ce32922b66d8;p=clang Sema: Do not allow lambda expressions to appear inside of constant expressions We would previously not diagnose this which would lead to crashes (on very strange code). This fixes PR17675. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@193397 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 21aad683ea..441ad4ccac 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -5067,6 +5067,8 @@ let CategoryName = "Lambda Issue" in { def note_lambda_decl : Note<"lambda expression begins here">; def err_lambda_unevaluated_operand : Error< "lambda expression in an unevaluated operand">; + def err_lambda_in_constant_expression : Error< + "a lambda expression may not appear inside of a constant expression">; def err_lambda_return_init_list : Error< "cannot deduce lambda return type from initializer list">; def err_lambda_capture_default_arg : Error< diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index c842ed035d..69f8f2e739 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10962,13 +10962,22 @@ void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); if (!Rec.Lambdas.empty()) { - if (Rec.isUnevaluated()) { - // C++11 [expr.prim.lambda]p2: - // A lambda-expression shall not appear in an unevaluated operand - // (Clause 5). + if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { + unsigned D; + if (Rec.isUnevaluated()) { + // C++11 [expr.prim.lambda]p2: + // A lambda-expression shall not appear in an unevaluated operand + // (Clause 5). + D = diag::err_lambda_unevaluated_operand; + } else { + // C++1y [expr.const]p2: + // A conditional-expression e is a core constant expression unless the + // evaluation of e, following the rules of the abstract machine, would + // evaluate [...] a lambda-expression. + D = diag::err_lambda_in_constant_expression; + } for (unsigned I = 0, N = Rec.Lambdas.size(); I != N; ++I) - Diag(Rec.Lambdas[I]->getLocStart(), - diag::err_lambda_unevaluated_operand); + Diag(Rec.Lambdas[I]->getLocStart(), D); } else { // Mark the capture expressions odr-used. This was deferred // during lambda expression creation. diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index c843da74cd..2e1cd105a9 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1229,20 +1229,25 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, CaptureInits, ArrayIndexVars, ArrayIndexStarts, Body->getLocEnd(), ContainsUnexpandedParameterPack); - // C++11 [expr.prim.lambda]p2: - // A lambda-expression shall not appear in an unevaluated operand - // (Clause 5). + if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { + // C++11 [expr.prim.lambda]p2: + // A lambda-expression shall not appear in an unevaluated operand + // (Clause 5). case Unevaluated: case UnevaluatedAbstract: + // C++1y [expr.const]p2: + // A conditional-expression e is a core constant expression unless the + // evaluation of e, following the rules of the abstract machine, would + // evaluate [...] a lambda-expression. + case ConstantEvaluated: // We don't actually diagnose this case immediately, because we // could be within a context where we might find out later that // the expression is potentially evaluated (e.g., for typeid). ExprEvalContexts.back().Lambdas.push_back(Lambda); break; - case ConstantEvaluated: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp index d4afeb8a03..f0b53c7d3b 100644 --- a/test/CXX/expr/expr.const/p2-0x.cpp +++ b/test/CXX/expr/expr.const/p2-0x.cpp @@ -275,9 +275,7 @@ namespace UndefinedBehavior { // - a lambda-expression (5.1.2); struct Lambda { - // FIXME: clang crashes when trying to parse this! Revisit this check once - // lambdas are fully implemented. - //int n : []{ return 1; }(); + int n : []{ return 1; }(); // expected-error {{constant expression}} expected-error {{integral constant expression}} }; // - an lvalue-to-rvalue conversion (4.1) unless it is applied to diff --git a/test/SemaCXX/new-delete-0x.cpp b/test/SemaCXX/new-delete-0x.cpp index 9e3b4928b1..a11392d589 100644 --- a/test/SemaCXX/new-delete-0x.cpp +++ b/test/SemaCXX/new-delete-0x.cpp @@ -21,7 +21,9 @@ void bad_news(int *ip) auto s = new int*[[]{return 1;}()][2]; // expected-error {{expected ']'}} // ... but not here: auto t = new (int(*)[[]]); // expected-error {{an attribute list cannot appear here}} - auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} expected-error {{variably modified type}} + auto u = new (int(*)[[]{return 1;}()][2]); // expected-error {{C++11 only allows consecutive left square brackets when introducing an attribute}} \ + expected-error {{variably modified type}} \ + expected-error {{a lambda expression may not appear inside of a constant expression}} } void good_deletes()