Properly Propagate RecoveryExpr through RequiresExpr
authorErich Keane <erich.keane@intel.com>
Wed, 29 Mar 2023 15:54:40 +0000 (08:54 -0700)
committerErich Keane <erich.keane@intel.com>
Wed, 29 Mar 2023 16:04:59 +0000 (09:04 -0700)
Commit 3d7946c58 implemented a DR that allowed us to error in a case
where an ill-formedness in a RequiresExpr is diagnosed as a satisfaction
failure.  However, it failed to cover cases where the RequiresExpr had
Requirements that failed for similar reasons.

This patch propagates the RecoveryExpr "containsErrors" correctly
through RequiresExpr.

Fixes: #61776

clang/lib/AST/ExprConcepts.cpp
clang/test/CXX/drs/dr25xx.cpp

index fc8f1eb..a8a35d7 100644 (file)
@@ -112,6 +112,19 @@ concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
       ->getTypeConstraint();
 }
 
+// Search through the requirements, and see if any have a RecoveryExpr in it,
+// which means this RequiresExpr ALSO needs to be invalid.
+static bool RequirementContainsError(concepts::Requirement *R) {
+  if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(R))
+    return ExprReq->getExpr() && ExprReq->getExpr()->containsErrors();
+
+  if (auto *NestedReq = dyn_cast<concepts::NestedRequirement>(R))
+    return !NestedReq->hasInvalidConstraint() &&
+           NestedReq->getConstraintExpr() &&
+           NestedReq->getConstraintExpr()->containsErrors();
+  return false;
+}
+
 RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
                            RequiresExprBodyDecl *Body,
                            ArrayRef<ParmVarDecl *> LocalParameters,
@@ -138,6 +151,9 @@ RequiresExpr::RequiresExpr(ASTContext &C, SourceLocation RequiresKWLoc,
       if (!RequiresExprBits.IsSatisfied)
         break;
     }
+
+    if (RequirementContainsError(R))
+      setDependence(getDependence() | ExprDependence::Error);
   }
   std::copy(LocalParameters.begin(), LocalParameters.end(),
             getTrailingObjects<ParmVarDecl *>());
index 0800add..28ebda2 100644 (file)
@@ -75,4 +75,25 @@ namespace dr2565 { // dr2565: 16 open
   // expected-error@-1{{constraints not satisfied for class template 'VariadicStruct'}}
   // expected-note@#VSREQ{{because 'Variadic<void, int, char, double>' evaluated to false}}
   // expected-note@#VC{{because 'b' would be invalid: argument may not have 'void' type}}
+
+  template<typename T>
+  // expected-error@+1 {{unknown type name 'ErrorRequires'}}
+  concept ErrorRequires = requires (ErrorRequires auto x) {
+    x;
+  };
+  static_assert(ErrorRequires<int>);
+  // expected-error@-1{{static assertion failed}}
+  // expected-note@-2{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+
+  template<typename T>
+  // expected-error@+2 {{unknown type name 'NestedErrorInRequires'}}
+  concept NestedErrorInRequires = requires (T x) {
+    requires requires (NestedErrorInRequires auto y) {
+      y;
+    };
+  };
+  static_assert(NestedErrorInRequires<int>);
+  // expected-error@-1{{static assertion failed}}
+  // expected-note@-2{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
+
 }