usaxena95 updated this revision to Diff 474716.
usaxena95 added a comment.

Moving closer to show diagnostic of entity for which SFNIAE occurred.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137712/new/

https://reviews.llvm.org/D137712

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/Sema/Sema.h
  clang/lib/AST/ASTConcept.cpp
  clang/lib/AST/ComputeDependence.cpp
  clang/lib/AST/ExprConcepts.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/Sema/SemaConcept.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/test/SemaTemplate/concepts.cpp

Index: clang/test/SemaTemplate/concepts.cpp
===================================================================
--- clang/test/SemaTemplate/concepts.cpp
+++ clang/test/SemaTemplate/concepts.cpp
@@ -764,3 +764,53 @@
   __iterator_traits_member_pointer_or_arrow_or_void<counted_iterator<int>> f;
 }
 }// namespace InheritedFromPartialSpec
+
+namespace nested_requirements {
+template<class T>  concept True = true;
+
+struct S { double value; };
+
+template <class T>
+concept Pipes = requires (T x) {
+   requires True<decltype(x.value)> || True<T>;
+   requires True<T> || True<decltype(x.value)>;
+};
+template <class T>
+concept Amps1 = requires (T x) {
+   requires True<decltype(x.value)> && True<T>;
+   // expected-note@-1{{because 'todo fill me' would be invalid: member reference base type 'int' is not a structure or union}}
+};
+template <class T>
+concept Amps2 = requires (T x) {
+   requires True<T> && True<decltype(x.value)>;
+};
+
+static_assert(Pipes<S>);
+static_assert(Pipes<double>);
+
+static_assert(Amps1<S>);
+static_assert(!Amps1<double>);
+
+static_assert(Amps2<S>);
+static_assert(!Amps2<double>);
+
+template<class T>
+void foo1() requires requires (T x) { // expected-note {{candidate template ignored: constraints not satisfied [with T = int]}}
+  requires 
+  True<decltype(x.value)> // expected-note {{because 'todo fill me' would be invalid: member reference base type 'int' is not a structure or union}}
+  && True<T>;
+} {}
+template<class T> void fooPipes() requires Pipes<T> {}
+template<class T> void fooAmps1() requires Amps1<T> {}
+// expected-note@-1 {{candidate template ignored: constraints not satisfied [with T = int]}} \
+// expected-note@-1 {{because 'int' does not satisfy 'Amps1'}}
+
+void foo() {
+  foo1<S>();
+  foo1<int>(); // expected-error {{no matching function for call to 'foo1'}}
+  fooPipes<S>();
+  fooPipes<int>();
+  fooAmps1<S>();
+  fooAmps1<int>(); // expected-error {{no matching function for call to 'fooAmps1'}}
+}
+}
\ No newline at end of file
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -11,6 +11,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/ExprOpenMP.h"
 #include "clang/Serialization/ASTRecordWriter.h"
 #include "clang/Sema/DeclSpec.h"
@@ -412,19 +413,18 @@
       if (E)
         Record.AddStmt(E);
       else {
-        auto *Diag = DetailRecord.second.get<std::pair<SourceLocation,
-                                                       StringRef> *>();
-        Record.AddSourceLocation(Diag->first);
-        Record.AddString(Diag->second);
+        auto *Diag =
+            DetailRecord.second.get<concepts::SubstitutionDiagnostic *>();
+        Record.AddSourceLocation(Diag->DiagLoc);
+        Record.AddString(Diag->DiagMessage);
       }
     }
   }
 }
 
 static void
-addSubstitutionDiagnostic(
-    ASTRecordWriter &Record,
-    const concepts::Requirement::SubstitutionDiagnostic *D) {
+addSubstitutionDiagnostic(ASTRecordWriter &Record,
+                          const concepts::SubstitutionDiagnostic *D) {
   Record.AddString(D->SubstitutedEntity);
   Record.AddSourceLocation(D->DiagLoc);
   Record.AddString(D->DiagMessage);
@@ -467,8 +467,8 @@
       Record.push_back(ExprReq->getKind());
       Record.push_back(ExprReq->Status);
       if (ExprReq->isExprSubstitutionFailure()) {
-        addSubstitutionDiagnostic(Record,
-         ExprReq->Value.get<concepts::Requirement::SubstitutionDiagnostic *>());
+        addSubstitutionDiagnostic(
+            Record, ExprReq->Value.get<concepts::SubstitutionDiagnostic *>());
       } else
         Record.AddStmt(ExprReq->Value.get<Expr *>());
       if (ExprReq->getKind() == concepts::Requirement::RK_Compound) {
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -781,9 +781,9 @@
         SourceLocation DiagLocation = Record.readSourceLocation();
         std::string DiagMessage = Record.readString();
         Satisfaction.Details.emplace_back(
-            ConstraintExpr, new (Record.getContext())
-                                ConstraintSatisfaction::SubstitutionDiagnostic{
-                                    DiagLocation, DiagMessage});
+            ConstraintExpr,
+            new (Record.getContext()) concepts::SubstitutionDiagnostic{
+                "todo: fill substituted entity", DiagLocation, DiagMessage});
       } else
         Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr());
     }
@@ -806,14 +806,13 @@
                                         readConstraintSatisfaction(Record));
 }
 
-static concepts::Requirement::SubstitutionDiagnostic *
+static concepts::SubstitutionDiagnostic *
 readSubstitutionDiagnostic(ASTRecordReader &Record) {
   std::string SubstitutedEntity = Record.readString();
   SourceLocation DiagLoc = Record.readSourceLocation();
   std::string DiagMessage = Record.readString();
   return new (Record.getContext())
-      concepts::Requirement::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc,
-                                                    DiagMessage};
+      concepts::SubstitutionDiagnostic{SubstitutedEntity, DiagLoc, DiagMessage};
 }
 
 void ASTStmtReader::VisitRequiresExpr(RequiresExpr *E) {
@@ -850,8 +849,7 @@
         auto Status =
             static_cast<concepts::ExprRequirement::SatisfactionStatus>(
                 Record.readInt());
-        llvm::PointerUnion<concepts::Requirement::SubstitutionDiagnostic *,
-                           Expr *> E;
+        llvm::PointerUnion<concepts::SubstitutionDiagnostic *, Expr *> E;
         if (Status == concepts::ExprRequirement::SS_ExprSubstitutionFailure) {
           E = readSubstitutionDiagnostic(Record);
         } else
@@ -890,9 +888,9 @@
                   std::move(*Req), Status, SubstitutedConstraintExpr);
         else
           R = new (Record.getContext()) concepts::ExprRequirement(
-                  E.get<concepts::Requirement::SubstitutionDiagnostic *>(),
-                  RK == concepts::Requirement::RK_Simple, NoexceptLoc,
-                  std::move(*Req));
+              E.get<concepts::SubstitutionDiagnostic *>(),
+              RK == concepts::Requirement::RK_Simple, NoexceptLoc,
+              std::move(*Req));
       } break;
       case concepts::Requirement::RK_Nested: {
         if (/* IsSubstitutionDiagnostic */Record.readInt()) {
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -37,6 +37,7 @@
 #include "clang/Sema/ScopeInfo.h"
 #include "clang/Sema/SemaDiagnostic.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/TemplateDeduction.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <algorithm>
@@ -3477,6 +3478,23 @@
     return Result;
   }
 
+  ExprResult RebuildConceptSpecializationSubstitutionFailure(
+      ConceptSpecializationExpr *E,
+      concepts::SubstitutionDiagnostic *SubstDiags) {
+    ConstraintSatisfaction Satisfaction;
+    Satisfaction.IsSatisfied = false;
+    Satisfaction.ContainsErrors = false;
+    Satisfaction.Details.emplace_back(E, SubstDiags);
+    CXXScopeSpec SS;
+    SS.Adopt(E->getNestedNameSpecifierLoc());
+    return ConceptSpecializationExpr::CreateSubstitutionFailure(
+        SemaRef.Context,
+        SS.isSet() ? SS.getWithLocInContext(SemaRef.Context)
+                   : NestedNameSpecifierLoc{},
+        E->getTemplateKWLoc(), E->getConceptNameInfo(), E->getFoundDecl(),
+        E->getNamedConcept(), &Satisfaction);
+  }
+
   /// \brief Build a new requires expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -3491,8 +3509,7 @@
   }
 
   concepts::TypeRequirement *
-  RebuildTypeRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+  RebuildTypeRequirement(concepts::SubstitutionDiagnostic *SubstDiag) {
     return SemaRef.BuildTypeRequirement(SubstDiag);
   }
 
@@ -3501,10 +3518,9 @@
   }
 
   concepts::ExprRequirement *
-  RebuildExprRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple,
-      SourceLocation NoexceptLoc,
-      concepts::ExprRequirement::ReturnTypeRequirement Ret) {
+  RebuildExprRequirement(concepts::SubstitutionDiagnostic *SubstDiag,
+                         bool IsSimple, SourceLocation NoexceptLoc,
+                         concepts::ExprRequirement::ReturnTypeRequirement Ret) {
     return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc,
                                         std::move(Ret));
   }
@@ -3517,8 +3533,7 @@
   }
 
   concepts::NestedRequirement *
-  RebuildNestedRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+  RebuildNestedRequirement(concepts::SubstitutionDiagnostic *SubstDiag) {
     return SemaRef.BuildNestedRequirement(SubstDiag);
   }
 
@@ -12611,15 +12626,41 @@
                                        E->getEndLoc());
 }
 
-template<typename Derived>
-ExprResult
-TreeTransform<Derived>::TransformConceptSpecializationExpr(
-                                                 ConceptSpecializationExpr *E) {
+namespace {
+// TODO: refactor to use CreateSubstDiag from SemaTemplateInstantiate.cpp.
+inline concepts::SubstitutionDiagnostic *
+CreateSubstDiag(Sema &S, sema::TemplateDeductionInfo &Info) {
+  SmallString<128> Message;
+  SourceLocation ErrorLoc;
+
+  PartialDiagnosticAt PDA(SourceLocation(),
+                          PartialDiagnostic::NullDiagnostic{});
+  Info.takeSFINAEDiagnostic(PDA);
+  PDA.second.EmitToString(S.getDiagnostics(), Message);
+  ErrorLoc = PDA.first;
+  char *MessageBuf = new (S.Context) char[Message.size()];
+  std::copy(Message.begin(), Message.end(), MessageBuf);
+  return new (S.Context) concepts::SubstitutionDiagnostic{
+      "todo fill me", ErrorLoc, StringRef(MessageBuf, Message.size())};
+}
+} // namespace
+
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformConceptSpecializationExpr(
+    ConceptSpecializationExpr *E) {
   const ASTTemplateArgumentListInfo *Old = E->getTemplateArgsAsWritten();
   TemplateArgumentListInfo TransArgs(Old->LAngleLoc, Old->RAngleLoc);
-  if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(),
-                                              Old->NumTemplateArgs, TransArgs))
-    return ExprError();
+  {
+    Sema::SFINAETrap Trap(getSema());
+    if (getDerived().TransformTemplateArguments(
+            Old->getTemplateArgs(), Old->NumTemplateArgs, TransArgs)) {
+      if (!E->isInstantiationDependent() || !Trap.hasErrorOccurred())
+        return ExprError();
+      // FIXME: Propagate detailed subtitution falilure diagnostics.
+      return getDerived().RebuildConceptSpecializationSubstitutionFailure(
+          E, CreateSubstDiag(SemaRef, **SemaRef.isSFINAEContext()));
+    }
+  }
 
   return getDerived().RebuildConceptSpecializationExpr(
       E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(),
@@ -12720,7 +12761,7 @@
 template<typename Derived>
 concepts::ExprRequirement *
 TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) {
-  llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr;
+  llvm::PointerUnion<Expr *, concepts::SubstitutionDiagnostic *> TransExpr;
   if (Req->isExprSubstitutionFailure())
     TransExpr = Req->getExprSubstitutionDiagnostic();
   else {
@@ -12753,8 +12794,8 @@
                                                Req->getNoexceptLoc(),
                                                std::move(*TransRetReq));
   return getDerived().RebuildExprRequirement(
-      TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
-      Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+      TransExpr.get<concepts::SubstitutionDiagnostic *>(), Req->isSimple(),
+      Req->getNoexceptLoc(), std::move(*TransRetReq));
 }
 
 template<typename Derived>
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2151,8 +2151,8 @@
       getPackIndex(Pack), Arg, TL.getNameLoc());
 }
 
-template<typename EntityPrinter>
-static concepts::Requirement::SubstitutionDiagnostic *
+template <typename EntityPrinter>
+static concepts::SubstitutionDiagnostic *
 createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) {
   SmallString<128> Message;
   SourceLocation ErrorLoc;
@@ -2172,7 +2172,7 @@
   Printer(OS);
   char *EntityBuf = new (S.Context) char[Entity.size()];
   std::copy(Entity.begin(), Entity.end(), EntityBuf);
-  return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{
+  return new (S.Context) concepts::SubstitutionDiagnostic{
       StringRef(EntityBuf, Entity.size()), ErrorLoc,
       StringRef(MessageBuf, Message.size())};
 }
@@ -2228,9 +2228,9 @@
     return nullptr;
   TypeSourceInfo *TransType = TransformType(Req->getType());
   if (!TransType || Trap.hasErrorOccurred())
-    return RebuildTypeRequirement(createSubstDiag(SemaRef, Info,
-        [&] (llvm::raw_ostream& OS) {
-            Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy());
+    return RebuildTypeRequirement(
+        createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
+          Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy());
         }));
   return RebuildTypeRequirement(TransType);
 }
@@ -2242,8 +2242,7 @@
 
   Sema::SFINAETrap Trap(SemaRef);
 
-  llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *>
-      TransExpr;
+  llvm::PointerUnion<Expr *, concepts::SubstitutionDiagnostic *> TransExpr;
   if (Req->isExprSubstitutionFailure())
     TransExpr = Req->getExprSubstitutionDiagnostic();
   else {
@@ -2258,9 +2257,10 @@
         TransExprRes.get()->hasPlaceholderType())
       TransExprRes = SemaRef.CheckPlaceholderExpr(TransExprRes.get());
     if (TransExprRes.isInvalid() || Trap.hasErrorOccurred())
-      TransExpr = createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
-        E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
-      });
+      TransExpr =
+          createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
+            E->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+          });
     else
       TransExpr = TransExprRes.get();
   }
@@ -2281,10 +2281,11 @@
       return nullptr;
     TemplateParameterList *TPL = TransformTemplateParameterList(OrigTPL);
     if (!TPL)
-      TransRetReq.emplace(createSubstDiag(SemaRef, Info,
-          [&] (llvm::raw_ostream& OS) {
-              RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint()
-                  ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
+      TransRetReq.emplace(
+          createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
+            RetReq.getTypeConstraint()
+                ->getImmediatelyDeclaredConstraint()
+                ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy());
           }));
     else {
       TPLInst.Clear();
@@ -2296,8 +2297,8 @@
     return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(),
                                   std::move(*TransRetReq));
   return RebuildExprRequirement(
-      TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(),
-      Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq));
+      TransExpr.get<concepts::SubstitutionDiagnostic *>(), Req->isSimple(),
+      Req->getNoexceptLoc(), std::move(*TransRetReq));
 }
 
 concepts::NestedRequirement *
@@ -2349,10 +2350,10 @@
                                  "but did not produce a SFINAE error");
     }
     if (TransConstraint.isInvalid() || Trap.hasErrorOccurred())
-      return RebuildNestedRequirement(createSubstDiag(SemaRef, Info,
-          [&] (llvm::raw_ostream& OS) {
-              Req->getConstraintExpr()->printPretty(OS, nullptr,
-                                                    SemaRef.getPrintingPolicy());
+      return RebuildNestedRequirement(
+          createSubstDiag(SemaRef, Info, [&](llvm::raw_ostream &OS) {
+            Req->getConstraintExpr()->printPretty(OS, nullptr,
+                                                  SemaRef.getPrintingPolicy());
           }));
   }
   if (TransConstraint.get()->isInstantiationDependent())
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -8989,10 +8989,9 @@
                                                  SubstitutedConstraintExpr);
 }
 
-concepts::ExprRequirement *
-Sema::BuildExprRequirement(
-    concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic,
-    bool IsSimple, SourceLocation NoexceptLoc,
+concepts::ExprRequirement *Sema::BuildExprRequirement(
+    concepts::SubstitutionDiagnostic *ExprSubstitutionDiagnostic, bool IsSimple,
+    SourceLocation NoexceptLoc,
     concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) {
   return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic,
                                                  IsSimple, NoexceptLoc,
@@ -9005,8 +9004,7 @@
 }
 
 concepts::TypeRequirement *
-Sema::BuildTypeRequirement(
-    concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+Sema::BuildTypeRequirement(concepts::SubstitutionDiagnostic *SubstDiag) {
   return new (Context) concepts::TypeRequirement(SubstDiag);
 }
 
@@ -9026,8 +9024,7 @@
 }
 
 concepts::NestedRequirement *
-Sema::BuildNestedRequirement(
-    concepts::Requirement::SubstitutionDiagnostic *SubstDiag) {
+Sema::BuildNestedRequirement(concepts::SubstitutionDiagnostic *SubstDiag) {
   return new (Context) concepts::NestedRequirement(SubstDiag);
 }
 
Index: clang/lib/Sema/SemaConcept.cpp
===================================================================
--- clang/lib/Sema/SemaConcept.cpp
+++ clang/lib/Sema/SemaConcept.cpp
@@ -223,10 +223,9 @@
     char *Mem = new (S.Context) char[MessageSize];
     memcpy(Mem, DiagString.c_str(), MessageSize);
     Satisfaction.Details.emplace_back(
-        ConstraintExpr,
-        new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-            SubstitutedAtomicExpr.get()->getBeginLoc(),
-            StringRef(Mem, MessageSize)});
+        ConstraintExpr, new (S.Context) concepts::SubstitutionDiagnostic{
+                            "", SubstitutedAtomicExpr.get()->getBeginLoc(),
+                            StringRef(Mem, MessageSize)});
     return SubstitutedAtomicExpr;
   }
 
@@ -314,9 +313,9 @@
             char *Mem = new (S.Context) char[MessageSize];
             memcpy(Mem, DiagString.c_str(), MessageSize);
             Satisfaction.Details.emplace_back(
-                AtomicExpr,
-                new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{
-                        SubstDiag.first, StringRef(Mem, MessageSize)});
+                AtomicExpr, new (S.Context) concepts::SubstitutionDiagnostic{
+                                "todo: fill substituted entity",
+                                SubstDiag.first, StringRef(Mem, MessageSize)});
             Satisfaction.IsSatisfied = false;
             return ExprEmpty();
           }
@@ -858,7 +857,7 @@
                                            concepts::NestedRequirement *Req,
                                            bool First) {
   if (Req->isSubstitutionFailure()) {
-    concepts::Requirement::SubstitutionDiagnostic *SubstDiag =
+    concepts::SubstitutionDiagnostic *SubstDiag =
         Req->getSubstitutionDiagnostic();
     if (!SubstDiag->DiagMessage.empty())
       S.Diag(SubstDiag->DiagLoc,
@@ -941,6 +940,19 @@
       break;
     }
   } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) {
+    if (CSE->hasSubstitutionFailureInArgs()) {
+      for (const auto &Diags : CSE->getSatisfaction()) {
+        auto *SubstDiag =
+            Diags.second.get<concepts::SubstitutionDiagnostic *>();
+        S.Diag(SubstDiag->DiagLoc,
+               // todo: create another diag for concept specialisation. this one
+               // is not needed anymore.
+               diag::note_nested_requirement_substitution_error)
+            << (int)First << SubstDiag->SubstitutedEntity
+            << SubstDiag->DiagMessage;
+      }
+      return;
+    }
     if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) {
       S.Diag(
           CSE->getSourceRange().getBegin(),
@@ -982,8 +994,8 @@
     const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record,
     bool First = true) {
   if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){
-    S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed)
-        << Diag->second;
+    S.Diag(Diag->DiagLoc, diag::note_substituted_constraint_expr_is_ill_formed)
+        << Diag->DiagMessage;
     return;
   }
 
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -2467,9 +2467,12 @@
   if (E->getTemplateKWLoc().isValid())
     OS << "template ";
   OS << E->getFoundDecl()->getName();
-  printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(),
-                            Policy,
-                            E->getNamedConcept()->getTemplateParameters());
+  if (E->hasSubstitutionFailureInArgs())
+    OS << "<<error-expression>>";
+  else
+    printTemplateArgumentList(OS, E->getTemplateArgsAsWritten()->arguments(),
+                              Policy,
+                              E->getNamedConcept()->getTemplateParameters());
 }
 
 void StmtPrinter::VisitRequiresExpr(RequiresExpr *E) {
Index: clang/lib/AST/ExprConcepts.cpp
===================================================================
--- clang/lib/AST/ExprConcepts.cpp
+++ clang/lib/AST/ExprConcepts.cpp
@@ -23,6 +23,8 @@
 #include "clang/AST/TemplateBase.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/TemplateDeduction.h"
 #include "llvm/Support/TrailingObjects.h"
 #include <algorithm>
 #include <string>
@@ -36,14 +38,15 @@
     NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
     const ASTTemplateArgumentListInfo *ArgsAsWritten,
     ImplicitConceptSpecializationDecl *SpecDecl,
-    const ConstraintSatisfaction *Satisfaction)
+    const ConstraintSatisfaction *Satisfaction, bool ArgsHasSubstitutionFailure)
     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
       ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
                        NamedConcept, ArgsAsWritten),
       SpecDecl(SpecDecl),
       Satisfaction(Satisfaction
                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
-                       : nullptr) {
+                       : nullptr),
+      ArgsHasSubstitutionFailure(ArgsHasSubstitutionFailure) {
   setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
 
   // Currently guaranteed by the fact concepts can only be at namespace-scope.
@@ -53,6 +56,13 @@
               ->containsUnexpandedParameterPack()));
   assert((!isValueDependent() || isInstantiationDependent()) &&
          "should not be value-dependent");
+  if (ArgsHasSubstitutionFailure) {
+    assert(Satisfaction);
+    assert(!Satisfaction->IsSatisfied);
+    // assert(Satisfaction->ContainsErrors);
+    assert(!ArgsAsWritten);
+    assert(!SpecDecl);
+  }
 }
 
 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
@@ -103,6 +113,17 @@
                                 Dependent, ContainsUnexpandedParameterPack);
 }
 
+ConceptSpecializationExpr *ConceptSpecializationExpr::CreateSubstitutionFailure(
+    const ASTContext &C, NestedNameSpecifierLoc NNS,
+    SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
+    NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+    const ConstraintSatisfaction *Satisfaction) {
+  return new (C) ConceptSpecializationExpr(
+      C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
+      /*ArgsAsWritten=*/nullptr, /*SpecDecl=*/nullptr, Satisfaction,
+      /*ArgsHasSubstitutionFailure=*/true);
+}
+
 const TypeConstraint *
 concepts::ExprRequirement::ReturnTypeRequirement::getTypeConstraint() const {
   assert(isTypeConstraint());
Index: clang/lib/AST/ComputeDependence.cpp
===================================================================
--- clang/lib/AST/ComputeDependence.cpp
+++ clang/lib/AST/ComputeDependence.cpp
@@ -844,12 +844,13 @@
   auto TA = TemplateArgumentDependence::None;
   const auto InterestingDeps = TemplateArgumentDependence::Instantiation |
                                TemplateArgumentDependence::UnexpandedPack;
-  for (const TemplateArgumentLoc &ArgLoc :
-       E->getTemplateArgsAsWritten()->arguments()) {
-    TA |= ArgLoc.getArgument().getDependence() & InterestingDeps;
-    if (TA == InterestingDeps)
-      break;
-  }
+  if (E->getTemplateArgsAsWritten())
+    for (const TemplateArgumentLoc &ArgLoc :
+         E->getTemplateArgsAsWritten()->arguments()) {
+      TA |= ArgLoc.getArgument().getDependence() & InterestingDeps;
+      if (TA == InterestingDeps)
+        break;
+    }
 
   ExprDependence D =
       ValueDependent ? ExprDependence::Value : ExprDependence::None;
Index: clang/lib/AST/ASTConcept.cpp
===================================================================
--- clang/lib/AST/ASTConcept.cpp
+++ clang/lib/AST/ASTConcept.cpp
@@ -14,6 +14,7 @@
 #include "clang/AST/ASTConcept.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
+#include "clang/AST/ExprConcepts.h"
 #include "clang/AST/TemplateBase.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/FoldingSet.h"
@@ -33,12 +34,13 @@
                                          Detail.second.get<Expr *>())};
     else {
       auto &SubstitutionDiagnostic =
-          *Detail.second.get<std::pair<SourceLocation, StringRef> *>();
-      unsigned MessageSize = SubstitutionDiagnostic.second.size();
+          *Detail.second.get<concepts::SubstitutionDiagnostic *>();
+      unsigned MessageSize = SubstitutionDiagnostic.DiagMessage.size();
       char *Mem = new (C) char[MessageSize];
-      memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize);
-      auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>(
-          SubstitutionDiagnostic.first, StringRef(Mem, MessageSize));
+      memcpy(Mem, SubstitutionDiagnostic.DiagMessage.data(), MessageSize);
+      auto *NewSubstDiag = new (C) concepts::SubstitutionDiagnostic{
+          /*todo: copy me*/ SubstitutionDiagnostic.SubstitutedEntity,
+          SubstitutionDiagnostic.DiagLoc, StringRef(Mem, MessageSize)};
       new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I)
          UnsatisfiedConstraintRecord{Detail.first,
                                      UnsatisfiedConstraintRecord::second_type(
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -8448,19 +8448,16 @@
   BuildExprRequirement(
       Expr *E, bool IsSatisfied, SourceLocation NoexceptLoc,
       concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement);
-  concepts::ExprRequirement *
-  BuildExprRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *ExprSubstDiag,
-      bool IsSatisfied, SourceLocation NoexceptLoc,
+  concepts::ExprRequirement *BuildExprRequirement(
+      concepts::SubstitutionDiagnostic *ExprSubstDiag, bool IsSatisfied,
+      SourceLocation NoexceptLoc,
       concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement);
   concepts::TypeRequirement *BuildTypeRequirement(TypeSourceInfo *Type);
   concepts::TypeRequirement *
-  BuildTypeRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *SubstDiag);
+  BuildTypeRequirement(concepts::SubstitutionDiagnostic *SubstDiag);
   concepts::NestedRequirement *BuildNestedRequirement(Expr *E);
   concepts::NestedRequirement *
-  BuildNestedRequirement(
-      concepts::Requirement::SubstitutionDiagnostic *SubstDiag);
+  BuildNestedRequirement(concepts::SubstitutionDiagnostic *SubstDiag);
   ExprResult ActOnRequiresExpr(SourceLocation RequiresKWLoc,
                                RequiresExprBodyDecl *Body,
                                ArrayRef<ParmVarDecl *> LocalParameters,
Index: clang/include/clang/AST/ExprConcepts.h
===================================================================
--- clang/include/clang/AST/ExprConcepts.h
+++ clang/include/clang/AST/ExprConcepts.h
@@ -29,6 +29,10 @@
 #include <string>
 
 namespace clang {
+namespace sema {
+class TemplateDeductionInfo;
+}
+
 class ASTStmtReader;
 class ASTStmtWriter;
 
@@ -42,7 +46,6 @@
   friend class ASTStmtReader;
 
 public:
-  using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
 
 protected:
   /// \brief The Implicit Concept Specialization Decl, which holds the template
@@ -53,6 +56,7 @@
   /// given arguments. If this expression is value dependent, this is to be
   /// ignored.
   ASTConstraintSatisfaction *Satisfaction;
+  bool ArgsHasSubstitutionFailure = false;
 
   ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
                             SourceLocation TemplateKWLoc,
@@ -60,7 +64,8 @@
                             NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
                             const ASTTemplateArgumentListInfo *ArgsAsWritten,
                             ImplicitConceptSpecializationDecl *SpecDecl,
-                            const ConstraintSatisfaction *Satisfaction);
+                            const ConstraintSatisfaction *Satisfaction,
+                            bool ArgsHasSubstitutionFailure = false);
 
   ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
                             ImplicitConceptSpecializationDecl *SpecDecl,
@@ -84,10 +89,21 @@
          const ConstraintSatisfaction *Satisfaction, bool Dependent,
          bool ContainsUnexpandedParameterPack);
 
+  static ConceptSpecializationExpr *
+  CreateSubstitutionFailure(const ASTContext &C, NestedNameSpecifierLoc NNS,
+                            SourceLocation TemplateKWLoc,
+                            DeclarationNameInfo ConceptNameInfo,
+                            NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+                            const ConstraintSatisfaction *Satisfaction);
+
   ArrayRef<TemplateArgument> getTemplateArguments() const {
     return SpecDecl->getTemplateArguments();
   }
 
+  bool hasSubstitutionFailureInArgs() const {
+    return ArgsHasSubstitutionFailure;
+  }
+
   const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
     assert(SpecDecl && "Template Argument Decl not initialized");
     return SpecDecl;
@@ -139,6 +155,15 @@
 };
 
 namespace concepts {
+  // todo: add doc ?
+struct SubstitutionDiagnostic {
+  StringRef SubstitutedEntity;
+  // FIXME: Store diagnostics semantically and not as prerendered strings.
+  //  Fixing this probably requires serialization of PartialDiagnostic
+  //  objects.
+  SourceLocation DiagLoc;
+  StringRef DiagMessage;
+};
 
 /// \brief A static requirement that can be used in a requires-expression to
 /// check properties of types and expression.
@@ -154,14 +179,6 @@
   bool ContainsUnexpandedParameterPack : 1;
   bool Satisfied : 1;
 public:
-  struct SubstitutionDiagnostic {
-    StringRef SubstitutedEntity;
-    // FIXME: Store diagnostics semantically and not as prerendered strings.
-    //  Fixing this probably requires serialization of PartialDiagnostic
-    //  objects.
-    SourceLocation DiagLoc;
-    StringRef DiagMessage;
-  };
 
   Requirement(RequirementKind Kind, bool IsDependent,
               bool ContainsUnexpandedParameterPack, bool IsSatisfied = true) :
Index: clang/include/clang/AST/ASTConcept.h
===================================================================
--- clang/include/clang/AST/ASTConcept.h
+++ clang/include/clang/AST/ASTConcept.h
@@ -22,6 +22,9 @@
 
 namespace clang {
 class ConceptDecl;
+namespace concepts {
+struct SubstitutionDiagnostic;
+} // namespace concepts
 
 /// The result of a constraint satisfaction check, containing the necessary
 /// information to diagnose an unsatisfied constraint.
@@ -40,8 +43,7 @@
       ConstraintOwner(ConstraintOwner), TemplateArgs(TemplateArgs.begin(),
                                                      TemplateArgs.end()) { }
 
-  using SubstitutionDiagnostic = std::pair<SourceLocation, StringRef>;
-  using Detail = llvm::PointerUnion<Expr *, SubstitutionDiagnostic *>;
+  using Detail = llvm::PointerUnion<Expr *, concepts::SubstitutionDiagnostic *>;
 
   bool IsSatisfied = false;
   bool ContainsErrors = false;
@@ -66,9 +68,7 @@
 /// substituted into them, or a diagnostic if substitution resulted in
 /// an invalid expression.
 using UnsatisfiedConstraintRecord =
-    std::pair<const Expr *,
-              llvm::PointerUnion<Expr *,
-                                 std::pair<SourceLocation, StringRef> *>>;
+    std::pair<const Expr *, ConstraintSatisfaction::Detail>;
 
 /// \brief The result of a constraint satisfaction check, containing the
 /// necessary information to diagnose an unsatisfied constraint.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to