From 73eaf62463b4a29adf4194685af12d1a5d172987 Mon Sep 17 00:00:00 2001 From: Saar Raz Date: Fri, 24 Jan 2020 02:22:17 +0200 Subject: [PATCH] [Concepts] Make constraint expressions unevaluated until satisfaction checking As per P1980R0, constraint expressions are unevaluated operands, and their constituent atomic constraints only become constant evaluated during satisfaction checking. Change the evaluation context during parsing and instantiation of constraints to unevaluated. --- clang/lib/Parse/ParseExpr.cpp | 4 ++-- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 8 +++----- .../expr/expr.prim/expr.prim.req/nested-requirement.cpp | 5 +++-- clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ba7525ecf52..e0c53df992e 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -234,7 +234,7 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { /// \endverbatim ExprResult Parser::ParseConstraintExpression() { EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult LHS(ParseCastExpression(AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { @@ -256,7 +256,7 @@ ExprResult Parser::ParseConstraintExpression() { ExprResult Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( - Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Actions, Sema::ExpressionEvaluationContext::Unevaluated); bool NotPrimaryExpression = false; auto ParsePrimary = [&] () { ExprResult E = ParseCastExpression(PrimaryExprOnly, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 92f6e0dc1c9..fbbab8f0070 100755 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1849,7 +1849,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -2189,7 +2189,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -2529,8 +2529,6 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( TemplateArgumentListInfo InstArgs; if (TemplArgInfo) { - EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), @@ -3736,7 +3734,7 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { Expr *InstRequiresClause = nullptr; if (Expr *E = L->getRequiresClause()) { EnterExpressionEvaluationContext ConstantEvaluated( - SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); if (Res.isInvalid() || !Res.isUsable()) { return nullptr; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp index bc093a0fc50..b45b57f6b92 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp @@ -39,8 +39,9 @@ namespace std_example { using dc1 = D_check; // expected-error{{constraints not satisfied for class template 'D_check' [with T = short]}} template - concept C2 = requires (T a) { // expected-note{{'a' declared here}} + concept C2 = requires (T a) { requires sizeof(a) == 4; // OK - requires a == 0; // expected-error{{constraint variable 'a' cannot be used in an evaluated context}} + requires a == 0; // expected-note{{because 'a == 0' would be invalid: constraint variable 'a' cannot be used in an evaluated context}} }; + static_assert(C2); // expected-note{{because 'int' does not satisfy 'C2'}} expected-error{{static_assert failed}} } \ No newline at end of file diff --git a/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp new file mode 100644 index 00000000000..a2a7232b4b8 --- /dev/null +++ b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +// Make sure constraint expressions are unevaluated before being substituted +// into during satisfaction checking. + +template constexpr int f() { return T::value; } +template concept Foo = false && (f(), true); +bool k = Foo; +template requires false && (f(), true) struct S {}; +// expected-note@-1{{because}} +using s = S; // expected-error {{constraints not satisfied}} +template void foo() requires false && (f(), true) { }; +// expected-note@-1{{because}} expected-note@-1{{candidate template ignored}} +int a = (foo(), 0); // expected-error{{no matching function}} +template void bar() requires requires { requires false && (f(), true); } { }; +// expected-note@-1{{because}} expected-note@-1{{candidate template ignored}} +int b = (bar(), 0); // expected-error{{no matching function}} \ No newline at end of file -- 2.11.0