massberg created this revision.
massberg added reviewers: hokein, sammccall, erichkeane.
Herald added subscribers: ChuanqiXu, kadircet, martong.
Herald added a reviewer: shafik.
Herald added a project: All.
massberg requested review of this revision.
Herald added subscribers: cfe-commits, ilya-biryukov.
Herald added a project: clang.

(note this patch is not be ready to be submitted. The current version should 
work as a base
for discussion and later be changed to a submittable version.
Also note that there is a draft version of this patch containing some comments, 
see https://reviews.llvm.org/D155858)

This patch adds a concept AST node (`ConceptLoc`) and uses it at the 
corresponding places.

There are three objects that might have constraints via concepts:
`TypeConstraint`,  `ConceptSpecializationExpr` and `AutoTypeLoc`.
The first two inherit from `ConceptReference` while the latter has
the information about a possible constraint directly stored in 
`AutoTypeLocInfo`. It would be nice if the concept information would be stored 
the same way in all three cases.

Moreover the current structure makes it difficult to deal with these concepts. 
For example in Clangd accessing the locations of constraints of a `AutoTypeLoc` 
can only be done with quite ugly hacks.

So we think that it makes sense to create a new AST node for such concepts.

In details we propose the following:

- Rename `ConceptReference` to `ConceptLoc` (or something else what is 
approriate)

and make it the new AST node.

- `TypeConstraint` and `ConceptSpecializationExpr` do not longer inherit from 
`ConceptReference` but store a pointer to a `ConceptLoc`.
- `AutoTypeLoc` stores a pointer to `ConceptLoc` instead of storing the concept 
info in `AutoTypeLocInfo`.

This patch implements a first version of this idea which compiles and where the 
existing tests pass.
To make this patch as small as possible we keep the existing member functions 
to access concept data. Later these can be replaced by directly calling the 
corresponding functions of the `ConceptLoc`s.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D156867

Files:
  clang/include/clang/AST/ASTConcept.h
  clang/include/clang/AST/DeclTemplate.h
  clang/include/clang/AST/ExprConcepts.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/AST/TypeLoc.h
  clang/include/clang/Serialization/ASTRecordReader.h
  clang/include/clang/Serialization/ASTRecordWriter.h
  clang/lib/AST/ASTContext.cpp
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/DeclTemplate.cpp
  clang/lib/AST/ExprConcepts.cpp
  clang/lib/AST/TypeLoc.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiate.cpp
  clang/lib/Sema/SemaType.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReader.cpp
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriter.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp

Index: clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp
===================================================================
--- clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp
+++ clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp
@@ -29,12 +29,22 @@
     ++ConceptRequirementsTraversed;
     return ExpectedLocationVisitor::TraverseConceptRequirement(R);
   }
+  bool TraverseConceptLoc(const ConceptLoc *CL) {
+    ++ConceptLocsTraversed;
+    return ExpectedLocationVisitor::TraverseConceptLoc(CL);
+  }
+  bool VisitConceptLoc(const ConceptLoc *CL) {
+    ++ConceptLocsVisited;
+    return true;
+  }
 
   bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; }
 
   int ConceptSpecializationExprsVisited = 0;
   int TypeConstraintsTraversed = 0;
   int ConceptRequirementsTraversed = 0;
+  int ConceptLocsTraversed = 0;
+  int ConceptLocsVisited = 0;
   bool ShouldVisitImplicitCode = false;
 };
 
@@ -50,6 +60,8 @@
   EXPECT_EQ(1, Visitor.ConceptSpecializationExprsVisited);
   // Also check we traversed the TypeConstraint that produced the expr.
   EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsVisited);
 
   Visitor = {}; // Don't visit implicit code now.
   EXPECT_TRUE(Visitor.runOver("template <typename T> concept Fooable = true;\n"
@@ -59,6 +71,8 @@
   // generated immediately declared expression.
   EXPECT_EQ(0, Visitor.ConceptSpecializationExprsVisited);
   EXPECT_EQ(1, Visitor.TypeConstraintsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsVisited);
 
   Visitor = {};
   EXPECT_TRUE(Visitor.runOver("template <class T> concept A = true;\n"
@@ -70,6 +84,8 @@
                               "};",
                               ConceptVisitor::Lang_CXX2a));
   EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsTraversed);
+  EXPECT_EQ(1, Visitor.ConceptLocsVisited);
 }
 
 struct VisitDeclOnlyOnce : ExpectedLocationVisitor<VisitDeclOnlyOnce> {
@@ -86,6 +102,10 @@
     ++AutoTypeLocVisited;
     return true;
   }
+  bool VisitConceptLoc(const ConceptLoc *) {
+    ++ConceptLocsVisited;
+    return true;
+  }
 
   bool TraverseVarDecl(VarDecl *V) {
     // The base traversal visits only the `TypeLoc`.
@@ -99,6 +119,7 @@
   int ConceptDeclsVisited = 0;
   int AutoTypeVisited = 0;
   int AutoTypeLocVisited = 0;
+  int ConceptLocsVisited = 0;
 };
 
 TEST(RecursiveASTVisitor, ConceptDeclInAutoType) {
@@ -111,6 +132,7 @@
   EXPECT_EQ(1, Visitor.AutoTypeVisited);
   EXPECT_EQ(1, Visitor.AutoTypeLocVisited);
   EXPECT_EQ(1, Visitor.ConceptDeclsVisited);
+  EXPECT_EQ(1, Visitor.ConceptLocsVisited);
 }
 
 } // end anonymous namespace
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -437,13 +437,8 @@
 void ASTStmtWriter::VisitConceptSpecializationExpr(
         ConceptSpecializationExpr *E) {
   VisitExpr(E);
-  Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc());
-  Record.AddSourceLocation(E->getTemplateKWLoc());
-  Record.AddDeclarationNameInfo(E->getConceptNameInfo());
-  Record.AddDeclRef(E->getNamedConcept());
-  Record.AddDeclRef(E->getFoundDecl());
   Record.AddDeclRef(E->getSpecializationDecl());
-  Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten());
+  Record.AddConceptLoc(E->getConceptLoc());
   if (!E->isValueDependent())
     addConstraintSatisfaction(Record, E->getSatisfaction());
 
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -1774,12 +1774,7 @@
   const TypeConstraint *TC = D->getTypeConstraint();
   Record.push_back(TC != nullptr);
   if (TC) {
-    Record.AddNestedNameSpecifierLoc(TC->getNestedNameSpecifierLoc());
-    Record.AddDeclarationNameInfo(TC->getConceptNameInfo());
-    Record.AddDeclRef(TC->getNamedConcept());
-    Record.push_back(TC->getTemplateArgsAsWritten() != nullptr);
-    if (TC->getTemplateArgsAsWritten())
-      Record.AddASTTemplateArgumentListInfo(TC->getTemplateArgsAsWritten());
+    Record.AddConceptLoc(TC->getConceptLoc());
     Record.AddStmt(TC->getImmediatelyDeclaredConstraint());
     Record.push_back(D->isExpandedParameterPack());
     if (D->isExpandedParameterPack())
Index: clang/lib/Serialization/ASTWriter.cpp
===================================================================
--- clang/lib/Serialization/ASTWriter.cpp
+++ clang/lib/Serialization/ASTWriter.cpp
@@ -469,20 +469,25 @@
   Record.AddTypeSourceInfo(TL.getUnderlyingTInfo());
 }
 
+void ASTRecordWriter::AddConceptLoc(const ConceptLoc *CL) {
+  push_back(CL != nullptr);
+  if (!CL)
+    return;
+  AddNestedNameSpecifierLoc(CL->getNestedNameSpecifierLoc());
+  AddSourceLocation(CL->getTemplateKWLoc());
+  AddDeclarationNameInfo(CL->getConceptNameInfo());
+  AddDeclRef(CL->getFoundDecl());
+  AddDeclRef(CL->getNamedConcept());
+  push_back(CL->getTemplateArgsAsWritten() != nullptr);
+  if (CL->getTemplateArgsAsWritten())
+    AddASTTemplateArgumentListInfo(CL->getTemplateArgsAsWritten());
+}
+
 void TypeLocWriter::VisitAutoTypeLoc(AutoTypeLoc TL) {
   addSourceLocation(TL.getNameLoc());
   Record.push_back(TL.isConstrained());
   if (TL.isConstrained()) {
-    Record.AddNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc());
-    addSourceLocation(TL.getTemplateKWLoc());
-    addSourceLocation(TL.getConceptNameLoc());
-    Record.AddDeclRef(TL.getFoundDecl());
-    addSourceLocation(TL.getLAngleLoc());
-    addSourceLocation(TL.getRAngleLoc());
-    for (unsigned I = 0; I < TL.getNumArgs(); ++I)
-      Record.AddTemplateArgumentLocInfo(
-          TL.getTypePtr()->getTypeConstraintArguments()[I].getKind(),
-          TL.getArgLocInfo(I));
+    Record.AddConceptLoc(TL.getConceptLoc());
   }
   Record.push_back(TL.isDecltypeAuto());
   if (TL.isDecltypeAuto())
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -795,13 +795,8 @@
 void ASTStmtReader::VisitConceptSpecializationExpr(
         ConceptSpecializationExpr *E) {
   VisitExpr(E);
-  E->NestedNameSpec = Record.readNestedNameSpecifierLoc();
-  E->TemplateKWLoc = Record.readSourceLocation();
-  E->ConceptName = Record.readDeclarationNameInfo();
-  E->NamedConcept = readDeclAs<ConceptDecl>();
-  E->FoundDecl = Record.readDeclAs<NamedDecl>();
   E->SpecDecl = Record.readDeclAs<ImplicitConceptSpecializationDecl>();
-  E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+  E->Loc = Record.readConceptLoc();
   E->Satisfaction = E->isValueDependent() ? nullptr :
       ASTConstraintSatisfaction::Create(Record.getContext(),
                                         readConstraintSatisfaction(Record));
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2633,15 +2633,10 @@
   D->setDeclaredWithTypename(Record.readInt());
 
   if (Record.readBool()) {
-    NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc();
-    DeclarationNameInfo DN = Record.readDeclarationNameInfo();
-    ConceptDecl *NamedConcept = Record.readDeclAs<ConceptDecl>();
-    const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
-    if (Record.readBool())
-        ArgsAsWritten = Record.readASTTemplateArgumentListInfo();
+    auto *CL = Record.readConceptLoc();
     Expr *ImmediatelyDeclaredConstraint = Record.readExpr();
-    D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept,
-                         ArgsAsWritten, ImmediatelyDeclaredConstraint);
+
+    D->setTypeConstraint(CL, ImmediatelyDeclaredConstraint);
     if ((D->ExpandedParameterPack = Record.readInt()))
       D->NumExpanded = Record.readInt();
   }
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -6806,19 +6806,25 @@
   TL.setUnderlyingTInfo(GetTypeSourceInfo());
 }
 
+ConceptLoc *ASTRecordReader::readConceptLoc() {
+  if (!readBool()) {
+    return nullptr;
+  }
+  auto NNS = readNestedNameSpecifierLoc();
+  auto TemplateKWLoc = readSourceLocation();
+  auto ConceptNameLoc = readDeclarationNameInfo();
+  auto FoundDecl = readDeclAs<NamedDecl>();
+  auto NamedConcept = readDeclAs<ConceptDecl>();
+  auto *CL = ConceptLoc::Create(
+      getContext(), NNS, TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept,
+      (readBool() ? readASTTemplateArgumentListInfo() : nullptr));
+  return CL;
+}
+
 void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) {
   TL.setNameLoc(readSourceLocation());
   if (Reader.readBool()) {
-    TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc());
-    TL.setTemplateKWLoc(readSourceLocation());
-    TL.setConceptNameLoc(readSourceLocation());
-    TL.setFoundDecl(Reader.readDeclAs<NamedDecl>());
-    TL.setLAngleLoc(readSourceLocation());
-    TL.setRAngleLoc(readSourceLocation());
-    for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i)
-      TL.setArgLocInfo(
-          i, Reader.readTemplateArgumentLocInfo(
-                 TL.getTypePtr()->getTypeConstraintArguments()[i].getKind()));
+    TL.setConceptLoc(Reader.readConceptLoc());
   }
   if (Reader.readBool())
     TL.setRParenLoc(readSourceLocation());
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -6858,15 +6858,22 @@
 
   AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result);
   NewTL.setNameLoc(TL.getNameLoc());
-  NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec);
-  NewTL.setTemplateKWLoc(TL.getTemplateKWLoc());
-  NewTL.setConceptNameLoc(TL.getConceptNameLoc());
-  NewTL.setFoundDecl(TL.getFoundDecl());
-  NewTL.setLAngleLoc(TL.getLAngleLoc());
-  NewTL.setRAngleLoc(TL.getRAngleLoc());
   NewTL.setRParenLoc(TL.getRParenLoc());
-  for (unsigned I = 0; I < NewTL.getNumArgs(); ++I)
-    NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo());
+
+  if (T->isConstrained()) {
+    DeclarationNameInfo DNI = DeclarationNameInfo(
+        TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(),
+        TL.getConceptNameLoc(),
+        TL.getTypePtr()->getTypeConstraintConcept()->getDeclName());
+    /*DNI.setLoc(TL.getConceptNameLoc());
+    DNI.setName(TL.getTypePtr()->getTypeConstraintConcept()->getDeclName());
+    DNI.setInfo(TL.getTypePtr()->getTypeConstraintConcept()->getDeclName());*/
+    auto *CL = ConceptLoc::Create(
+        SemaRef.Context, NewNestedNameSpec, TL.getTemplateKWLoc(), DNI,
+        TL.getFoundDecl(), TL.getTypePtr()->getTypeConstraintConcept(),
+        ASTTemplateArgumentListInfo::Create(SemaRef.Context, NewTemplateArgs));
+    NewTL.setConceptLoc(CL);
+  }
 
   return Result;
 }
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ clang/lib/Sema/SemaType.cpp
@@ -6300,24 +6300,27 @@
       TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId();
       if (!TemplateId)
         return;
-      if (DS.getTypeSpecScope().isNotEmpty())
-        TL.setNestedNameSpecifierLoc(
-            DS.getTypeSpecScope().getWithLocInContext(Context));
-      else
-        TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
-      TL.setTemplateKWLoc(TemplateId->TemplateKWLoc);
-      TL.setConceptNameLoc(TemplateId->TemplateNameLoc);
-      TL.setFoundDecl(nullptr);
-      TL.setLAngleLoc(TemplateId->LAngleLoc);
-      TL.setRAngleLoc(TemplateId->RAngleLoc);
-      if (TemplateId->NumArgs == 0)
-        return;
-      TemplateArgumentListInfo TemplateArgsInfo;
-      ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
-                                         TemplateId->NumArgs);
-      SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
-      for (unsigned I = 0; I < TemplateId->NumArgs; ++I)
-        TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo());
+
+      NestedNameSpecifierLoc NNS =
+          (DS.getTypeSpecScope().isNotEmpty()
+               ? DS.getTypeSpecScope().getWithLocInContext(Context)
+               : NestedNameSpecifierLoc());
+      TemplateArgumentListInfo TemplateArgsInfo(TemplateId->LAngleLoc,
+                                                TemplateId->RAngleLoc);
+      if (TemplateId->NumArgs > 0) {
+        ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(),
+                                           TemplateId->NumArgs);
+        SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo);
+      }
+      DeclarationNameInfo DNI = DeclarationNameInfo(
+          TL.getTypePtr()->getTypeConstraintConcept()->getDeclName(),
+          TemplateId->TemplateNameLoc);
+      auto *CL = ConceptLoc::Create(
+          Context, NNS, TemplateId->TemplateKWLoc, DNI,
+          /*FoundDecl=*/nullptr,
+          /*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(),
+          ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo));
+      TL.setConceptLoc(CL);
     }
     void VisitTagTypeLoc(TagTypeLoc TL) {
       TL.setNameLoc(DS.getTypeSpecTypeNameLoc());
Index: clang/lib/Sema/SemaTemplateInstantiate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2769,11 +2769,9 @@
       TC->getTemplateArgsAsWritten();
 
   if (!EvaluateConstraints) {
-    Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(),
-                            TC->getConceptNameInfo(), TC->getNamedConcept(),
-                            TC->getNamedConcept(), TemplArgInfo,
-                            TC->getImmediatelyDeclaredConstraint());
-    return false;
+      Inst->setTypeConstraint(TC->getConceptLoc(),
+                              TC->getImmediatelyDeclaredConstraint());
+      return false;
   }
 
   TemplateArgumentListInfo InstArgs;
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -23,6 +23,7 @@
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/Stack.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Sema/DeclSpec.h"
@@ -1256,9 +1257,13 @@
   if (ImmediatelyDeclaredConstraint.isInvalid())
     return true;
 
-  ConstrainedParameter->setTypeConstraint(NS, NameInfo,
-                                          /*FoundDecl=*/NamedConcept,
-                                          NamedConcept, ArgsAsWritten,
+  auto *CL = ConceptLoc::Create(Context, /*NNS=*/NS,
+                                /*TemplateKWLoc=*/SourceLocation{},
+                                /*ConceptNameInfo=*/NameInfo,
+                                /*FoundDecl=*/NamedConcept,
+                                /*NamedConcept=*/NamedConcept,
+                                /*ArgsWritten=*/ArgsAsWritten);
+  ConstrainedParameter->setTypeConstraint(CL,
                                           ImmediatelyDeclaredConstraint.get());
   return false;
 }
@@ -4941,13 +4946,13 @@
                       TemplateArgs->getRAngleLoc()),
           Satisfaction))
     return ExprError();
-
-  return ConceptSpecializationExpr::Create(
+  auto *CL = ConceptLoc::Create(
       Context,
       SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{},
       TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
-      ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), CSD,
-      AreArgsDependent ? nullptr : &Satisfaction);
+      ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs));
+  return ConceptSpecializationExpr::Create(
+      Context, CL, CSD, AreArgsDependent ? nullptr : &Satisfaction);
 }
 
 ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
Index: clang/lib/AST/TypeLoc.cpp
===================================================================
--- clang/lib/AST/TypeLoc.cpp
+++ clang/lib/AST/TypeLoc.cpp
@@ -621,25 +621,14 @@
   }
 }
 
-DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const {
-  return DeclarationNameInfo(getNamedConcept()->getDeclName(),
-                             getLocalData()->ConceptNameLoc);
-}
-
 void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) {
-  setNestedNameSpecifierLoc(NestedNameSpecifierLoc());
-  setTemplateKWLoc(Loc);
-  setConceptNameLoc(Loc);
-  setFoundDecl(nullptr);
-  setRAngleLoc(Loc);
-  setLAngleLoc(Loc);
   setRParenLoc(Loc);
   TemplateSpecializationTypeLoc::initializeArgLocs(
       Context, getTypePtr()->getTypeConstraintArguments(), getArgInfos(), Loc);
   setNameLoc(Loc);
+  setConceptLoc(nullptr);
 }
 
-
 namespace {
 
   class GetContainedAutoTypeLocVisitor :
Index: clang/lib/AST/ExprConcepts.cpp
===================================================================
--- clang/lib/AST/ExprConcepts.cpp
+++ clang/lib/AST/ExprConcepts.cpp
@@ -31,26 +31,24 @@
 using namespace clang;
 
 ConceptSpecializationExpr::ConceptSpecializationExpr(
-    const ASTContext &C, NestedNameSpecifierLoc NNS,
-    SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
-    NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten,
+    const ASTContext &C, ConceptLoc *Loc,
     ImplicitConceptSpecializationDecl *SpecDecl,
     const ConstraintSatisfaction *Satisfaction)
     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
-      ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
-                       NamedConcept, ArgsAsWritten),
-      SpecDecl(SpecDecl),
+      Loc(Loc), SpecDecl(SpecDecl),
       Satisfaction(Satisfaction
                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
                        : nullptr) {
   setDependence(computeDependence(this, /*ValueDependent=*/!Satisfaction));
 
   // Currently guaranteed by the fact concepts can only be at namespace-scope.
-  assert(!NestedNameSpec ||
-         (!NestedNameSpec.getNestedNameSpecifier()->isInstantiationDependent() &&
-          !NestedNameSpec.getNestedNameSpecifier()
-              ->containsUnexpandedParameterPack()));
+  assert(!Loc->getNestedNameSpecifierLoc() ||
+         (!Loc->getNestedNameSpecifierLoc()
+               .getNestedNameSpecifier()
+               ->isInstantiationDependent() &&
+          !Loc->getNestedNameSpecifierLoc()
+               .getNestedNameSpecifier()
+               ->containsUnexpandedParameterPack()));
   assert((!isValueDependent() || isInstantiationDependent()) &&
          "should not be value-dependent");
 }
@@ -58,29 +56,20 @@
 ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty)
     : Expr(ConceptSpecializationExprClass, Empty) {}
 
-ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
-    const ASTContext &C, NestedNameSpecifierLoc NNS,
-    SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
-    NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten,
-    ImplicitConceptSpecializationDecl *SpecDecl,
-    const ConstraintSatisfaction *Satisfaction) {
-  return new (C) ConceptSpecializationExpr(
-      C, NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept,
-      ArgsAsWritten, SpecDecl, Satisfaction);
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C, ConceptLoc *Loc,
+                                  ImplicitConceptSpecializationDecl *SpecDecl,
+                                  const ConstraintSatisfaction *Satisfaction) {
+  return new (C) ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction);
 }
 
 ConceptSpecializationExpr::ConceptSpecializationExpr(
-    const ASTContext &C, ConceptDecl *NamedConcept,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten,
+    const ASTContext &C, ConceptLoc *Loc,
     ImplicitConceptSpecializationDecl *SpecDecl,
     const ConstraintSatisfaction *Satisfaction, bool Dependent,
     bool ContainsUnexpandedParameterPack)
     : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary),
-      ConceptReference(NestedNameSpecifierLoc(), SourceLocation(),
-                       DeclarationNameInfo(), NamedConcept, NamedConcept,
-                       ArgsAsWritten),
-      SpecDecl(SpecDecl),
+      Loc(Loc), SpecDecl(SpecDecl),
       Satisfaction(Satisfaction
                        ? ASTConstraintSatisfaction::Create(C, *Satisfaction)
                        : nullptr) {
@@ -94,15 +83,15 @@
   setDependence(D);
 }
 
-ConceptSpecializationExpr *ConceptSpecializationExpr::Create(
-    const ASTContext &C, ConceptDecl *NamedConcept,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten,
-    ImplicitConceptSpecializationDecl *SpecDecl,
-    const ConstraintSatisfaction *Satisfaction, bool Dependent,
-    bool ContainsUnexpandedParameterPack) {
-  return new (C) ConceptSpecializationExpr(C, NamedConcept, ArgsAsWritten,
-                                           SpecDecl, Satisfaction, Dependent,
-                                           ContainsUnexpandedParameterPack);
+ConceptSpecializationExpr *
+ConceptSpecializationExpr::Create(const ASTContext &C, ConceptLoc *Loc,
+                                  ImplicitConceptSpecializationDecl *SpecDecl,
+                                  const ConstraintSatisfaction *Satisfaction,
+                                  bool Dependent,
+                                  bool ContainsUnexpandedParameterPack) {
+  return new (C)
+      ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent,
+                                ContainsUnexpandedParameterPack);
 }
 
 const TypeConstraint *
Index: clang/lib/AST/DeclTemplate.cpp
===================================================================
--- clang/lib/AST/DeclTemplate.cpp
+++ clang/lib/AST/DeclTemplate.cpp
@@ -697,17 +697,15 @@
   return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack();
 }
 
-void TemplateTypeParmDecl::setTypeConstraint(NestedNameSpecifierLoc NNS,
-    DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, ConceptDecl *CD,
-    const ASTTemplateArgumentListInfo *ArgsAsWritten,
-    Expr *ImmediatelyDeclaredConstraint) {
+void TemplateTypeParmDecl::setTypeConstraint(
+    ConceptLoc *Loc, Expr *ImmediatelyDeclaredConstraint) {
   assert(HasTypeConstraint &&
          "HasTypeConstraint=true must be passed at construction in order to "
          "call setTypeConstraint");
   assert(!TypeConstraintInitialized &&
          "TypeConstraint was already initialized!");
-  new (getTrailingObjects<TypeConstraint>()) TypeConstraint(NNS, NameInfo,
-      FoundDecl, CD, ArgsAsWritten, ImmediatelyDeclaredConstraint);
+  new (getTrailingObjects<TypeConstraint>())
+      TypeConstraint(Loc, ImmediatelyDeclaredConstraint);
   TypeConstraintInitialized = true;
 }
 
@@ -1554,7 +1552,7 @@
                    createBuiltinTemplateParameterList(C, DC, BTK)),
       BTK(BTK) {}
 
-void TypeConstraint::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const {
+void ConceptLoc::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const {
   if (NestedNameSpec)
     NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy);
   ConceptName.printName(OS, Policy);
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -5690,13 +5690,14 @@
       if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs,
                                                      ToTAInfo))
         return std::move(Err);
-
-    ToD->setTypeConstraint(ToNNS, DeclarationNameInfo(ToName, ToNameLoc),
-        ToFoundDecl, ToNamedConcept,
-        ASTTemplateArgs ?
-            ASTTemplateArgumentListInfo::Create(Importer.getToContext(),
-                                                ToTAInfo) : nullptr,
-        ToIDC);
+    auto *CL = ConceptLoc::Create(
+        Importer.getToContext(), ToNNS,
+        ToNameLoc, // What is the right Loc here?
+        DeclarationNameInfo(ToName, ToNameLoc), ToFoundDecl, ToNamedConcept,
+        ASTTemplateArgs ? ASTTemplateArgumentListInfo::Create(
+                              Importer.getToContext(), ToTAInfo)
+                        : nullptr);
+    ToD->setTypeConstraint(CL, ToIDC);
   }
 
   if (D->hasDefaultArgument()) {
Index: clang/lib/AST/ASTContext.cpp
===================================================================
--- clang/lib/AST/ASTContext.cpp
+++ clang/lib/AST/ASTContext.cpp
@@ -6345,11 +6345,12 @@
   auto *NCY = YTC->getNamedConcept();
   if (!NCX || !NCY || !isSameEntity(NCX, NCY))
     return false;
-  if (XTC->hasExplicitTemplateArgs() != YTC->hasExplicitTemplateArgs())
+  if (XTC->getConceptLoc()->hasExplicitTemplateArgs() !=
+      YTC->getConceptLoc()->hasExplicitTemplateArgs())
     return false;
-  if (XTC->hasExplicitTemplateArgs())
-    if (XTC->getTemplateArgsAsWritten()->NumTemplateArgs !=
-        YTC->getTemplateArgsAsWritten()->NumTemplateArgs)
+  if (XTC->getConceptLoc()->hasExplicitTemplateArgs())
+    if (XTC->getConceptLoc()->getTemplateArgsAsWritten()->NumTemplateArgs !=
+        YTC->getConceptLoc()->getTemplateArgsAsWritten()->NumTemplateArgs)
       return false;
 
   // Compare slowly by profiling.
Index: clang/include/clang/Serialization/ASTRecordWriter.h
===================================================================
--- clang/include/clang/Serialization/ASTRecordWriter.h
+++ clang/include/clang/Serialization/ASTRecordWriter.h
@@ -222,6 +222,9 @@
   void AddASTTemplateArgumentListInfo(
       const ASTTemplateArgumentListInfo *ASTTemplArgList);
 
+  // Emits a concept location.
+  void AddConceptLoc(const ConceptLoc *CL);
+
   /// Emit a reference to a declaration.
   void AddDeclRef(const Decl *D) {
     return Writer->AddDeclRef(D, *Record);
Index: clang/include/clang/Serialization/ASTRecordReader.h
===================================================================
--- clang/include/clang/Serialization/ASTRecordReader.h
+++ clang/include/clang/Serialization/ASTRecordReader.h
@@ -158,6 +158,9 @@
   const ASTTemplateArgumentListInfo*
   readASTTemplateArgumentListInfo();
 
+  // Reads a concept location from the given record.
+  ConceptLoc *readConceptLoc();
+
   /// Reads a declarator info from the given record, advancing Idx.
   TypeSourceInfo *readTypeSourceInfo();
 
Index: clang/include/clang/AST/TypeLoc.h
===================================================================
--- clang/include/clang/AST/TypeLoc.h
+++ clang/include/clang/AST/TypeLoc.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_CLANG_AST_TYPELOC_H
 #define LLVM_CLANG_AST_TYPELOC_H
 
+#include "clang/AST/ASTConcept.h"
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/TemplateBase.h"
@@ -2104,16 +2105,10 @@
                                        DeducedType> {};
 
 struct AutoTypeLocInfo : TypeSpecLocInfo {
-  NestedNameSpecifierLoc NestedNameSpec;
-  SourceLocation TemplateKWLoc;
-  SourceLocation ConceptNameLoc;
-  NamedDecl *FoundDecl = nullptr;
-  SourceLocation LAngleLoc;
-  SourceLocation RAngleLoc;
-
   // For decltype(auto).
   SourceLocation RParenLoc;
 
+  ConceptLoc *CL = nullptr;
   // Followed by a TemplateArgumentLocInfo[]
 };
 
@@ -2135,79 +2130,75 @@
     return getTypePtr()->isConstrained();
   }
 
-  const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
-    return getLocalData()->NestedNameSpec;
-  }
+  void setConceptLoc(ConceptLoc *Loc) { getLocalData()->CL = Loc; }
 
-  void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) {
-    getLocalData()->NestedNameSpec = NNS;
-  }
+  ConceptLoc *getConceptLoc() const { return getLocalData()->CL; }
 
-  SourceLocation getTemplateKWLoc() const {
-    return getLocalData()->TemplateKWLoc;
+  // FIXME: Deprecate the following functions and let the caller directly
+  // work with the ConceptLoc.
+  const NestedNameSpecifierLoc getNestedNameSpecifierLoc() const {
+    if (getConceptLoc())
+      return getConceptLoc()->getNestedNameSpecifierLoc();
+    return NestedNameSpecifierLoc();
   }
 
-  void setTemplateKWLoc(SourceLocation Loc) {
-    getLocalData()->TemplateKWLoc = Loc;
+  SourceLocation getTemplateKWLoc() const {
+    if (getConceptLoc())
+      return getConceptLoc()->getTemplateKWLoc();
+    return SourceLocation();
   }
 
   SourceLocation getConceptNameLoc() const {
-    return getLocalData()->ConceptNameLoc;
-  }
-
-  void setConceptNameLoc(SourceLocation Loc) {
-    getLocalData()->ConceptNameLoc = Loc;
+    if (getConceptLoc())
+      return getConceptLoc()->getConceptNameLoc();
+    return SourceLocation();
   }
 
   NamedDecl *getFoundDecl() const {
-    return getLocalData()->FoundDecl;
-  }
-
-  void setFoundDecl(NamedDecl *D) {
-    getLocalData()->FoundDecl = D;
+    if (getConceptLoc())
+      return getConceptLoc()->getFoundDecl();
+    return nullptr;
   }
 
   ConceptDecl *getNamedConcept() const {
-    return getTypePtr()->getTypeConstraintConcept();
+    if (getConceptLoc())
+      return getConceptLoc()->getNamedConcept();
+    return nullptr;
   }
 
-  DeclarationNameInfo getConceptNameInfo() const;
+  DeclarationNameInfo getConceptNameInfo() const {
+    return getConceptLoc()->getConceptNameInfo();
+  }
 
   bool hasExplicitTemplateArgs() const {
-    return getLocalData()->LAngleLoc.isValid();
+    return (
+        getConceptLoc() && getConceptLoc()->getTemplateArgsAsWritten() &&
+        getConceptLoc()->getTemplateArgsAsWritten()->getLAngleLoc().isValid());
   }
 
   SourceLocation getLAngleLoc() const {
-    return this->getLocalData()->LAngleLoc;
-  }
-
-  void setLAngleLoc(SourceLocation Loc) {
-    this->getLocalData()->LAngleLoc = Loc;
+    if (getConceptLoc() && getConceptLoc()->getTemplateArgsAsWritten())
+      return getConceptLoc()->getTemplateArgsAsWritten()->getLAngleLoc();
+    return SourceLocation();
   }
 
   SourceLocation getRAngleLoc() const {
-    return this->getLocalData()->RAngleLoc;
-  }
-
-  void setRAngleLoc(SourceLocation Loc) {
-    this->getLocalData()->RAngleLoc = Loc;
+    if (getConceptLoc() && getConceptLoc()->getTemplateArgsAsWritten())
+      return getConceptLoc()->getTemplateArgsAsWritten()->getRAngleLoc();
+    return SourceLocation();
   }
 
   unsigned getNumArgs() const {
     return getTypePtr()->getTypeConstraintArguments().size();
   }
 
-  void setArgLocInfo(unsigned i, TemplateArgumentLocInfo AI) {
-    getArgInfos()[i] = AI;
-  }
-
-  TemplateArgumentLocInfo getArgLocInfo(unsigned i) const {
-    return getArgInfos()[i];
-  }
-
   TemplateArgumentLoc getArgLoc(unsigned i) const {
+    if (getConceptLoc())
+      return getConceptLoc()->getTemplateArgsAsWritten()->getTemplateArgs()[i];
+    // FIXME: Check why we still need this fallback in case that there is no
+    // ConceptLoc.
     return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i],
-                               getArgLocInfo(i));
+                               getArgInfos()[i]);
   }
 
   SourceRange getLocalSourceRange() const {
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -312,6 +312,13 @@
   /// \returns false if the visitation was terminated early, true otherwise.
   bool TraverseObjCProtocolLoc(ObjCProtocolLoc ProtocolLoc);
 
+  /// Recursively visit concept reference with location information.
+  ///
+  /// \returns false if the visitation was terminated early, true otherwise.
+  bool TraverseConceptLoc(const ConceptLoc *CL);
+
+  // Visit concept loc.
+  bool VisitConceptLoc(const ConceptLoc *CL) { return true; }
   // ---- Methods on Attrs ----
 
   // Visit an attribute.
@@ -469,9 +476,6 @@
 private:
   // These are helper methods used by more than one Traverse* method.
   bool TraverseTemplateParameterListHelper(TemplateParameterList *TPL);
-  /// Traverses the qualifier, name and template arguments of a concept
-  /// reference.
-  bool TraverseConceptReferenceHelper(const ConceptReference &C);
 
   // Traverses template parameter lists of either a DeclaratorDecl or TagDecl.
   template <typename T>
@@ -507,17 +511,17 @@
 bool RecursiveASTVisitor<Derived>::TraverseTypeConstraint(
     const TypeConstraint *C) {
   if (!getDerived().shouldVisitImplicitCode()) {
-    TRY_TO(TraverseConceptReferenceHelper(*C));
+    TRY_TO(TraverseConceptLoc(C->getConceptLoc()));
     return true;
   }
   if (Expr *IDC = C->getImmediatelyDeclaredConstraint()) {
     TRY_TO(TraverseStmt(IDC));
   } else {
-    // Avoid traversing the ConceptReference in the TypeConstraint
+    // Avoid traversing the ConceptLoc in the TypeConstraint
     // if we have an immediately-declared-constraint, otherwise
     // we'll end up visiting the concept and the arguments in
     // the TC twice.
-    TRY_TO(TraverseConceptReferenceHelper(*C));
+    TRY_TO(TraverseConceptLoc(C->getConceptLoc()));
   }
   return true;
 }
@@ -540,18 +544,6 @@
   llvm_unreachable("unexpected case");
 }
 
-template <typename Derived>
-bool RecursiveASTVisitor<Derived>::TraverseConceptReferenceHelper(
-    const ConceptReference &C) {
-  TRY_TO(TraverseNestedNameSpecifierLoc(C.getNestedNameSpecifierLoc()));
-  TRY_TO(TraverseDeclarationNameInfo(C.getConceptNameInfo()));
-  if (C.hasExplicitTemplateArgs())
-    TRY_TO(TraverseTemplateArgumentLocsHelper(
-        C.getTemplateArgsAsWritten()->getTemplateArgs(),
-        C.getTemplateArgsAsWritten()->NumTemplateArgs));
-  return true;
-}
-
 template <typename Derived>
 bool RecursiveASTVisitor<Derived>::dataTraverseNode(Stmt *S,
                                                     DataRecursionQueue *Queue) {
@@ -1356,10 +1348,7 @@
 DEF_TRAVERSE_TYPELOC(AutoType, {
   TRY_TO(TraverseType(TL.getTypePtr()->getDeducedType()));
   if (TL.isConstrained()) {
-    TRY_TO(TraverseNestedNameSpecifierLoc(TL.getNestedNameSpecifierLoc()));
-    TRY_TO(TraverseDeclarationNameInfo(TL.getConceptNameInfo()));
-    for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I)
-      TRY_TO(TraverseTemplateArgumentLoc(TL.getArgLoc(I)));
+    TRY_TO(TraverseConceptLoc(TL.getConceptLoc()));
   }
 })
 
@@ -2522,6 +2511,18 @@
   return true;
 }
 
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::TraverseConceptLoc(const ConceptLoc *CL) {
+  TRY_TO(VisitConceptLoc(CL));
+  TRY_TO(TraverseNestedNameSpecifierLoc(CL->getNestedNameSpecifierLoc()));
+  TRY_TO(TraverseDeclarationNameInfo(CL->getConceptNameInfo()));
+  if (CL->hasExplicitTemplateArgs())
+    TRY_TO(TraverseTemplateArgumentLocsHelper(
+        CL->getTemplateArgsAsWritten()->getTemplateArgs(),
+        CL->getTemplateArgsAsWritten()->NumTemplateArgs));
+  return true;
+}
+
 // If shouldVisitImplicitCode() returns false, this method traverses only the
 // syntactic form of InitListExpr.
 // If shouldVisitImplicitCode() return true, this method is called once for
@@ -2904,7 +2905,7 @@
 })
 
 DEF_TRAVERSE_STMT(ConceptSpecializationExpr,
-                  { TRY_TO(TraverseConceptReferenceHelper(*S)); })
+                  { TRY_TO(TraverseConceptLoc(S->getConceptLoc())); })
 
 DEF_TRAVERSE_STMT(RequiresExpr, {
   TRY_TO(TraverseDecl(S->getBody()));
Index: clang/include/clang/AST/ExprConcepts.h
===================================================================
--- clang/include/clang/AST/ExprConcepts.h
+++ clang/include/clang/AST/ExprConcepts.h
@@ -38,7 +38,7 @@
 ///
 /// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
 /// specialization of a concept results in a prvalue of type bool.
-class ConceptSpecializationExpr final : public Expr, public ConceptReference {
+class ConceptSpecializationExpr final : public Expr {
   friend class ASTReader;
   friend class ASTStmtReader;
 
@@ -46,6 +46,8 @@
   using SubstitutionDiagnostic = std::pair<SourceLocation, std::string>;
 
 protected:
+  ConceptLoc *Loc;
+
   /// \brief The Implicit Concept Specialization Decl, which holds the template
   /// arguments for this specialization.
   ImplicitConceptSpecializationDecl *SpecDecl;
@@ -55,16 +57,11 @@
   /// ignored.
   ASTConstraintSatisfaction *Satisfaction;
 
-  ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS,
-                            SourceLocation TemplateKWLoc,
-                            DeclarationNameInfo ConceptNameInfo,
-                            NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
-                            const ASTTemplateArgumentListInfo *ArgsAsWritten,
+  ConceptSpecializationExpr(const ASTContext &C, ConceptLoc *Loc,
                             ImplicitConceptSpecializationDecl *SpecDecl,
                             const ConstraintSatisfaction *Satisfaction);
 
-  ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept,
-                            const ASTTemplateArgumentListInfo *ArgsAsWritten,
+  ConceptSpecializationExpr(const ASTContext &C, ConceptLoc *Loc,
                             ImplicitConceptSpecializationDecl *SpecDecl,
                             const ConstraintSatisfaction *Satisfaction,
                             bool Dependent,
@@ -73,16 +70,12 @@
 
 public:
   static ConceptSpecializationExpr *
-  Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
-         SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
-         NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
-         const ASTTemplateArgumentListInfo *ArgsAsWritten,
+  Create(const ASTContext &C, ConceptLoc *Loc,
          ImplicitConceptSpecializationDecl *SpecDecl,
          const ConstraintSatisfaction *Satisfaction);
 
   static ConceptSpecializationExpr *
-  Create(const ASTContext &C, ConceptDecl *NamedConcept,
-         const ASTTemplateArgumentListInfo *ArgsAsWritten,
+  Create(const ASTContext &C, ConceptLoc *Loc,
          ImplicitConceptSpecializationDecl *SpecDecl,
          const ConstraintSatisfaction *Satisfaction, bool Dependent,
          bool ContainsUnexpandedParameterPack);
@@ -91,6 +84,34 @@
     return SpecDecl->getTemplateArguments();
   }
 
+  const ConceptLoc *getConceptLoc() const { return Loc; }
+
+  // NOTE(massberg): For the first minimal prototype we keep the
+  // following functions to prevent. Later these functions should
+  // be accessed getConceptLoc().
+  ConceptDecl *getNamedConcept() const { return Loc->getNamedConcept(); }
+
+  bool hasExplicitTemplateArgs() const {
+    return Loc->hasExplicitTemplateArgs();
+  }
+
+  SourceLocation getConceptNameLoc() const { return Loc->getConceptNameLoc(); }
+  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+    return Loc->getTemplateArgsAsWritten();
+  }
+
+  const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
+    return Loc->getNestedNameSpecifierLoc();
+  }
+
+  SourceLocation getTemplateKWLoc() const { return Loc->getTemplateKWLoc(); }
+
+  NamedDecl *getFoundDecl() const { return Loc->getFoundDecl(); }
+
+  const DeclarationNameInfo &getConceptNameInfo() const {
+    return Loc->getConceptNameInfo();
+  }
+
   const ImplicitConceptSpecializationDecl *getSpecializationDecl() const {
     assert(SpecDecl && "Template Argument Decl not initialized");
     return SpecDecl;
@@ -119,17 +140,19 @@
   }
 
   SourceLocation getBeginLoc() const LLVM_READONLY {
-    if (auto QualifierLoc = getNestedNameSpecifierLoc())
+    if (auto QualifierLoc = Loc->getNestedNameSpecifierLoc())
       return QualifierLoc.getBeginLoc();
-    return ConceptName.getBeginLoc();
+    return Loc->getConceptNameInfo().getBeginLoc();
   }
 
   SourceLocation getEndLoc() const LLVM_READONLY {
     // If the ConceptSpecializationExpr is the ImmediatelyDeclaredConstraint
     // of a TypeConstraint written syntactically as a constrained-parameter,
     // there may not be a template argument list.
-    return ArgsAsWritten->RAngleLoc.isValid() ? ArgsAsWritten->RAngleLoc
-                                              : ConceptName.getEndLoc();
+    return Loc->hasExplicitTemplateArgs() &&
+                   Loc->getTemplateArgsAsWritten()->getRAngleLoc().isValid()
+               ? Loc->getTemplateArgsAsWritten()->getRAngleLoc()
+               : Loc->getConceptNameInfo().getEndLoc();
   }
 
   // Iterators
Index: clang/include/clang/AST/DeclTemplate.h
===================================================================
--- clang/include/clang/AST/DeclTemplate.h
+++ clang/include/clang/AST/DeclTemplate.h
@@ -1373,11 +1373,7 @@
          nullptr;
   }
 
-  void setTypeConstraint(NestedNameSpecifierLoc NNS,
-                         DeclarationNameInfo NameInfo, NamedDecl *FoundDecl,
-                         ConceptDecl *CD,
-                         const ASTTemplateArgumentListInfo *ArgsAsWritten,
-                         Expr *ImmediatelyDeclaredConstraint);
+  void setTypeConstraint(ConceptLoc *Loc, Expr *ImmediatelyDeclaredConstraint);
 
   /// Determine whether this template parameter has a type-constraint.
   bool hasTypeConstraint() const {
Index: clang/include/clang/AST/ASTConcept.h
===================================================================
--- clang/include/clang/AST/ASTConcept.h
+++ clang/include/clang/AST/ASTConcept.h
@@ -14,7 +14,9 @@
 #ifndef LLVM_CLANG_AST_ASTCONCEPT_H
 #define LLVM_CLANG_AST_ASTCONCEPT_H
 
+#include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/PrettyPrinter.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/ADT/PointerUnion.h"
 #include "llvm/ADT/SmallVector.h"
@@ -109,7 +111,7 @@
 
 /// \brief Common data class for constructs that reference concepts with
 /// template arguments.
-class ConceptReference {
+class ConceptLoc {
 protected:
   // \brief The optional nested name specifier used when naming the concept.
   NestedNameSpecifierLoc NestedNameSpec;
@@ -135,17 +137,26 @@
   const ASTTemplateArgumentListInfo *ArgsAsWritten;
 
 public:
-  ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
-                   DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
-                   ConceptDecl *NamedConcept,
-                   const ASTTemplateArgumentListInfo *ArgsAsWritten)
+  ConceptLoc(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
+             DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
+             ConceptDecl *NamedConcept,
+             const ASTTemplateArgumentListInfo *ArgsAsWritten)
       : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
         ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
         NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {}
 
-  ConceptReference()
+  ConceptLoc()
       : FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {}
 
+  static ConceptLoc *Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
+                            SourceLocation TemplateKWLoc,
+                            DeclarationNameInfo ConceptNameInfo,
+                            NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
+                            const ASTTemplateArgumentListInfo *ArgsAsWritten) {
+    return new (C) ConceptLoc(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl,
+                              NamedConcept, ArgsAsWritten);
+  }
+
   const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
     return NestedNameSpec;
   }
@@ -175,22 +186,20 @@
   bool hasExplicitTemplateArgs() const {
     return ArgsAsWritten != nullptr;
   }
+
+  void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const;
 };
 
-class TypeConstraint : public ConceptReference {
+class TypeConstraint {
   /// \brief The immediately-declared constraint expression introduced by this
   /// type-constraint.
   Expr *ImmediatelyDeclaredConstraint = nullptr;
+  ConceptLoc *Loc;
 
 public:
-  TypeConstraint(NestedNameSpecifierLoc NNS,
-                 DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
-                 ConceptDecl *NamedConcept,
-                 const ASTTemplateArgumentListInfo *ArgsAsWritten,
-                 Expr *ImmediatelyDeclaredConstraint) :
-      ConceptReference(NNS, /*TemplateKWLoc=*/SourceLocation(), ConceptNameInfo,
-                       FoundDecl, NamedConcept, ArgsAsWritten),
-      ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint) {}
+  TypeConstraint(ConceptLoc *Loc, Expr *ImmediatelyDeclaredConstraint)
+      : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint), Loc(Loc) {
+  }
 
   /// \brief Get the immediately-declared constraint expression introduced by
   /// this type-constraint, that is - the constraint expression that is added to
@@ -199,7 +208,37 @@
     return ImmediatelyDeclaredConstraint;
   }
 
-  void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const;
+  ConceptLoc *getConceptLoc() const { return Loc; }
+
+  // FIXME: Instead of using these concept related functions the callers should
+  // directly work with the corresponding ConceptLoc.
+  ConceptDecl *getNamedConcept() const { return Loc->getNamedConcept(); }
+
+  SourceLocation getConceptNameLoc() const { return Loc->getConceptNameLoc(); }
+
+  bool hasExplicitTemplateArgs() const {
+    return Loc->hasExplicitTemplateArgs();
+  }
+
+  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+    return Loc->getTemplateArgsAsWritten();
+  }
+
+  SourceLocation getTemplateKWLoc() const { return Loc->getTemplateKWLoc(); }
+
+  NamedDecl *getFoundDecl() const { return Loc->getFoundDecl(); }
+
+  const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
+    return Loc->getNestedNameSpecifierLoc();
+  }
+
+  const DeclarationNameInfo &getConceptNameInfo() const {
+    return Loc->getConceptNameInfo();
+  }
+
+  void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const {
+    Loc->print(OS, Policy);
+  }
 };
 
 } // clang
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to