[clang] 980517b - [Concepts] Check function constraints before deducing auto return type

Saar Raz via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 30 17:51:38 PST 2020


Author: Saar Raz
Date: 2020-01-31T03:51:26+02:00
New Revision: 980517b3530ffb7faa1a23fdc007d78f5b45ae3c

URL: https://github.com/llvm/llvm-project/commit/980517b3530ffb7faa1a23fdc007d78f5b45ae3c
DIFF: https://github.com/llvm/llvm-project/commit/980517b3530ffb7faa1a23fdc007d78f5b45ae3c.diff

LOG: [Concepts] Check function constraints before deducing auto return type

A constrained function with an auto return type would have it's definition
instantiated in order to deduce the auto return type before the constraints
are checked.

Move the constraints check after the return type deduction.

Added: 
    

Modified: 
    clang/lib/Sema/SemaExpr.cpp
    clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 248757682057..2380a6b8d67f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -245,8 +245,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
     return true;
   }
 
-  // See if this is a deleted function.
   if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    // See if this is a deleted function.
     if (FD->isDeleted()) {
       auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
       if (Ctor && Ctor->isInheritingConstructor())
@@ -259,6 +259,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
       return true;
     }
 
+    // [expr.prim.id]p4
+    //   A program that refers explicitly or implicitly to a function with a
+    //   trailing requires-clause whose constraint-expression is not satisfied,
+    //   other than to declare it, is ill-formed. [...]
+    //
+    // See if this is a function with constraints that need to be satisfied.
+    // Check this before deducing the return type, as it might instantiate the
+    // definition.
+    if (FD->getTrailingRequiresClause()) {
+      ConstraintSatisfaction Satisfaction;
+      if (CheckFunctionConstraints(FD, Satisfaction, Loc))
+        // A diagnostic will have already been generated (non-constant
+        // constraint expression, for example)
+        return true;
+      if (!Satisfaction.IsSatisfied) {
+        Diag(Loc,
+             diag::err_reference_to_function_with_unsatisfied_constraints)
+            << D;
+        DiagnoseUnsatisfiedConstraint(Satisfaction);
+        return true;
+      }
+    }
+
     // If the function has a deduced return type, and we can't deduce it,
     // then we can't use it either.
     if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
@@ -326,29 +349,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
 
   diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
 
-  // [expr.prim.id]p4
-  //   A program that refers explicitly or implicitly to a function with a
-  //   trailing requires-clause whose constraint-expression is not satisfied,
-  //   other than to declare it, is ill-formed. [...]
-  //
-  // See if this is a function with constraints that need to be satisfied.
-  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
-    if (FD->getTrailingRequiresClause()) {
-      ConstraintSatisfaction Satisfaction;
-      if (CheckFunctionConstraints(FD, Satisfaction, Loc))
-        // A diagnostic will have already been generated (non-constant
-        // constraint expression, for example)
-        return true;
-      if (!Satisfaction.IsSatisfied) {
-        Diag(Loc,
-             diag::err_reference_to_function_with_unsatisfied_constraints)
-            << D;
-        DiagnoseUnsatisfiedConstraint(Satisfaction);
-        return true;
-      }
-    }
-  }
-
   if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
       !isUnevaluatedContext()) {
     // C++ [expr.prim.req.nested] p3

diff  --git a/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp
index f4c38c73d255..d3dde10ff2b2 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.id/p4.cpp
@@ -26,11 +26,14 @@ namespace methods
   struct A {
     static void foo(int) requires (sizeof(T) == 1) {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}}
     static void bar(int) requires (sizeof(T) == 2) {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
+    // Make sure the function body is not instantiated before constraints are checked.
+    static auto baz(int) requires (sizeof(T) == 2) { return T::foo(); } // expected-note{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
   };
 
   void baz() {
     A<char>::foo(1);
     A<char>::bar(1); // expected-error{{invalid reference to function 'bar': constraints not satisfied}}
+    A<char>::baz(1); // expected-error{{invalid reference to function 'baz': constraints not satisfied}}
     A<char[2]>::foo(1); // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
     A<char[2]>::bar(1);
     void (*p1)(int) = A<char>::foo;


        


More information about the cfe-commits mailing list