diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h --- a/clang/include/clang/AST/ASTConcept.h +++ b/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" @@ -107,8 +109,17 @@ Rebuild(const ASTContext &C, const ASTConstraintSatisfaction &Satisfaction); }; -/// \brief Common data class for constructs that reference concepts with -/// template arguments. +/// A reference to a concept and its template args, as it appears in the code. +/// +/// Examples: +/// template requires is_even int half = X/2; +/// ~~~~~~~~~~ (in ConceptSpecializationExpr) +/// +/// std::input_iterator auto I = Container.begin(); +/// ~~~~~~~~~~~~~~~~~~~ (in AutoTypeLoc) +/// +/// template T> void dump(); +/// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl) class ConceptReference { protected: // \brief The optional nested name specifier used when naming the concept. @@ -134,7 +145,7 @@ /// concept. const ASTTemplateArgumentListInfo *ArgsAsWritten; -public: +private: ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, @@ -143,8 +154,15 @@ ConceptName(ConceptNameInfo), FoundDecl(FoundDecl), NamedConcept(NamedConcept), ArgsAsWritten(ArgsAsWritten) {} - ConceptReference() - : FoundDecl(nullptr), NamedConcept(nullptr), ArgsAsWritten(nullptr) {} +public: + static ConceptReference * + Create(const ASTContext &C, NestedNameSpecifierLoc NNS, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, + NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + const ASTTemplateArgumentListInfo *ArgsAsWritten) { + return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, + FoundDecl, NamedConcept, ArgsAsWritten); + } const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { return NestedNameSpec; @@ -158,6 +176,26 @@ SourceLocation getTemplateKWLoc() const { return TemplateKWLoc; } + SourceLocation getLocation() const { return getConceptNameLoc(); } + + SourceLocation getBeginLoc() const LLVM_READONLY { + // Note that if the qualifier is null the template KW must also be null. + if (auto QualifierLoc = getNestedNameSpecifierLoc()) + return QualifierLoc.getBeginLoc(); + return getConceptNameInfo().getBeginLoc(); + } + + SourceLocation getEndLoc() const LLVM_READONLY { + return getTemplateArgsAsWritten() && + getTemplateArgsAsWritten()->getRAngleLoc().isValid() + ? getTemplateArgsAsWritten()->getRAngleLoc() + : getConceptNameInfo().getEndLoc(); + } + + SourceRange getSourceRange() const LLVM_READONLY { + return SourceRange(getBeginLoc(), getEndLoc()); + } + NamedDecl *getFoundDecl() const { return FoundDecl; } @@ -175,22 +213,30 @@ bool hasExplicitTemplateArgs() const { return ArgsAsWritten != nullptr; } + + void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const; }; -class TypeConstraint : public ConceptReference { +/// Models the abbreviated syntax to constrain a template type parameter: +/// template T> void print(T object); +/// ~~~~~~~~~~~~~~~~~~~~~~ +/// Semantically, this adds an "immediately-declared constraint" with extra arg: +/// requires convertible_to +/// +/// In the C++ grammar, a type-constraint is also used for auto types: +/// convertible_to auto X = ...; +/// We do *not* model these as TypeConstraints, but AutoType(Loc) directly. +class TypeConstraint { /// \brief The immediately-declared constraint expression introduced by this /// type-constraint. Expr *ImmediatelyDeclaredConstraint = nullptr; + ConceptReference *ConceptRef; 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(ConceptReference *ConceptRef, + Expr *ImmediatelyDeclaredConstraint) + : ImmediatelyDeclaredConstraint(ImmediatelyDeclaredConstraint), + ConceptRef(ConceptRef) {} /// \brief Get the immediately-declared constraint expression introduced by /// this type-constraint, that is - the constraint expression that is added to @@ -199,7 +245,41 @@ return ImmediatelyDeclaredConstraint; } - void print(llvm::raw_ostream &OS, PrintingPolicy Policy) const; + ConceptReference *getConceptReference() const { return ConceptRef; } + + // FIXME: Instead of using these concept related functions the callers should + // directly work with the corresponding ConceptReference. + ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } + + SourceLocation getConceptNameLoc() const { + return ConceptRef->getConceptNameLoc(); + } + + bool hasExplicitTemplateArgs() const { + return ConceptRef->hasExplicitTemplateArgs(); + } + + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ConceptRef->getTemplateArgsAsWritten(); + } + + SourceLocation getTemplateKWLoc() const { + return ConceptRef->getTemplateKWLoc(); + } + + NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); } + + const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { + return ConceptRef->getNestedNameSpecifierLoc(); + } + + const DeclarationNameInfo &getConceptNameInfo() const { + return ConceptRef->getConceptNameInfo(); + } + + void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { + ConceptRef->print(OS, Policy); + } }; } // clang diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1373,10 +1373,7 @@ nullptr; } - void setTypeConstraint(NestedNameSpecifierLoc NNS, - DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, - ConceptDecl *CD, - const ASTTemplateArgumentListInfo *ArgsAsWritten, + void setTypeConstraint(ConceptReference *CR, Expr *ImmediatelyDeclaredConstraint); /// Determine whether this template parameter has a type-constraint. diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h --- a/clang/include/clang/AST/ExprConcepts.h +++ b/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; protected: + ConceptReference *ConceptRef; + /// \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, ConceptReference *ConceptRef, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); - ConceptSpecializationExpr(const ASTContext &C, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, + ConceptSpecializationExpr(const ASTContext &C, ConceptReference *ConceptRef, 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, ConceptReference *ConceptRef, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction); static ConceptSpecializationExpr * - Create(const ASTContext &C, ConceptDecl *NamedConcept, - const ASTTemplateArgumentListInfo *ArgsAsWritten, + Create(const ASTContext &C, ConceptReference *ConceptRef, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction, bool Dependent, bool ContainsUnexpandedParameterPack); @@ -91,6 +84,37 @@ return SpecDecl->getTemplateArguments(); } + ConceptReference *getConceptReference() const { return ConceptRef; } + + ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } + + // FIXME: Several of the following functions can be removed. Instead the + // caller can directly work with the ConceptReference. + bool hasExplicitTemplateArgs() const { + return ConceptRef->hasExplicitTemplateArgs(); + } + + SourceLocation getConceptNameLoc() const { + return ConceptRef->getConceptNameLoc(); + } + const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { + return ConceptRef->getTemplateArgsAsWritten(); + } + + const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { + return ConceptRef->getNestedNameSpecifierLoc(); + } + + SourceLocation getTemplateKWLoc() const { + return ConceptRef->getTemplateKWLoc(); + } + + NamedDecl *getFoundDecl() const { return ConceptRef->getFoundDecl(); } + + const DeclarationNameInfo &getConceptNameInfo() const { + return ConceptRef->getConceptNameInfo(); + } + const ImplicitConceptSpecializationDecl *getSpecializationDecl() const { assert(SpecDecl && "Template Argument Decl not initialized"); return SpecDecl; @@ -119,17 +143,15 @@ } SourceLocation getBeginLoc() const LLVM_READONLY { - if (auto QualifierLoc = getNestedNameSpecifierLoc()) - return QualifierLoc.getBeginLoc(); - return ConceptName.getBeginLoc(); + return ConceptRef->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 ConceptRef->getEndLoc(); + } + + SourceLocation getExprLoc() const LLVM_READONLY { + return ConceptRef->getLocation(); } // Iterators diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/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 TraverseConceptReference(ConceptReference *CR); + + // Visit concept reference. + bool VisitConceptReference(ConceptReference *CR) { 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 @@ -507,7 +511,7 @@ bool RecursiveASTVisitor::TraverseTypeConstraint( const TypeConstraint *C) { if (!getDerived().shouldVisitImplicitCode()) { - TRY_TO(TraverseConceptReferenceHelper(*C)); + TRY_TO(TraverseConceptReference(C->getConceptReference())); return true; } if (Expr *IDC = C->getImmediatelyDeclaredConstraint()) { @@ -517,7 +521,7 @@ // 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(TraverseConceptReference(C->getConceptReference())); } return true; } @@ -540,18 +544,6 @@ llvm_unreachable("unexpected case"); } -template -bool RecursiveASTVisitor::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 bool RecursiveASTVisitor::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(TraverseConceptReference(TL.getConceptReference())); } }) @@ -2522,6 +2511,22 @@ return true; } +template +bool RecursiveASTVisitor::TraverseConceptReference( + ConceptReference *CR) { + if (!getDerived().shouldTraversePostOrder()) + TRY_TO(VisitConceptReference(CR)); + TRY_TO(TraverseNestedNameSpecifierLoc(CR->getNestedNameSpecifierLoc())); + TRY_TO(TraverseDeclarationNameInfo(CR->getConceptNameInfo())); + if (CR->hasExplicitTemplateArgs()) + TRY_TO(TraverseTemplateArgumentLocsHelper( + CR->getTemplateArgsAsWritten()->getTemplateArgs(), + CR->getTemplateArgsAsWritten()->NumTemplateArgs)); + if (getDerived().shouldTraversePostOrder()) + TRY_TO(VisitConceptReference(CR)); + 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 @@ -2899,8 +2904,9 @@ } }) -DEF_TRAVERSE_STMT(ConceptSpecializationExpr, - { TRY_TO(TraverseConceptReferenceHelper(*S)); }) +DEF_TRAVERSE_STMT(ConceptSpecializationExpr, { + TRY_TO(TraverseConceptReference(S->getConceptReference())); +}) DEF_TRAVERSE_STMT(RequiresExpr, { TRY_TO(TraverseDecl(S->getBody())); diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h --- a/clang/include/clang/AST/TypeLoc.h +++ b/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,17 +2105,10 @@ DeducedType> {}; struct AutoTypeLocInfo : TypeSpecLocInfo { - NestedNameSpecifierLoc NestedNameSpec; - SourceLocation TemplateKWLoc; - SourceLocation ConceptNameLoc; - NamedDecl *FoundDecl = nullptr; - SourceLocation LAngleLoc; - SourceLocation RAngleLoc; - // For decltype(auto). SourceLocation RParenLoc; - // Followed by a TemplateArgumentLocInfo[] + ConceptReference *CR = nullptr; }; class AutoTypeLoc @@ -2135,79 +2129,77 @@ return getTypePtr()->isConstrained(); } - const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { - return getLocalData()->NestedNameSpec; - } + void setConceptReference(ConceptReference *CR) { getLocalData()->CR = CR; } - void setNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { - getLocalData()->NestedNameSpec = NNS; - } + ConceptReference *getConceptReference() const { return getLocalData()->CR; } - SourceLocation getTemplateKWLoc() const { - return getLocalData()->TemplateKWLoc; + // FIXME: Several of the following functions can be removed. Instead the + // caller can directly work with the ConceptReference. + const NestedNameSpecifierLoc getNestedNameSpecifierLoc() const { + if (const auto *CR = getConceptReference()) + return CR->getNestedNameSpecifierLoc(); + return NestedNameSpecifierLoc(); } - void setTemplateKWLoc(SourceLocation Loc) { - getLocalData()->TemplateKWLoc = Loc; + SourceLocation getTemplateKWLoc() const { + if (const auto *CR = getConceptReference()) + return CR->getTemplateKWLoc(); + return SourceLocation(); } SourceLocation getConceptNameLoc() const { - return getLocalData()->ConceptNameLoc; - } - - void setConceptNameLoc(SourceLocation Loc) { - getLocalData()->ConceptNameLoc = Loc; + if (const auto *CR = getConceptReference()) + return CR->getConceptNameLoc(); + return SourceLocation(); } NamedDecl *getFoundDecl() const { - return getLocalData()->FoundDecl; - } - - void setFoundDecl(NamedDecl *D) { - getLocalData()->FoundDecl = D; + if (const auto *CR = getConceptReference()) + return CR->getFoundDecl(); + return nullptr; } ConceptDecl *getNamedConcept() const { - return getTypePtr()->getTypeConstraintConcept(); + if (const auto *CR = getConceptReference()) + return CR->getNamedConcept(); + return nullptr; } - DeclarationNameInfo getConceptNameInfo() const; + DeclarationNameInfo getConceptNameInfo() const { + return getConceptReference()->getConceptNameInfo(); + } bool hasExplicitTemplateArgs() const { - return getLocalData()->LAngleLoc.isValid(); + return (getConceptReference() && + getConceptReference()->getTemplateArgsAsWritten() && + getConceptReference() + ->getTemplateArgsAsWritten() + ->getLAngleLoc() + .isValid()); } SourceLocation getLAngleLoc() const { - return this->getLocalData()->LAngleLoc; - } - - void setLAngleLoc(SourceLocation Loc) { - this->getLocalData()->LAngleLoc = Loc; + if (const auto *CR = getConceptReference()) + if (const auto *TAAW = CR->getTemplateArgsAsWritten()) + return TAAW->getLAngleLoc(); + return SourceLocation(); } SourceLocation getRAngleLoc() const { - return this->getLocalData()->RAngleLoc; - } - - void setRAngleLoc(SourceLocation Loc) { - this->getLocalData()->RAngleLoc = Loc; + if (const auto *CR = getConceptReference()) + if (const auto *TAAW = CR->getTemplateArgsAsWritten()) + return TAAW->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 { - return TemplateArgumentLoc(getTypePtr()->getTypeConstraintArguments()[i], - getArgLocInfo(i)); + const auto *CR = getConceptReference(); + assert(CR && "No ConceptReference"); + return CR->getTemplateArgsAsWritten()->getTemplateArgs()[i]; } SourceRange getLocalSourceRange() const { @@ -2227,19 +2219,6 @@ } void initializeLocal(ASTContext &Context, SourceLocation Loc); - - unsigned getExtraLocalDataSize() const { - return getNumArgs() * sizeof(TemplateArgumentLocInfo); - } - - unsigned getExtraLocalDataAlignment() const { - return alignof(TemplateArgumentLocInfo); - } - -private: - TemplateArgumentLocInfo *getArgInfos() const { - return static_cast(getExtraLocalData()); - } }; class DeducedTemplateSpecializationTypeLoc diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -158,6 +158,9 @@ const ASTTemplateArgumentListInfo* readASTTemplateArgumentListInfo(); + // Reads a concept reference from the given record. + ConceptReference *readConceptReference(); + /// Reads a declarator info from the given record, advancing Idx. TypeSourceInfo *readTypeSourceInfo(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -222,6 +222,9 @@ void AddASTTemplateArgumentListInfo( const ASTTemplateArgumentListInfo *ASTTemplArgList); + // Emits a concept reference. + void AddConceptReference(const ConceptReference *CR); + /// Emit a reference to a declaration. void AddDeclRef(const Decl *D) { return Writer->AddDeclRef(D, *Record); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6345,11 +6345,14 @@ auto *NCY = YTC->getNamedConcept(); if (!NCX || !NCY || !isSameEntity(NCX, NCY)) return false; - if (XTC->hasExplicitTemplateArgs() != YTC->hasExplicitTemplateArgs()) + if (XTC->getConceptReference()->hasExplicitTemplateArgs() != + YTC->getConceptReference()->hasExplicitTemplateArgs()) return false; - if (XTC->hasExplicitTemplateArgs()) - if (XTC->getTemplateArgsAsWritten()->NumTemplateArgs != - YTC->getTemplateArgsAsWritten()->NumTemplateArgs) + if (XTC->getConceptReference()->hasExplicitTemplateArgs()) + if (XTC->getConceptReference() + ->getTemplateArgsAsWritten() + ->NumTemplateArgs != + YTC->getConceptReference()->getTemplateArgsAsWritten()->NumTemplateArgs) return false; // Compare slowly by profiling. diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1004,6 +1004,33 @@ *ToRBracketLocOrErr); } +template <> +Expected ASTNodeImporter::import(ConceptReference *From) { + Error Err = Error::success(); + auto ToNNS = importChecked(Err, From->getNestedNameSpecifierLoc()); + auto ToTemplateKWLoc = importChecked(Err, From->getTemplateKWLoc()); + auto ToConceptNameLoc = + importChecked(Err, From->getConceptNameInfo().getLoc()); + auto ToConceptName = importChecked(Err, From->getConceptNameInfo().getName()); + auto ToFoundDecl = importChecked(Err, From->getFoundDecl()); + auto ToNamedConcept = importChecked(Err, From->getNamedConcept()); + if (Err) + return std::move(Err); + TemplateArgumentListInfo ToTAInfo; + const auto *ASTTemplateArgs = From->getTemplateArgsAsWritten(); + if (ASTTemplateArgs) + if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, ToTAInfo)) + return std::move(Err); + auto *ConceptRef = ConceptReference::Create( + Importer.getToContext(), ToNNS, ToTemplateKWLoc, + DeclarationNameInfo(ToConceptName, ToConceptNameLoc), ToFoundDecl, + ToNamedConcept, + ASTTemplateArgs ? ASTTemplateArgumentListInfo::Create( + Importer.getToContext(), ToTAInfo) + : nullptr); + return ConceptRef; +} + template <> Expected ASTNodeImporter::import(const LambdaCapture &From) { ValueDecl *Var = nullptr; @@ -5637,28 +5664,12 @@ if (const TypeConstraint *TC = D->getTypeConstraint()) { Error Err = Error::success(); - auto ToNNS = importChecked(Err, TC->getNestedNameSpecifierLoc()); - auto ToName = importChecked(Err, TC->getConceptNameInfo().getName()); - auto ToNameLoc = importChecked(Err, TC->getConceptNameInfo().getLoc()); - auto ToFoundDecl = importChecked(Err, TC->getFoundDecl()); - auto ToNamedConcept = importChecked(Err, TC->getNamedConcept()); + auto ToConceptRef = importChecked(Err, TC->getConceptReference()); auto ToIDC = importChecked(Err, TC->getImmediatelyDeclaredConstraint()); if (Err) return std::move(Err); - TemplateArgumentListInfo ToTAInfo; - const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten(); - if (ASTTemplateArgs) - 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); + ToD->setTypeConstraint(ToConceptRef, ToIDC); } if (D->hasDefaultArgument()) { diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -697,17 +697,15 @@ return getTypeForDecl()->castAs()->isParameterPack(); } -void TemplateTypeParmDecl::setTypeConstraint(NestedNameSpecifierLoc NNS, - DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, ConceptDecl *CD, - const ASTTemplateArgumentListInfo *ArgsAsWritten, - Expr *ImmediatelyDeclaredConstraint) { +void TemplateTypeParmDecl::setTypeConstraint( + ConceptReference *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(NNS, NameInfo, - FoundDecl, CD, ArgsAsWritten, ImmediatelyDeclaredConstraint); + new (getTrailingObjects()) + TypeConstraint(Loc, ImmediatelyDeclaredConstraint); TypeConstraintInitialized = true; } @@ -1554,7 +1552,8 @@ createBuiltinTemplateParameterList(C, DC, BTK)), BTK(BTK) {} -void TypeConstraint::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const { +void ConceptReference::print(llvm::raw_ostream &OS, + const PrintingPolicy &Policy) const { if (NestedNameSpec) NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy); ConceptName.printName(OS, Policy); diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp --- a/clang/lib/AST/ExprConcepts.cpp +++ b/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, ConceptReference *Loc, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction) : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_PRValue, OK_Ordinary), - ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, - NamedConcept, ArgsAsWritten), - SpecDecl(SpecDecl), + ConceptRef(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, ConceptReference *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, ConceptReference *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), + ConceptRef(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, ConceptReference *Loc, + ImplicitConceptSpecializationDecl *SpecDecl, + const ConstraintSatisfaction *Satisfaction, + bool Dependent, + bool ContainsUnexpandedParameterPack) { + return new (C) + ConceptSpecializationExpr(C, Loc, SpecDecl, Satisfaction, Dependent, + ContainsUnexpandedParameterPack); } const TypeConstraint * diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -11,9 +11,10 @@ //===----------------------------------------------------------------------===// #include "clang/AST/TypeLoc.h" -#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -621,25 +622,40 @@ } } -DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const { - return DeclarationNameInfo(getNamedConcept()->getDeclName(), - getLocalData()->ConceptNameLoc); +static ConceptReference *createConceptReference(ASTContext &Context, + SourceLocation Loc, + const AutoType *AT) { + DeclarationNameInfo DNI = + DeclarationNameInfo(AT->getTypeConstraintConcept()->getDeclName(), Loc, + AT->getTypeConstraintConcept()->getDeclName()); + unsigned size = AT->getTypeConstraintArguments().size(); + TemplateArgumentLocInfo *TALI = new TemplateArgumentLocInfo[size]; + TemplateSpecializationTypeLoc::initializeArgLocs( + Context, AT->getTypeConstraintArguments(), TALI, Loc); + TemplateArgumentListInfo TAListI; + for (unsigned i = 0; i < size; ++i) { + TAListI.addArgument( + TemplateArgumentLoc(AT->getTypeConstraintArguments()[i], + TALI[i])); // TemplateArgumentLocInfo() + } + + auto *ConceptRef = ConceptReference::Create( + Context, NestedNameSpecifierLoc{}, Loc, DNI, nullptr, + AT->getTypeConstraintConcept(), + ASTTemplateArgumentListInfo::Create(Context, TAListI)); + delete[] TALI; + return ConceptRef; } 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); + setConceptReference(nullptr); + if (getTypePtr()->isConstrained()) { + setConceptReference(createConceptReference(Context, Loc, getTypePtr())); + } } - namespace { class GetContainedAutoTypeLocVisitor : diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/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 = ConceptReference::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 = ConceptReference::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, diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2764,11 +2764,9 @@ TC->getTemplateArgsAsWritten(); if (!EvaluateConstraints) { - Inst->setTypeConstraint(TC->getNestedNameSpecifierLoc(), - TC->getConceptNameInfo(), TC->getNamedConcept(), - TC->getNamedConcept(), TemplArgInfo, - TC->getImmediatelyDeclaredConstraint()); - return false; + Inst->setTypeConstraint(TC->getConceptReference(), + TC->getImmediatelyDeclaredConstraint()); + return false; } TemplateArgumentListInfo InstArgs; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/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 *CR = ConceptReference::Create( + Context, NNS, TemplateId->TemplateKWLoc, DNI, + /*FoundDecl=*/nullptr, + /*NamedDecl=*/TL.getTypePtr()->getTypeConstraintConcept(), + ASTTemplateArgumentListInfo::Create(Context, TemplateArgsInfo)); + TL.setConceptReference(CR); } void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -6809,16 +6809,16 @@ TemplateArgumentListInfo NewTemplateArgs; NestedNameSpecifierLoc NewNestedNameSpec; if (T->isConstrained()) { + assert(TL.getConceptReference()); NewCD = cast_or_null(getDerived().TransformDecl( TL.getConceptNameLoc(), T->getTypeConstraintConcept())); NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); typedef TemplateArgumentLocContainerIterator ArgIterator; - if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), - ArgIterator(TL, - TL.getNumArgs()), - NewTemplateArgs)) + if (getDerived().TransformTemplateArguments( + ArgIterator(TL, 0), ArgIterator(TL, TL.getNumArgs()), + NewTemplateArgs)) return QualType(); if (TL.getNestedNameSpecifierLoc()) { @@ -6846,15 +6846,19 @@ AutoTypeLoc NewTL = TLB.push(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()); + auto *CR = ConceptReference::Create( + SemaRef.Context, NewNestedNameSpec, TL.getTemplateKWLoc(), DNI, + TL.getFoundDecl(), TL.getTypePtr()->getTypeConstraintConcept(), + ASTTemplateArgumentListInfo::Create(SemaRef.Context, NewTemplateArgs)); + NewTL.setConceptReference(CR); + } return Result; } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -6806,20 +6806,22 @@ TL.setUnderlyingTInfo(GetTypeSourceInfo()); } +ConceptReference *ASTRecordReader::readConceptReference() { + auto NNS = readNestedNameSpecifierLoc(); + auto TemplateKWLoc = readSourceLocation(); + auto ConceptNameLoc = readDeclarationNameInfo(); + auto FoundDecl = readDeclAs(); + auto NamedConcept = readDeclAs(); + auto *CR = ConceptReference::Create( + getContext(), NNS, TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, + (readBool() ? readASTTemplateArgumentListInfo() : nullptr)); + return CR; +} + void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { TL.setNameLoc(readSourceLocation()); - if (Reader.readBool()) { - TL.setNestedNameSpecifierLoc(ReadNestedNameSpecifierLoc()); - TL.setTemplateKWLoc(readSourceLocation()); - TL.setConceptNameLoc(readSourceLocation()); - TL.setFoundDecl(Reader.readDeclAs()); - 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())); - } + if (Reader.readBool()) + TL.setConceptReference(Reader.readConceptReference()); if (Reader.readBool()) TL.setRParenLoc(readSourceLocation()); } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -13,6 +13,7 @@ #include "ASTCommon.h" #include "ASTReaderInternals.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/Attr.h" @@ -2620,15 +2621,12 @@ D->setDeclaredWithTypename(Record.readInt()); if (Record.readBool()) { - NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc(); - DeclarationNameInfo DN = Record.readDeclarationNameInfo(); - ConceptDecl *NamedConcept = Record.readDeclAs(); - const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; + ConceptReference *CR = nullptr; if (Record.readBool()) - ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + CR = Record.readConceptReference(); Expr *ImmediatelyDeclaredConstraint = Record.readExpr(); - D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept, - ArgsAsWritten, ImmediatelyDeclaredConstraint); + + D->setTypeConstraint(CR, ImmediatelyDeclaredConstraint); if ((D->ExpandedParameterPack = Record.readInt())) D->NumExpanded = Record.readInt(); } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -795,13 +795,9 @@ void ASTStmtReader::VisitConceptSpecializationExpr( ConceptSpecializationExpr *E) { VisitExpr(E); - E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); - E->TemplateKWLoc = Record.readSourceLocation(); - E->ConceptName = Record.readDeclarationNameInfo(); - E->NamedConcept = readDeclAs(); - E->FoundDecl = Record.readDeclAs(); E->SpecDecl = Record.readDeclAs(); - E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + if (Record.readBool()) + E->ConceptRef = Record.readConceptReference(); E->Satisfaction = E->isValueDependent() ? nullptr : ASTConstraintSatisfaction::Create(Record.getContext(), readConstraintSatisfaction(Record)); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -469,21 +469,24 @@ Record.AddTypeSourceInfo(TL.getUnderlyingTInfo()); } +void ASTRecordWriter::AddConceptReference(const ConceptReference *CR) { + assert(CR); + AddNestedNameSpecifierLoc(CR->getNestedNameSpecifierLoc()); + AddSourceLocation(CR->getTemplateKWLoc()); + AddDeclarationNameInfo(CR->getConceptNameInfo()); + AddDeclRef(CR->getFoundDecl()); + AddDeclRef(CR->getNamedConcept()); + push_back(CR->getTemplateArgsAsWritten() != nullptr); + if (CR->getTemplateArgsAsWritten()) + AddASTTemplateArgumentListInfo(CR->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)); - } + auto *CR = TL.getConceptReference(); + Record.push_back(TL.isConstrained() && CR); + if (TL.isConstrained() && CR) + Record.AddConceptReference(CR); Record.push_back(TL.isDecltypeAuto()); if (TL.isDecltypeAuto()) addSourceLocation(TL.getRParenLoc()); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -1774,12 +1774,10 @@ 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()); + auto *CR = TC->getConceptReference(); + Record.push_back(CR != nullptr); + if (CR) + Record.AddConceptReference(CR); Record.AddStmt(TC->getImmediatelyDeclaredConstraint()); Record.push_back(D->isExpandedParameterPack()); if (D->isExpandedParameterPack()) diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -11,15 +11,16 @@ /// //===----------------------------------------------------------------------===// -#include "clang/AST/ExprOpenMP.h" -#include "clang/Serialization/ASTRecordWriter.h" -#include "clang/Sema/DeclSpec.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Lex/Token.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Serialization/ASTRecordWriter.h" #include "llvm/Bitstream/BitstreamWriter.h" using namespace clang; @@ -437,13 +438,11 @@ 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()); + const ConceptReference *CR = E->getConceptReference(); + Record.push_back(CR != nullptr); + if (CR) + Record.AddConceptReference(CR); if (!E->isValueDependent()) addConstraintSatisfaction(Record, E->getSatisfaction()); diff --git a/clang/unittests/AST/SourceLocationTest.cpp b/clang/unittests/AST/SourceLocationTest.cpp --- a/clang/unittests/AST/SourceLocationTest.cpp +++ b/clang/unittests/AST/SourceLocationTest.cpp @@ -16,7 +16,11 @@ //===----------------------------------------------------------------------===// #include "MatchVerifier.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTFwd.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/Tooling.h" @@ -370,10 +374,10 @@ TEST(CompoundLiteralExpr, ParensCompoundVectorLiteralRange) { RangeVerifier Verifier; Verifier.expectRange(2, 20, 2, 31); - EXPECT_TRUE(Verifier.match( - "typedef int int2 __attribute__((ext_vector_type(2)));\n" - "constant int2 i2 = (int2)(1, 2);", - compoundLiteralExpr(), Lang_OpenCL)); + EXPECT_TRUE( + Verifier.match("typedef int int2 __attribute__((ext_vector_type(2)));\n" + "constant int2 i2 = (int2)(1, 2);", + compoundLiteralExpr(), Lang_OpenCL)); } TEST(InitListExpr, VectorLiteralListBraceRange) { @@ -1000,4 +1004,131 @@ ASSERT_EQ(SM.getFileOffset(TL.getStarLoc()), Example.point("star")); } +class AutoTypeLocConceptReferenceRangeVerifier + : public RangeVerifier { +protected: + SourceRange getRange(const AutoTypeLoc &Node) override { + if (const ConceptReference *ConceptRef = Node.getConceptReference()) { + return ConceptRef->getSourceRange(); + } + return SourceRange(); + } +}; + +TEST(LocationVerifier, AutoTypeLocConceptReference) { + AutoTypeLocConceptReferenceRangeVerifier Verifier; + + const char *Code = + R"cpp(template concept CCC = true; +CCC auto abc(); +)cpp"; + // FIXME: expected range should be (2, 1, 2, 3) + Verifier.expectRange(2, 1, 2, 1); + EXPECT_TRUE(Verifier.match(Code, typeLoc(loc(autoType())), Lang_CXX20)); + + const char *Code2 = + R"cpp(template concept CCC = true; +CCC<10> auto abc(); +)cpp"; + Verifier.expectRange(2, 1, 2, 7); + EXPECT_TRUE(Verifier.match(Code2, typeLoc(loc(autoType())), Lang_CXX20)); + + const char *Code3 = + R"cpp(namespace NS { + template concept CCC = true; +} +NS::CCC<10> auto abc(); +)cpp"; + Verifier.expectRange(4, 1, 4, 11); + EXPECT_TRUE(Verifier.match(Code3, typeLoc(loc(autoType())), Lang_CXX20)); + + const char *Code4 = + R"cpp(template concept CCC = true; +CCC<> auto abc(); +)cpp"; + Verifier.expectRange(2, 1, 2, 5); + EXPECT_TRUE(Verifier.match(Code4, typeLoc(loc(autoType())), Lang_CXX20)); +} + +class TemplateTypeParmDeclConceptReferenceRangeVerifier + : public RangeVerifier { +protected: + SourceRange getRange(const TemplateTypeParmDecl &Node) override { + if (const TypeConstraint *TC = Node.getTypeConstraint()) { + if (const ConceptReference *ConceptRef = TC->getConceptReference()) { + return ConceptRef->getSourceRange(); + } + } + return SourceRange(); + } +}; + +TEST(LocationVerifier, TemplateTypeParmDeclConceptReference) { + TemplateTypeParmDeclConceptReferenceRangeVerifier Verifier; + + const char *Code = + R"cpp(template concept CCC = true; +template void print(T object); +)cpp"; + // FIXME: expected range should be (2, 11, 2, 13) + Verifier.expectRange(2, 11, 2, 11); + EXPECT_TRUE(Verifier.match(Code, templateTypeParmDecl(), Lang_CXX20)); + + const char *Code2 = + R"cpp(template concept CCC = true; +template T> void print(T object); +)cpp"; + Verifier.expectRange(2, 11, 2, 18); + EXPECT_TRUE(Verifier.match(Code2, templateTypeParmDecl(), Lang_CXX20)); + + const char *Code3 = + R"cpp(namespace X { + template concept CCC = true; +} +template T> void print(T object); +)cpp"; + Verifier.expectRange(4, 11, 4, 21); + EXPECT_TRUE(Verifier.match(Code3, templateTypeParmDecl(), Lang_CXX20)); +} + +class ConceptSpecializationExprConceptReferenceRangeVerifier + : public RangeVerifier { +protected: + SourceRange getRange(const VarTemplateDecl &Node) override { + assert(Node.hasAssociatedConstraints()); + SmallVector ACs; + Node.getAssociatedConstraints(ACs); + for (const Expr *Constraint : ACs) { + if (const ConceptSpecializationExpr *CSConstraint = + dyn_cast(Constraint)) { + return CSConstraint->getConceptReference()->getSourceRange(); + } + } + return SourceRange(); + } +}; + +const internal::VariadicDynCastAllOfMatcher + varTemplateDecl; + +TEST(LocationVerifier, ConceptSpecializationExprConceptReference) { + ConceptSpecializationExprConceptReferenceRangeVerifier Verifier; + + const char *Code = + R"cpp(template concept CCC = true; +template requires CCC int z = X; +)cpp"; + Verifier.expectRange(2, 27, 2, 32); + EXPECT_TRUE(Verifier.match(Code, varTemplateDecl(hasName("z")), Lang_CXX20)); + + const char *Code2 = + R"cpp(namespace NS { +template concept CCC = true; +} +template requires NS::CCC int z = X; +)cpp"; + Verifier.expectRange(4, 27, 4, 36); + EXPECT_TRUE(Verifier.match(Code2, varTemplateDecl(hasName("z")), Lang_CXX20)); +} + } // end namespace diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/Concept.cpp @@ -29,12 +29,22 @@ ++ConceptRequirementsTraversed; return ExpectedLocationVisitor::TraverseConceptRequirement(R); } + bool TraverseConceptReference(ConceptReference *CR) { + ++ConceptReferencesTraversed; + return ExpectedLocationVisitor::TraverseConceptReference(CR); + } + bool VisitConceptReference(ConceptReference *CR) { + ++ConceptReferencesVisited; + return true; + } bool shouldVisitImplicitCode() { return ShouldVisitImplicitCode; } int ConceptSpecializationExprsVisited = 0; int TypeConstraintsTraversed = 0; int ConceptRequirementsTraversed = 0; + int ConceptReferencesTraversed = 0; + int ConceptReferencesVisited = 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.ConceptReferencesTraversed); + EXPECT_EQ(1, Visitor.ConceptReferencesVisited); Visitor = {}; // Don't visit implicit code now. EXPECT_TRUE(Visitor.runOver("template 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.ConceptReferencesTraversed); + EXPECT_EQ(1, Visitor.ConceptReferencesVisited); Visitor = {}; EXPECT_TRUE(Visitor.runOver("template concept A = true;\n" @@ -70,6 +84,8 @@ "};", ConceptVisitor::Lang_CXX2a)); EXPECT_EQ(3, Visitor.ConceptRequirementsTraversed); + EXPECT_EQ(1, Visitor.ConceptReferencesTraversed); + EXPECT_EQ(1, Visitor.ConceptReferencesVisited); } struct VisitDeclOnlyOnce : ExpectedLocationVisitor { @@ -86,6 +102,10 @@ ++AutoTypeLocVisited; return true; } + bool VisitConceptReference(ConceptReference *) { + ++ConceptReferencesVisited; + 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 ConceptReferencesVisited = 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.ConceptReferencesVisited); } } // end anonymous namespace