From 9adc361008e25f5b7d9c3aa8968832384d21c12a Mon Sep 17 00:00:00 2001 From: David Majnemer Date: Fri, 25 Oct 2013 09:12:52 +0000 Subject: [PATCH] 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. llvm-svn: 193397 --- .../clang/Basic/DiagnosticSemaKinds.td | 2 ++ clang/lib/Sema/SemaExpr.cpp | 21 +++++++++++++------ clang/lib/Sema/SemaLambda.cpp | 13 ++++++++---- clang/test/CXX/expr/expr.const/p2-0x.cpp | 4 +--- clang/test/SemaCXX/new-delete-0x.cpp | 4 +++- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 21aad683eacb..441ad4ccace6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c842ed035d88..69f8f2e739a0 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index c843da74cd22..2e1cd105a98f 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/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/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp index d4afeb8a0318..f0b53c7d3b5c 100644 --- a/clang/test/CXX/expr/expr.const/p2-0x.cpp +++ b/clang/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/clang/test/SemaCXX/new-delete-0x.cpp b/clang/test/SemaCXX/new-delete-0x.cpp index 9e3b4928b141..a11392d5896c 100644 --- a/clang/test/SemaCXX/new-delete-0x.cpp +++ b/clang/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()