From 47b79ce997d63c739dfb17665019a10b1c7b7670 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Sun, 20 Jul 2025 14:53:30 -0300 Subject: [PATCH] [PATCH 6/7] [clang] improve NestedNameSpecifier --- .../ChangeNamespace.cpp | 53 +- .../ClangTidyDiagnosticConsumer.cpp | 3 +- .../ForwardingReferenceOverloadCheck.cpp | 18 +- .../bugprone/MoveForwardingReferenceCheck.cpp | 17 +- .../misc/RedundantExpressionCheck.cpp | 8 - .../clang-tidy/misc/UnusedAliasDeclsCheck.cpp | 10 +- .../clang-tidy/modernize/TypeTraitsCheck.cpp | 29 +- .../modernize/UseTrailingReturnTypeCheck.cpp | 93 ++- .../StaticAccessedThroughInstanceCheck.cpp | 26 +- .../utils/RenamerClangTidyCheck.cpp | 5 +- clang-tools-extra/clangd/AST.cpp | 83 ++- clang-tools-extra/clangd/CodeComplete.cpp | 16 +- clang-tools-extra/clangd/DumpAST.cpp | 33 +- clang-tools-extra/clangd/FindTarget.cpp | 85 ++- clang-tools-extra/clangd/IncludeFixer.cpp | 50 +- clang-tools-extra/clangd/Selection.cpp | 2 +- .../clangd/SemanticHighlighting.cpp | 15 - .../clangd/refactor/tweaks/AddUsing.cpp | 121 ++-- .../refactor/tweaks/ExtractFunction.cpp | 2 +- .../clangd/unittests/FindTargetTests.cpp | 4 +- .../clangd/unittests/SelectionTests.cpp | 4 +- .../include-cleaner/lib/WalkAST.cpp | 16 +- clang/include/clang/AST/ASTConcept.h | 9 +- clang/include/clang/AST/ASTContext.h | 38 +- clang/include/clang/AST/ASTImporter.h | 2 +- clang/include/clang/AST/ASTNodeTraverser.h | 12 +- clang/include/clang/AST/ASTTypeTraits.h | 13 +- clang/include/clang/AST/AbstractBasicReader.h | 37 +- clang/include/clang/AST/AbstractBasicWriter.h | 33 +- clang/include/clang/AST/CanonicalType.h | 2 +- clang/include/clang/AST/Decl.h | 10 +- clang/include/clang/AST/DeclCXX.h | 16 +- clang/include/clang/AST/DependenceFlags.h | 2 +- .../clang/AST/DynamicRecursiveASTVisitor.h | 3 +- clang/include/clang/AST/Expr.h | 4 +- clang/include/clang/AST/ExprCXX.h | 8 +- clang/include/clang/AST/NestedNameSpecifier.h | 665 ++++++------------ .../clang/AST/NestedNameSpecifierBase.h | 586 +++++++++++++++ clang/include/clang/AST/ODRHash.h | 2 +- clang/include/clang/AST/PropertiesBase.td | 5 +- clang/include/clang/AST/RecursiveASTVisitor.h | 74 +- clang/include/clang/AST/TemplateBase.h | 36 +- clang/include/clang/AST/TemplateName.h | 30 +- clang/include/clang/AST/TextNodeDumper.h | 2 +- clang/include/clang/AST/Type.h | 31 +- clang/include/clang/AST/TypeLoc.h | 19 +- clang/include/clang/ASTMatchers/ASTMatchers.h | 42 +- .../clang/ASTMatchers/ASTMatchersInternal.h | 2 +- .../clang/ExtractAPI/DeclarationFragments.h | 5 +- .../include/clang/Sema/CodeCompleteConsumer.h | 7 +- clang/include/clang/Sema/DeclSpec.h | 12 +- clang/include/clang/Sema/HeuristicResolver.h | 3 +- clang/include/clang/Sema/Sema.h | 13 +- clang/include/clang/Sema/SemaInternal.h | 8 +- clang/include/clang/Sema/TypoCorrection.h | 29 +- .../clang/Serialization/ASTRecordReader.h | 2 +- .../clang/Serialization/ASTRecordWriter.h | 2 +- .../clang/Tooling/Refactoring/Lookup.h | 3 +- .../Refactoring/RecursiveSymbolVisitor.h | 16 +- clang/lib/AST/ASTConcept.cpp | 11 +- clang/lib/AST/ASTContext.cpp | 308 +++----- clang/lib/AST/ASTDiagnostic.cpp | 7 +- clang/lib/AST/ASTImporter.cpp | 98 ++- clang/lib/AST/ASTStructuralEquivalence.cpp | 59 +- clang/lib/AST/ASTTypeTraits.cpp | 36 +- clang/lib/AST/ComputeDependence.cpp | 20 +- clang/lib/AST/Decl.cpp | 19 +- clang/lib/AST/DeclPrinter.cpp | 7 +- clang/lib/AST/DynamicRecursiveASTVisitor.cpp | 21 +- clang/lib/AST/ExprCXX.cpp | 7 +- clang/lib/AST/ExprConcepts.cpp | 4 +- clang/lib/AST/ItaniumMangle.cpp | 141 ++-- clang/lib/AST/JSONNodeDumper.cpp | 4 +- clang/lib/AST/NestedNameSpecifier.cpp | 471 +++---------- clang/lib/AST/ODRHash.cpp | 44 +- clang/lib/AST/OpenMPClause.cpp | 26 +- clang/lib/AST/ParentMapContext.cpp | 6 +- clang/lib/AST/QualTypeNames.cpp | 324 ++++----- clang/lib/AST/StmtPrinter.cpp | 27 +- clang/lib/AST/StmtProfile.cpp | 15 +- clang/lib/AST/TemplateBase.cpp | 30 +- clang/lib/AST/TemplateName.cpp | 56 +- clang/lib/AST/TextNodeDumper.cpp | 30 +- clang/lib/AST/Type.cpp | 35 +- clang/lib/AST/TypeLoc.cpp | 134 +++- clang/lib/ASTMatchers/ASTMatchFinder.cpp | 42 +- clang/lib/CodeGen/CGCXX.cpp | 11 +- clang/lib/CodeGen/CGExprCXX.cpp | 4 +- clang/lib/CodeGen/CodeGenFunction.h | 4 +- clang/lib/ExtractAPI/DeclarationFragments.cpp | 42 +- clang/lib/Index/IndexTypeSourceInfo.cpp | 36 +- clang/lib/Index/USRGeneration.cpp | 4 +- clang/lib/Parse/ParseDeclCXX.cpp | 2 +- clang/lib/Parse/ParseTentative.cpp | 2 +- clang/lib/Sema/AnalysisBasedWarnings.cpp | 11 +- clang/lib/Sema/DeclSpec.cpp | 23 +- clang/lib/Sema/HeuristicResolver.cpp | 37 +- clang/lib/Sema/SemaCXXScopeSpec.cpp | 110 +-- clang/lib/Sema/SemaCodeComplete.cpp | 82 ++- clang/lib/Sema/SemaDecl.cpp | 66 +- clang/lib/Sema/SemaDeclCXX.cpp | 43 +- clang/lib/Sema/SemaExpr.cpp | 18 +- clang/lib/Sema/SemaExprCXX.cpp | 37 +- clang/lib/Sema/SemaLookup.cpp | 169 +++-- clang/lib/Sema/SemaOverload.cpp | 18 +- clang/lib/Sema/SemaTemplate.cpp | 195 +++-- clang/lib/Sema/SemaTemplateDeduction.cpp | 45 +- clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 13 +- clang/lib/Sema/SemaTemplateInstantiate.cpp | 115 +-- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 +- clang/lib/Sema/SemaType.cpp | 19 +- clang/lib/Sema/SemaTypeTraits.cpp | 7 +- clang/lib/Sema/TreeTransform.h | 396 ++++++----- clang/lib/Serialization/ASTReader.cpp | 37 +- clang/lib/Serialization/ASTWriter.cpp | 49 +- clang/lib/Tooling/Refactoring/Lookup.cpp | 12 +- .../Refactoring/Rename/USRLocFinder.cpp | 110 ++- clang/lib/Tooling/Syntax/BuildTree.cpp | 166 +++-- clang/tools/libclang/CIndex.cpp | 132 ++-- clang/tools/libclang/CursorVisitor.h | 4 +- .../ASTMatchers/ASTMatchersTraversalTest.cpp | 74 +- .../unittests/Sema/HeuristicResolverTest.cpp | 15 +- .../NestedNameSpecifiers.cpp | 17 +- clang/unittests/Tooling/RefactoringTest.cpp | 9 +- 124 files changed, 3382 insertions(+), 3225 deletions(-) create mode 100644 clang/include/clang/AST/NestedNameSpecifierBase.h diff --git a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp index 3e367ab1a5558..471ca45fb5a53 100644 --- a/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp +++ b/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp @@ -31,24 +31,9 @@ llvm::SmallVector splitSymbolName(llvm::StringRef Name) { return Splitted; } -SourceLocation startLocationForType(TypeLoc TLoc) { - // For elaborated types (e.g. `struct a::A`) we want the portion after the - // `struct` but including the namespace qualifier, `a::`. - if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) { - NestedNameSpecifierLoc NestedNameSpecifier = - TLoc.castAs().getQualifierLoc(); - if (NestedNameSpecifier.getNestedNameSpecifier()) - return NestedNameSpecifier.getBeginLoc(); - TLoc = TLoc.getNextTypeLoc(); - } - return TLoc.getBeginLoc(); -} - SourceLocation endLocationForType(TypeLoc TLoc) { - // Dig past any namespace or keyword qualifications. - while (TLoc.getTypeLocClass() == TypeLoc::Elaborated || - TLoc.getTypeLocClass() == TypeLoc::Qualified) - TLoc = TLoc.getNextTypeLoc(); + if (auto QTL = TLoc.getAs()) + TLoc = QTL.getUnqualifiedLoc(); // The location for template specializations (e.g. Foo) includes the // templated types in its location range. We want to restrict this to just @@ -550,8 +535,8 @@ void ChangeNamespaceTool::run( Result.Nodes.getNodeAs( "nested_specifier_loc")) { SourceLocation Start = Specifier->getBeginLoc(); - SourceLocation End = endLocationForType(Specifier->getTypeLoc()); - fixTypeLoc(Result, Start, End, Specifier->getTypeLoc()); + SourceLocation End = endLocationForType(Specifier->castAsTypeLoc()); + fixTypeLoc(Result, Start, End, Specifier->castAsTypeLoc()); } else if (const auto *BaseInitializer = Result.Nodes.getNodeAs( "base_initializer")) { @@ -562,19 +547,16 @@ void ChangeNamespaceTool::run( // filtered by matchers in some cases, e.g. the type is templated. We should // handle the record type qualifier instead. TypeLoc Loc = *TLoc; - while (Loc.getTypeLocClass() == TypeLoc::Qualified) - Loc = Loc.getNextTypeLoc(); - if (Loc.getTypeLocClass() == TypeLoc::Elaborated) { - NestedNameSpecifierLoc NestedNameSpecifier = - Loc.castAs().getQualifierLoc(); - // FIXME: avoid changing injected class names. - if (auto *NNS = NestedNameSpecifier.getNestedNameSpecifier()) { - const Type *SpecifierType = NNS->getAsType(); - if (SpecifierType && SpecifierType->isRecordType()) - return; - } - } - fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc); + if (auto QTL = Loc.getAs()) + Loc = QTL.getUnqualifiedLoc(); + // FIXME: avoid changing injected class names. + if (NestedNameSpecifier NestedNameSpecifier = + Loc.getPrefix().getNestedNameSpecifier(); + NestedNameSpecifier.getKind() == NestedNameSpecifier::Kind::Type && + NestedNameSpecifier.getAsType()->isRecordType()) + return; + fixTypeLoc(Result, Loc.getNonElaboratedBeginLoc(), endLocationForType(Loc), + Loc); } else if (const auto *VarRef = Result.Nodes.getNodeAs("var_ref")) { const auto *Var = Result.Nodes.getNodeAs("var_decl"); @@ -588,10 +570,9 @@ void ChangeNamespaceTool::run( } else if (const auto *EnumConstRef = Result.Nodes.getNodeAs("enum_const_ref")) { // Do not rename the reference if it is already scoped by the EnumDecl name. - if (EnumConstRef->hasQualifier() && - EnumConstRef->getQualifier()->getKind() == - NestedNameSpecifier::SpecifierKind::TypeSpec && - EnumConstRef->getQualifier()->getAsType()->isEnumeralType()) + if (NestedNameSpecifier Qualifier = EnumConstRef->getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type && + Qualifier.getAsType()->isEnumeralType()) return; const auto *EnumConstDecl = Result.Nodes.getNodeAs("enum_const_decl"); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index f9d75978d0ea8..fac6e0418d163 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -533,7 +533,8 @@ void ClangTidyDiagnosticConsumer::forwardDiagnostic(const Diagnostic &Info) { Builder << reinterpret_cast(Info.getRawArg(Index)); break; case clang::DiagnosticsEngine::ak_nestednamespec: - Builder << reinterpret_cast(Info.getRawArg(Index)); + Builder << NestedNameSpecifier::getFromVoidPointer( + reinterpret_cast(Info.getRawArg(Index))); break; case clang::DiagnosticsEngine::ak_declcontext: Builder << reinterpret_cast(Info.getRawArg(Index)); diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp index 00e8f7e514368..10b747e17e2ad 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp @@ -33,21 +33,17 @@ AST_MATCHER(QualType, isEnableIf) { BaseType = BaseType->getPointeeType().getTypePtr(); } // Case: type parameter dependent (enable_if>). - if (const auto *Dependent = BaseType->getAs()) { - BaseType = Dependent->getQualifier()->getAsType(); - } + if (const auto *Dependent = BaseType->getAs()) + BaseType = Dependent->getQualifier().getAsType(); if (!BaseType) return false; if (CheckTemplate(BaseType->getAs())) return true; // Case: enable_if_t< >. - if (const auto *Elaborated = BaseType->getAs()) { - if (const auto *Q = Elaborated->getQualifier()) - if (const auto *Qualifier = Q->getAsType()) { - if (CheckTemplate(Qualifier->getAs())) { - return true; // Case: enable_if< >::type. - } - } - } + if (const auto *TT = BaseType->getAs()) + if (NestedNameSpecifier Q = TT->getQualifier(); + Q.getKind() == NestedNameSpecifier::Kind::Type) + if (CheckTemplate(Q.getAsType()->getAs())) + return true; // Case: enable_if< >::type. return false; } AST_MATCHER_P(TemplateTypeParmDecl, hasDefaultArgument, diff --git a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp index bfa2ab51a6d03..5dc988d6662df 100644 --- a/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/MoveForwardingReferenceCheck.cpp @@ -39,24 +39,31 @@ static void replaceMoveWithForward(const UnresolvedLookupExpr *Callee, // std::move(). This will hopefully prevent erroneous replacements if the // code does unusual things (e.g. create an alias for std::move() in // another namespace). - NestedNameSpecifier *NNS = Callee->getQualifier(); - if (!NNS) { + NestedNameSpecifier NNS = Callee->getQualifier(); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: // Called as "move" (i.e. presumably the code had a "using std::move;"). // We still conservatively put a "std::" in front of the forward because // we don't know whether the code also had a "using std::forward;". Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); - } else if (const NamespaceBaseDecl *Namespace = NNS->getAsNamespace()) { + break; + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); if (Namespace->getName() == "std") { - if (!NNS->getPrefix()) { + if (!Prefix) { // Called as "std::move". Diag << FixItHint::CreateReplacement(CallRange, "std::" + ForwardName); - } else if (NNS->getPrefix()->getKind() == NestedNameSpecifier::Global) { + } else if (Prefix.getKind() == NestedNameSpecifier::Kind::Global) { // Called as "::std::move". Diag << FixItHint::CreateReplacement(CallRange, "::std::" + ForwardName); } } + break; + } + default: + return; } } } diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp index 99763bd430f00..107eda2e98f27 100644 --- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp @@ -45,14 +45,6 @@ static bool incrementWithoutOverflow(const APSInt &Value, APSInt &Result) { return Value < Result; } -static bool areEquivalentNameSpecifier(const NestedNameSpecifier *Left, - const NestedNameSpecifier *Right) { - llvm::FoldingSetNodeID LeftID, RightID; - Left->Profile(LeftID); - Right->Profile(RightID); - return LeftID == RightID; -} - static bool areEquivalentExpr(const Expr *Left, const Expr *Right) { if (!Left || !Right) return !Left && !Right; diff --git a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp index 86992cd8a141b..4fa679aa8dd88 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedAliasDeclsCheck.cpp @@ -35,12 +35,12 @@ void UnusedAliasDeclsCheck::check(const MatchFinder::MatchResult &Result) { } if (const auto *NestedName = - Result.Nodes.getNodeAs("nns")) { - if (const auto *AliasDecl = dyn_cast_if_present( - NestedName->getAsNamespace())) { + Result.Nodes.getNodeAs("nns"); + NestedName && + NestedName->getKind() == NestedNameSpecifier::Kind::Namespace) + if (const auto *AliasDecl = dyn_cast( + NestedName->getAsNamespaceAndPrefix().Namespace)) FoundDecls[AliasDecl] = CharSourceRange(); - } - } } void UnusedAliasDeclsCheck::onEndOfTranslationUnit() { diff --git a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp index 76ea3e799aa6d..de2d42d760550 100644 --- a/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/TypeTraitsCheck.cpp @@ -214,14 +214,11 @@ static bool isNamedDeclInStdTraitsSet(const NamedDecl *ND, Set.contains(ND->getName()); } -static bool checkTemplatedDecl(const NestedNameSpecifier *NNS, +static bool checkTemplatedDecl(NestedNameSpecifier NNS, const llvm::StringSet<> &Set) { - if (!NNS) + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) return false; - const Type *NNST = NNS->getAsType(); - if (!NNST) - return false; - const auto *TST = NNST->getAs(); + const auto *TST = NNS.getAsType()->getAs(); if (!TST) return false; if (const TemplateDecl *TD = TST->getTemplateName().getAsTemplateDecl()) { @@ -238,8 +235,8 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) { auto EmitValueWarning = [this, &Result](const NestedNameSpecifierLoc &QualLoc, SourceLocation EndLoc) { SourceLocation TemplateNameEndLoc; - if (auto TSTL = QualLoc.getTypeLoc().getAs(); - !TSTL.isNull()) + if (auto TSTL = + QualLoc.getAsTypeLoc().getAs()) TemplateNameEndLoc = Lexer::getLocForEndOfToken( TSTL.getTemplateNameLoc(), 0, *Result.SourceManager, Result.Context->getLangOpts()); @@ -289,23 +286,21 @@ void TypeTraitsCheck::check(const MatchFinder::MatchResult &Result) { if (!DRE->hasQualifier()) return; if (const auto *CTSD = dyn_cast_if_present( - DRE->getQualifier()->getAsRecordDecl())) { + DRE->getQualifier().getAsRecordDecl())) { if (isNamedDeclInStdTraitsSet(CTSD, ValueTraits)) EmitValueWarning(DRE->getQualifierLoc(), DRE->getEndLoc()); } return; } - if (const auto *ETL = Result.Nodes.getNodeAs(Bind)) { - const NestedNameSpecifierLoc QualLoc = ETL->getQualifierLoc(); - const auto *NNS = QualLoc.getNestedNameSpecifier(); - if (!NNS) - return; + if (const auto *TL = Result.Nodes.getNodeAs(Bind)) { + const NestedNameSpecifierLoc QualLoc = TL->getQualifierLoc(); + NestedNameSpecifier NNS = QualLoc.getNestedNameSpecifier(); if (const auto *CTSD = dyn_cast_if_present( - NNS->getAsRecordDecl())) { + NNS.getAsRecordDecl())) { if (isNamedDeclInStdTraitsSet(CTSD, TypeTraits)) - EmitTypeWarning(ETL->getQualifierLoc(), ETL->getEndLoc(), - ETL->getElaboratedKeywordLoc()); + EmitTypeWarning(TL->getQualifierLoc(), TL->getEndLoc(), + TL->getElaboratedKeywordLoc()); } return; } diff --git a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp index ced4825f79a99..82f64096cbec1 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseTrailingReturnTypeCheck.cpp @@ -64,66 +64,65 @@ struct UnqualNameVisitor : public RecursiveASTVisitor { return false; } - bool TraverseTypeLoc(TypeLoc TL, bool Elaborated = false) { + bool TraverseTypeLoc(TypeLoc TL, bool TraverseQualifier = true) { if (TL.isNull()) return true; - if (!Elaborated) { - switch (TL.getTypeLocClass()) { - case TypeLoc::Record: - if (visitUnqualName( - TL.getAs().getTypePtr()->getDecl()->getName())) - return false; + switch (TL.getTypeLocClass()) { + case TypeLoc::InjectedClassName: + case TypeLoc::Record: + case TypeLoc::Enum: { + auto TTL = TL.getAs(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - case TypeLoc::Enum: - if (visitUnqualName( - TL.getAs().getTypePtr()->getDecl()->getName())) - return false; - break; - case TypeLoc::TemplateSpecialization: - if (visitUnqualName(TL.getAs() - .getTypePtr() - ->getTemplateName() - .getAsTemplateDecl() - ->getName())) - return false; - break; - case TypeLoc::Typedef: - if (visitUnqualName( - TL.getAs().getTypePtr()->getDecl()->getName())) - return false; + if (visitUnqualName(T->getOriginalDecl()->getName())) + return false; + break; + } + case TypeLoc::TemplateSpecialization: { + auto TTL = TL.getAs(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - case TypeLoc::Using: - if (visitUnqualName(TL.getAs() - .getTypePtr() - ->getFoundDecl() - ->getName())) - return false; + if (visitUnqualName(T->getTemplateName().getAsTemplateDecl()->getName())) + return false; + break; + } + case TypeLoc::Typedef: { + auto TTL = TL.getAs(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - default: + if (visitUnqualName(T->getDecl()->getName())) + return false; + break; + } + case TypeLoc::Using: { + auto TTL = TL.getAs(); + const auto *T = TTL.getTypePtr(); + if (T->getKeyword() != ElaboratedTypeKeyword::None || + TTL.getQualifierLoc()) break; - } + if (visitUnqualName(T->getDecl()->getName())) + return false; + break; + } + default: + break; } - return RecursiveASTVisitor::TraverseTypeLoc(TL); + return RecursiveASTVisitor::TraverseTypeLoc( + TL, TraverseQualifier); } // Replace the base method in order to call our own // TraverseTypeLoc(). - bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { - return TraverseTypeLoc(TL.getUnqualifiedLoc()); - } - - // Replace the base version to inform TraverseTypeLoc that the type is - // elaborated. - bool TraverseElaboratedTypeLoc(ElaboratedTypeLoc TL) { - if (TL.getQualifierLoc() && - !TraverseNestedNameSpecifierLoc(TL.getQualifierLoc())) - return false; - const auto *T = TL.getTypePtr(); - return TraverseTypeLoc(TL.getNamedTypeLoc(), - T->getKeyword() != ElaboratedTypeKeyword::None || - T->getQualifier()); + bool TraverseQualifiedTypeLoc(QualifiedTypeLoc TL, bool TraverseQualifier) { + return TraverseTypeLoc(TL.getUnqualifiedLoc(), TraverseQualifier); } bool VisitDeclRefExpr(DeclRefExpr *S) { diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp index fffb136e5a332..a7b3c4a1f7cf9 100644 --- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp @@ -19,19 +19,25 @@ namespace { AST_MATCHER(CXXMethodDecl, isStatic) { return Node.isStatic(); } } // namespace -static unsigned getNameSpecifierNestingLevel(const QualType &QType) { - if (const auto *ElType = QType->getAs()) { - if (const NestedNameSpecifier *NestedSpecifiers = ElType->getQualifier()) { - unsigned NameSpecifierNestingLevel = 1; - do { - NameSpecifierNestingLevel++; - NestedSpecifiers = NestedSpecifiers->getPrefix(); - } while (NestedSpecifiers); - +static unsigned getNameSpecifierNestingLevel(QualType QType) { + unsigned NameSpecifierNestingLevel = 1; + for (NestedNameSpecifier Qualifier = QType->getPrefix(); /**/; + ++NameSpecifierNestingLevel) { + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: return NameSpecifierNestingLevel; + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + return NameSpecifierNestingLevel + 1; + case NestedNameSpecifier::Kind::Namespace: + Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix; + continue; + case NestedNameSpecifier::Kind::Type: + Qualifier = Qualifier.getAsType()->getPrefix(); + continue; } + llvm_unreachable("unhandled nested name specifier kind"); } - return 0; } void StaticAccessedThroughInstanceCheck::storeOptions( diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index 1ef1da71cbce1..3cf6e57ca4df5 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -281,9 +281,10 @@ class RenamerClangTidyVisitor } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Loc) { - if (const NestedNameSpecifier *Spec = Loc.getNestedNameSpecifier()) { + if (NestedNameSpecifier Spec = Loc.getNestedNameSpecifier(); + Spec.getKind() == NestedNameSpecifier::Kind::Namespace) { if (const auto *Decl = - dyn_cast_if_present(Spec->getAsNamespace())) + dyn_cast(Spec.getAsNamespaceAndPrefix().Namespace)) Check->addUsage(Decl, Loc.getLocalSourceRange(), SM); } diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 218d3f7359afb..82aee4c84d074 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -102,54 +102,78 @@ getUsingNamespaceDirectives(const DeclContext *DestContext, // ancestor is redundant, therefore we stop at lowest common ancestor. // In addition to that stops early whenever IsVisible returns true. This can be // used to implement support for "using namespace" decls. -std::string -getQualification(ASTContext &Context, const DeclContext *DestContext, - const DeclContext *SourceContext, - llvm::function_ref IsVisible) { - std::vector Parents; - bool ReachedNS = false; +std::string getQualification(ASTContext &Context, + const DeclContext *DestContext, + const DeclContext *SourceContext, + llvm::function_ref IsVisible) { + std::vector Parents; + [[maybe_unused]] bool ReachedNS = false; for (const DeclContext *CurContext = SourceContext; CurContext; CurContext = CurContext->getLookupParent()) { // Stop once we reach a common ancestor. if (CurContext->Encloses(DestContext)) break; - NestedNameSpecifier *NNS = nullptr; + const Decl *CurD; if (auto *TD = llvm::dyn_cast(CurContext)) { // There can't be any more tag parents after hitting a namespace. assert(!ReachedNS); - (void)ReachedNS; - NNS = NestedNameSpecifier::Create(Context, nullptr, TD->getTypeForDecl()); + CurD = TD; } else if (auto *NSD = llvm::dyn_cast(CurContext)) { ReachedNS = true; - NNS = NestedNameSpecifier::Create(Context, nullptr, NSD); // Anonymous and inline namespace names are not spelled while qualifying // a name, so skip those. if (NSD->isAnonymousNamespace() || NSD->isInlineNamespace()) continue; + CurD = NSD; } else { // Other types of contexts cannot be spelled in code, just skip over // them. continue; } // Stop if this namespace is already visible at DestContext. - if (IsVisible(NNS)) + if (IsVisible(CurD)) break; - Parents.push_back(NNS); + Parents.push_back(CurD); + } + + // Go over the declarations in reverse order, since we stored inner-most + // parent first. + NestedNameSpecifier Qualifier = std::nullopt; + bool IsFirst = true; + for (const auto *CurD : llvm::reverse(Parents)) { + if (auto *TD = llvm::dyn_cast(CurD)) { + QualType T; + if (const auto *RD = dyn_cast(TD); + ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) { + ArrayRef Args; + if (const auto *SD = dyn_cast(RD)) + Args = SD->getTemplateArgs().asArray(); + else + Args = CTD->getTemplateParameters()->getInjectedTemplateArgs(Context); + T = Context.getTemplateSpecializationType( + ElaboratedTypeKeyword::None, + Context.getQualifiedTemplateName( + Qualifier, /*TemplateKeyword=*/!IsFirst, TemplateName(CTD)), + Args, /*CanonicalArgs=*/{}, Context.getCanonicalTagType(RD)); + } else { + T = Context.getTagType(ElaboratedTypeKeyword::None, Qualifier, TD, + /*OwnsTag=*/false); + } + Qualifier = NestedNameSpecifier(T.getTypePtr()); + } else { + Qualifier = + NestedNameSpecifier(Context, cast(CurD), Qualifier); + } + IsFirst = false; } + if (!Qualifier) + return ""; - // Go over name-specifiers in reverse order to create necessary qualification, - // since we stored inner-most parent first. std::string Result; llvm::raw_string_ostream OS(Result); - for (const auto *Parent : llvm::reverse(Parents)) { - if (Parent != *Parents.rbegin() && Parent->isDependent() && - Parent->getAsRecordDecl() && - Parent->getAsRecordDecl()->getDescribedClassTemplate()) - OS << "template "; - Parent->print(OS, Context.getPrintingPolicy()); - } + Qualifier.print(OS, Context.getPrintingPolicy()); return OS.str(); } @@ -249,8 +273,7 @@ std::string printName(const ASTContext &Ctx, const NamedDecl &ND) { } // Print nested name qualifier if it was written in the source code. - if (auto *Qualifier = getQualifierLoc(ND).getNestedNameSpecifier()) - Qualifier->print(Out, PP); + getQualifierLoc(ND).getNestedNameSpecifier().print(Out, PP); // Print the name itself. ND.getDeclName().print(Out, PP); // Print template arguments. @@ -665,13 +688,10 @@ std::string getQualification(ASTContext &Context, auto VisibleNamespaceDecls = getUsingNamespaceDirectives(DestContext, InsertionPoint); return getQualification( - Context, DestContext, ND->getDeclContext(), - [&](NestedNameSpecifier *NNS) { - const NamespaceDecl *NS = - dyn_cast_if_present(NNS->getAsNamespace()); - if (!NS) + Context, DestContext, ND->getDeclContext(), [&](const Decl *D) { + if (D->getKind() != Decl::Namespace) return false; - NS = NS->getCanonicalDecl(); + const auto *NS = cast(D)->getCanonicalDecl(); return llvm::any_of(VisibleNamespaceDecls, [NS](const NamespaceDecl *NSD) { return NSD->getCanonicalDecl() == NS; @@ -688,12 +708,11 @@ std::string getQualification(ASTContext &Context, (void)NS; } return getQualification( - Context, DestContext, ND->getDeclContext(), - [&](NestedNameSpecifier *NNS) { + Context, DestContext, ND->getDeclContext(), [&](const Decl *D) { return llvm::any_of(VisibleNamespaces, [&](llvm::StringRef Namespace) { std::string NS; llvm::raw_string_ostream OS(NS); - NNS->print(OS, Context.getPrintingPolicy()); + D->print(OS, Context.getPrintingPolicy()); return OS.str() == Namespace; }); }); diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 184c3c962f063..69fca8de6b402 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -1462,19 +1462,15 @@ bool allowIndex(CodeCompletionContext &CC) { auto Scope = CC.getCXXScopeSpecifier(); if (!Scope) return true; - NestedNameSpecifier *NameSpec = (*Scope)->getScopeRep(); - if (!NameSpec) - return true; // We only query the index when qualifier is a namespace. // If it's a class, we rely solely on sema completions. - switch (NameSpec->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Namespace: + switch ((*Scope)->getScopeRep().getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Namespace: return true; - case NestedNameSpecifier::Super: - case NestedNameSpecifier::TypeSpec: - // Unresolved inside a template. - case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Kind::MicrosoftSuper: + case NestedNameSpecifier::Kind::Type: return false; } llvm_unreachable("invalid NestedNameSpecifier kind"); diff --git a/clang-tools-extra/clangd/DumpAST.cpp b/clang-tools-extra/clangd/DumpAST.cpp index 14e14a5e9f544..9a8d41d870929 100644 --- a/clang-tools-extra/clangd/DumpAST.cpp +++ b/clang-tools-extra/clangd/DumpAST.cpp @@ -147,17 +147,17 @@ class DumpVisitor : public RecursiveASTVisitor { } llvm_unreachable("Unhandled ArgKind enum"); } - std::string getKind(const NestedNameSpecifierLoc &NNSL) { - assert(NNSL.getNestedNameSpecifier()); - switch (NNSL.getNestedNameSpecifier()->getKind()) { + std::string getKind(NestedNameSpecifierLoc NNSL) { + switch (NNSL.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); #define NNS_KIND(X) \ - case NestedNameSpecifier::X: \ + case NestedNameSpecifier::Kind::X: \ return #X - NNS_KIND(Identifier); NNS_KIND(Namespace); - NNS_KIND(TypeSpec); + NNS_KIND(Type); NNS_KIND(Global); - NNS_KIND(Super); + NNS_KIND(MicrosoftSuper); #undef NNS_KIND } llvm_unreachable("Unhandled SpecifierKind enum"); @@ -273,16 +273,11 @@ class DumpVisitor : public RecursiveASTVisitor { return getDetail(TT->getDecl()); return ""; } - std::string getDetail(const NestedNameSpecifierLoc &NNSL) { - const auto &NNS = *NNSL.getNestedNameSpecifier(); - switch (NNS.getKind()) { - case NestedNameSpecifier::Identifier: - return NNS.getAsIdentifier()->getName().str() + "::"; - case NestedNameSpecifier::Namespace: - return NNS.getAsNamespace()->getNameAsString() + "::"; - default: + std::string getDetail(NestedNameSpecifierLoc NNSL) { + NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier(); + if (NNS.getKind() != NestedNameSpecifier::Kind::Namespace) return ""; - } + return NNS.getAsNamespaceAndPrefix().Namespace->getNameAsString() + "::"; } std::string getDetail(const CXXCtorInitializer *CCI) { if (FieldDecl *FD = CCI->getAnyMember()) @@ -391,11 +386,11 @@ class DumpVisitor : public RecursiveASTVisitor { // This means we'd never see 'int' in 'const int'! Work around that here. // (The reason for the behavior is to avoid traversing the nested Type twice, // but we ignore TraverseType anyway). - bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL) { + bool TraverseQualifiedTypeLoc(QualifiedTypeLoc QTL, bool TraverseQualifier) { return TraverseTypeLoc(QTL.getUnqualifiedLoc()); } // Uninteresting parts of the AST that don't have locations within them. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; } + bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; } bool TraverseType(QualType) { return true; } // OpaqueValueExpr blocks traversal, we must explicitly traverse it. @@ -422,7 +417,7 @@ ASTNode dumpAST(const DynTypedNode &N, const syntax::TokenBuffer &Tokens, V.TraverseNestedNameSpecifierLoc( *const_cast(NNSL)); else if (const auto *NNS = N.get()) - V.TraverseNestedNameSpecifier(const_cast(NNS)); + V.TraverseNestedNameSpecifier(*NNS); else if (const auto *TL = N.get()) V.TraverseTypeLoc(*const_cast(TL)); else if (const auto *QT = N.get()) diff --git a/clang-tools-extra/clangd/FindTarget.cpp b/clang-tools-extra/clangd/FindTarget.cpp index a5ab40e4221f1..32018d1bf3a84 100644 --- a/clang-tools-extra/clangd/FindTarget.cpp +++ b/clang-tools-extra/clangd/FindTarget.cpp @@ -475,30 +475,27 @@ struct TargetFinder { Visitor(*this, Flags).Visit(T.getTypePtr()); } - void add(const NestedNameSpecifier *NNS, RelSet Flags) { + void add(NestedNameSpecifier NNS, RelSet Flags) { if (!NNS) return; - debug(*NNS, Flags); - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - add(NNS->getAsNamespace(), Flags); + debug(NNS, Flags); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: + add(NNS.getAsNamespaceAndPrefix().Namespace, Flags); return; - case NestedNameSpecifier::Identifier: - if (Resolver) { - add(Resolver->resolveNestedNameSpecifierToType(NNS), Flags); - } + case NestedNameSpecifier::Kind::Type: + add(QualType(NNS.getAsType(), 0), Flags); return; - case NestedNameSpecifier::TypeSpec: - add(QualType(NNS->getAsType(), 0), Flags); - return; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // This should be TUDecl, but we can't get a pointer to it! return; - case NestedNameSpecifier::Super: - add(NNS->getAsRecordDecl(), Flags); + case NestedNameSpecifier::Kind::MicrosoftSuper: + add(NNS.getAsMicrosoftSuper(), Flags); return; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - llvm_unreachable("unhandled NestedNameSpecifier::SpecifierKind"); + llvm_unreachable("unhandled NestedNameSpecifier::Kind"); } void add(const CXXCtorInitializer *CCI, RelSet Flags) { @@ -547,7 +544,7 @@ allTargetDecls(const DynTypedNode &N, const HeuristicResolver *Resolver) { else if (const NestedNameSpecifierLoc *NNSL = N.get()) Finder.add(NNSL->getNestedNameSpecifier(), Flags); else if (const NestedNameSpecifier *NNS = N.get()) - Finder.add(NNS, Flags); + Finder.add(*NNS, Flags); else if (const TypeLoc *TL = N.get()) Finder.add(TL->getType(), Flags); else if (const QualType *QT = N.get()) @@ -853,29 +850,22 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { const HeuristicResolver *Resolver; llvm::SmallVector Refs; - void VisitElaboratedTypeLoc(ElaboratedTypeLoc L) { - // We only know about qualifier, rest if filled by inner locations. - size_t InitialSize = Refs.size(); - Visit(L.getNamedTypeLoc().getUnqualifiedLoc()); - size_t NewSize = Refs.size(); - // Add qualifier for the newly-added refs. - for (unsigned I = InitialSize; I < NewSize; ++I) { - ReferenceLoc *Ref = &Refs[I]; - // Fill in the qualifier. - assert(!Ref->Qualifier.hasQualifier() && "qualifier already set"); - Ref->Qualifier = L.getQualifierLoc(); - } + void VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc L) { + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), + L.getLocalSourceRange().getBegin(), + /*IsDecl=*/false, + {L.getDecl()}}); } void VisitUsingTypeLoc(UsingTypeLoc L) { - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), L.getLocalSourceRange().getBegin(), /*IsDecl=*/false, - {L.getFoundDecl()}}); + {L.getDecl()}}); } void VisitTagTypeLoc(TagTypeLoc L) { - Refs.push_back(ReferenceLoc{NestedNameSpecifierLoc(), + Refs.push_back(ReferenceLoc{L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false, {L.getOriginalDecl()}}); @@ -898,14 +888,14 @@ refInTypeLoc(TypeLoc L, const HeuristicResolver *Resolver) { // 2. 'vector' with mask 'Underlying'. // we want to return only #1 in this case. Refs.push_back(ReferenceLoc{ - NestedNameSpecifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false, + L.getQualifierLoc(), L.getTemplateNameLoc(), /*IsDecl=*/false, explicitReferenceTargets(DynTypedNode::create(L.getType()), DeclRelation::Alias, Resolver)}); } void VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc L) { Refs.push_back(ReferenceLoc{ - NestedNameSpecifierLoc(), L.getNameLoc(), /*IsDecl=*/false, + L.getQualifierLoc(), L.getNameLoc(), /*IsDecl=*/false, explicitReferenceTargets(DynTypedNode::create(L.getType()), DeclRelation::Alias, Resolver)}); } @@ -1025,7 +1015,7 @@ class ExplicitReferenceCollector return true; visitNode(DynTypedNode::create(L)); // Inner type is missing information about its qualifier, skip it. - if (auto TL = L.getTypeLoc()) + if (auto TL = L.getAsTypeLoc()) TypeLocsToSkip.insert(TL.getBeginLoc()); return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(L); } @@ -1066,12 +1056,21 @@ class ExplicitReferenceCollector if (auto *S = N.get()) return refInStmt(S, Resolver); if (auto *NNSL = N.get()) { - // (!) 'DeclRelation::Alias' ensures we do not loose namespace aliases. - return {ReferenceLoc{ - NNSL->getPrefix(), NNSL->getLocalBeginLoc(), false, - explicitReferenceTargets( - DynTypedNode::create(*NNSL->getNestedNameSpecifier()), - DeclRelation::Alias, Resolver)}}; + // (!) 'DeclRelation::Alias' ensures we do not lose namespace aliases. + NestedNameSpecifierLoc Qualifier; + SourceLocation NameLoc; + if (auto TL = NNSL->getAsTypeLoc()) { + Qualifier = TL.getPrefix(); + NameLoc = TL.getNonPrefixBeginLoc(); + } else { + Qualifier = NNSL->getAsNamespaceAndPrefix().Prefix; + NameLoc = NNSL->getLocalBeginLoc(); + } + return { + ReferenceLoc{Qualifier, NameLoc, false, + explicitReferenceTargets( + DynTypedNode::create(NNSL->getNestedNameSpecifier()), + DeclRelation::Alias, Resolver)}}; } if (const TypeLoc *TL = N.get()) return refInTypeLoc(*TL, Resolver); @@ -1184,8 +1183,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, ReferenceLoc R) { OS << "}"; if (R.Qualifier) { OS << ", qualifier = '"; - R.Qualifier.getNestedNameSpecifier()->print(OS, - PrintingPolicy(LangOptions())); + R.Qualifier.getNestedNameSpecifier().print(OS, + PrintingPolicy(LangOptions())); OS << "'"; } if (R.IsDecl) diff --git a/clang-tools-extra/clangd/IncludeFixer.cpp b/clang-tools-extra/clangd/IncludeFixer.cpp index cc1125e705674..c27d960cd963b 100644 --- a/clang-tools-extra/clangd/IncludeFixer.cpp +++ b/clang-tools-extra/clangd/IncludeFixer.cpp @@ -400,35 +400,35 @@ std::optional extractUnresolvedNameCheaply( CheapUnresolvedName Result; Result.Name = Unresolved.getAsString(); if (SS && SS->isNotEmpty()) { // "::" or "ns::" - if (auto *Nested = SS->getScopeRep()) { - if (Nested->getKind() == NestedNameSpecifier::Global) { - Result.ResolvedScope = ""; - } else if (const NamespaceBaseDecl *NSB = Nested->getAsNamespace()) { - if (const auto *NS = dyn_cast(NSB)) { - std::string SpecifiedNS = printNamespaceScope(*NS); - std::optional Spelling = getSpelledSpecifier(*SS, SM); - - // Check the specifier spelled in the source. - // If the resolved scope doesn't end with the spelled scope, the - // resolved scope may come from a sema typo correction. For example, - // sema assumes that "clangd::" is a typo of "clang::" and uses - // "clang::" as the specified scope in: - // namespace clang { clangd::X; } - // In this case, we use the "typo" specifier as extra scope instead - // of using the scope assumed by sema. - if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) { - Result.ResolvedScope = std::move(SpecifiedNS); - } else { - Result.UnresolvedScope = std::move(*Spelling); - } + NestedNameSpecifier Nested = SS->getScopeRep(); + if (Nested.getKind() == NestedNameSpecifier::Kind::Global) { + Result.ResolvedScope = ""; + } else if (Nested.getKind() == NestedNameSpecifier::Kind::Namespace) { + const NamespaceBaseDecl *NSB = Nested.getAsNamespaceAndPrefix().Namespace; + if (const auto *NS = dyn_cast(NSB)) { + std::string SpecifiedNS = printNamespaceScope(*NS); + std::optional Spelling = getSpelledSpecifier(*SS, SM); + + // Check the specifier spelled in the source. + // If the resolved scope doesn't end with the spelled scope, the + // resolved scope may come from a sema typo correction. For example, + // sema assumes that "clangd::" is a typo of "clang::" and uses + // "clang::" as the specified scope in: + // namespace clang { clangd::X; } + // In this case, we use the "typo" specifier as extra scope instead + // of using the scope assumed by sema. + if (!Spelling || llvm::StringRef(SpecifiedNS).ends_with(*Spelling)) { + Result.ResolvedScope = std::move(SpecifiedNS); } else { - Result.ResolvedScope = printNamespaceScope(*cast(NSB)->getNamespace()); + Result.UnresolvedScope = std::move(*Spelling); } } else { - // We don't fix symbols in scopes that are not top-level e.g. class - // members, as we don't collect includes for them. - return std::nullopt; + Result.ResolvedScope = printNamespaceScope(*cast(NSB)->getNamespace()); } + } else { + // We don't fix symbols in scopes that are not top-level e.g. class + // members, as we don't collect includes for them. + return std::nullopt; } } diff --git a/clang-tools-extra/clangd/Selection.cpp b/clang-tools-extra/clangd/Selection.cpp index a6e15fcee6bd2..06165dfbbcdd2 100644 --- a/clang-tools-extra/clangd/Selection.cpp +++ b/clang-tools-extra/clangd/Selection.cpp @@ -701,7 +701,7 @@ class SelectionVisitor : public RecursiveASTVisitor { return traverseNode(&PL, [&] { return Base::TraverseObjCProtocolLoc(PL); }); } // Uninteresting parts of the AST that don't have locations within them. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *) { return true; } + bool TraverseNestedNameSpecifier(NestedNameSpecifier) { return true; } bool TraverseType(QualType) { return true; } // The DeclStmt for the loop variable claims to cover the whole range diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index e6d5cf7053694..2b151b1274428 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -1127,21 +1127,6 @@ class CollectExtraHighlightings return RecursiveASTVisitor::TraverseTemplateArgumentLoc(L); } - // findExplicitReferences will walk nested-name-specifiers and - // find anything that can be resolved to a Decl. However, non-leaf - // components of nested-name-specifiers which are dependent names - // (kind "Identifier") cannot be resolved to a decl, so we visit - // them here. - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc Q) { - if (NestedNameSpecifier *NNS = Q.getNestedNameSpecifier()) { - if (NNS->getKind() == NestedNameSpecifier::Identifier) - H.addToken(Q.getLocalBeginLoc(), HighlightingKind::Type) - .addModifier(HighlightingModifier::DependentName) - .addModifier(HighlightingModifier::ClassScope); - } - return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(Q); - } - private: HighlightingsBuilder &H; }; diff --git a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp index 67fc451a6a1a1..f65c74fdbc9ee 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/AddUsing.cpp @@ -115,13 +115,6 @@ class UsingFinder : public RecursiveASTVisitor { const SourceManager &SM; }; -bool isFullyQualified(const NestedNameSpecifier *NNS) { - if (!NNS) - return false; - return NNS->getKind() == NestedNameSpecifier::Global || - isFullyQualified(NNS->getPrefix()); -} - struct InsertionPointData { // Location to insert the "using" statement. If invalid then the statement // should not be inserted at all (it already exists). @@ -167,18 +160,20 @@ findInsertionPoint(const Tweak::Selection &Inputs, for (auto &U : Usings) { // Only "upgrade" to fully qualified is all relevant using decls are fully // qualified. Otherwise trust what the user typed. - if (!isFullyQualified(U->getQualifier())) + if (!U->getQualifier().isFullyQualified()) AlwaysFullyQualify = false; if (SM.isBeforeInTranslationUnit(Inputs.Cursor, U->getUsingLoc())) // "Usings" is sorted, so we're done. break; - if (const auto *Namespace = dyn_cast_if_present( - U->getQualifier()->getAsNamespace())) { + if (NestedNameSpecifier Qualifier = U->getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) { + const auto *Namespace = + U->getQualifier().getAsNamespaceAndPrefix().Namespace; if (Namespace->getCanonicalDecl() == QualifierToRemove.getNestedNameSpecifier() - ->getAsNamespace() - ->getCanonicalDecl() && + .getAsNamespaceAndPrefix() + .Namespace->getCanonicalDecl() && U->getName() == Name) { return InsertionPointData(); } @@ -232,8 +227,9 @@ findInsertionPoint(const Tweak::Selection &Inputs, } bool isNamespaceForbidden(const Tweak::Selection &Inputs, - const NestedNameSpecifier &Namespace) { - const auto *NS = dyn_cast(Namespace.getAsNamespace()); + NestedNameSpecifier Namespace) { + const auto *NS = + dyn_cast(Namespace.getAsNamespaceAndPrefix().Namespace); if (!NS) return true; std::string NamespaceStr = printNamespaceScope(*NS); @@ -247,11 +243,11 @@ bool isNamespaceForbidden(const Tweak::Selection &Inputs, return false; } -std::string getNNSLAsString(NestedNameSpecifierLoc &NNSL, +std::string getNNSLAsString(NestedNameSpecifierLoc NNSL, const PrintingPolicy &Policy) { std::string Out; llvm::raw_string_ostream OutStream(Out); - NNSL.getNestedNameSpecifier()->print(OutStream, Policy); + NNSL.getNestedNameSpecifier().print(OutStream, Policy); return OutStream.str(); } @@ -276,16 +272,15 @@ bool AddUsing::prepare(const Selection &Inputs) { continue; } if (auto *T = Node->ASTNode.get()) { - if (T->getAs()) { + // Find the outermost TypeLoc. + if (Node->Parent->ASTNode.get()) + continue; + if (isa(T->getTypePtr())) break; - } - if (Node->Parent->ASTNode.get() || - Node->Parent->ASTNode.get()) { - // Node is TypeLoc, but it's parent is either TypeLoc or - // NestedNameSpecifier. In both cases, we want to go up, to find - // the outermost TypeLoc. + // Find the outermost TypeLoc. + if (Node->Parent->ASTNode.get()) continue; - } } break; } @@ -307,32 +302,70 @@ bool AddUsing::prepare(const Selection &Inputs) { MustInsertAfterLoc = D->getDecl()->getBeginLoc(); } } else if (auto *T = Node->ASTNode.get()) { - if (auto E = T->getAs()) { - QualifierToRemove = E.getQualifierLoc(); - - SpelledNameRange = E.getSourceRange(); - if (auto T = E.getNamedTypeLoc().getAs()) { - // Remove the template arguments from the name. - SpelledNameRange.setEnd(T.getLAngleLoc().getLocWithOffset(-1)); - } - - if (const auto *ET = E.getTypePtr()) { - if (const auto *TDT = - dyn_cast(ET->getNamedType().getTypePtr())) { - MustInsertAfterLoc = TDT->getDecl()->getBeginLoc(); - } else if (auto *TD = ET->getAsTagDecl()) { - MustInsertAfterLoc = TD->getBeginLoc(); - } - } + switch (T->getTypeLocClass()) { + case TypeLoc::TemplateSpecialization: { + auto TL = T->castAs(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getTemplateNameLoc(); + if (auto *TD = TL.getTypePtr()->getTemplateName().getAsTemplateDecl( + /*IgnoreDeduced=*/true)) + MustInsertAfterLoc = TD->getBeginLoc(); + break; + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: { + auto TL = T->castAs(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getOriginalDecl()->getBeginLoc(); + break; + } + case TypeLoc::Typedef: { + auto TL = T->castAs(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + case TypeLoc::UnresolvedUsing: { + auto TL = T->castAs(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + case TypeLoc::Using: { + auto TL = T->castAs(); + QualifierToRemove = TL.getQualifierLoc(); + if (!QualifierToRemove) + break; + SpelledNameRange = TL.getNameLoc(); + MustInsertAfterLoc = TL.getDecl()->getBeginLoc(); + break; + } + default: + break; } + if (QualifierToRemove) + SpelledNameRange.setBegin(QualifierToRemove.getBeginLoc()); } if (!QualifierToRemove || // FIXME: This only supports removing qualifiers that are made up of just // namespace names. If qualifier contains a type, we could take the // longest namespace prefix and remove that. - !QualifierToRemove.getNestedNameSpecifier()->getAsNamespace() || + QualifierToRemove.getNestedNameSpecifier().getKind() != + NestedNameSpecifier::Kind::Namespace || // Respect user config. - isNamespaceForbidden(Inputs, *QualifierToRemove.getNestedNameSpecifier())) + isNamespaceForbidden(Inputs, QualifierToRemove.getNestedNameSpecifier())) return false; // Macros are difficult. We only want to offer code action when what's spelled // under the cursor is a namespace qualifier. If it's a macro that expands to @@ -384,7 +417,7 @@ Expected AddUsing::apply(const Selection &Inputs) { llvm::raw_string_ostream UsingTextStream(UsingText); UsingTextStream << "using "; if (InsertionPoint->AlwaysFullyQualify && - !isFullyQualified(QualifierToRemove.getNestedNameSpecifier())) + !QualifierToRemove.getNestedNameSpecifier().isFullyQualified()) UsingTextStream << "::"; UsingTextStream << QualifierToSpell << SpelledName << ";" << InsertionPoint->Suffix; diff --git a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp index 3f900ab2aae86..134ae89288300 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ExtractFunction.cpp @@ -362,7 +362,7 @@ struct NewFunction { SourceLocation DefinitionPoint; std::optional ForwardDeclarationPoint; const CXXRecordDecl *EnclosingClass = nullptr; - const NestedNameSpecifier *DefinitionQualifier = nullptr; + NestedNameSpecifier DefinitionQualifier = std::nullopt; const DeclContext *SemanticDC = nullptr; const DeclContext *SyntacticDC = nullptr; const DeclContext *ForwardDeclarationSyntacticDC = nullptr; diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 4d77f9d690ca0..20fd23ed4fcdc 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -992,7 +992,7 @@ TEST_F(TargetDeclTest, DependentTypes) { )cpp"; EXPECT_DECLS("DependentNameTypeLoc", "struct B"); - // Heuristic resolution of dependent type name which doesn't get a TypeLoc + // Heuristic resolution of dependent type name within a NestedNameSpecifierLoc Code = R"cpp( template struct A { struct B { struct C {}; }; }; @@ -1000,7 +1000,7 @@ TEST_F(TargetDeclTest, DependentTypes) { template void foo(typename A::[[B]]::C); )cpp"; - EXPECT_DECLS("NestedNameSpecifierLoc", "struct B"); + EXPECT_DECLS("DependentNameTypeLoc", "struct B"); // Heuristic resolution of dependent type name whose qualifier is also // dependent diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index aaaf758e72236..3df19d8fc174d 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -104,9 +104,9 @@ TEST(SelectionTest, CommonAncestor) { { R"cpp( template - int x = [[T::^U::]]ccc(); + int x = T::[[^U]]::ccc(); )cpp", - "NestedNameSpecifierLoc", + "DependentNameTypeLoc", }, { R"cpp( diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index ff64b0b257572..0cbf9a080a3ce 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -131,16 +131,14 @@ class ASTWalker : public RecursiveASTVisitor { } bool qualifierIsNamespaceOrNone(DeclRefExpr *DRE) { - const auto *Qual = DRE->getQualifier(); - if (!Qual) + NestedNameSpecifier Qual = DRE->getQualifier(); + switch (Qual.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::Global: return true; - switch (Qual->getKind()) { - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - return true; - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::Super: - case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Kind::Type: + case NestedNameSpecifier::Kind::MicrosoftSuper: return false; } llvm_unreachable("Unknown value for NestedNameSpecifierKind"); diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index c8f6330a73bb1..6ab82824458ab 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_AST_ASTCONCEPT_H #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/UnsignedOrNone.h" @@ -175,12 +175,7 @@ class ConceptReference { 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 getBeginLoc() const LLVM_READONLY; SourceLocation getEndLoc() const LLVM_READONLY { return getTemplateArgsAsWritten() && diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a11ee774d466c..d33c50803f033 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -283,11 +283,11 @@ class ASTContext : public RefCountedBase { llvm::to_underlying(PredefinedSugarType::Kind::Last) + 1> PredefinedSugarTypes{}; - /// The set of nested name specifiers. + /// Internal storage for NestedNameSpecifiers. /// /// This set is managed by the NestedNameSpecifier class. - mutable llvm::FoldingSet NestedNameSpecifiers; - mutable NestedNameSpecifier *GlobalNestedNameSpecifier = nullptr; + mutable llvm::FoldingSet + NamespaceAndPrefixStorages; /// A cache mapping from RecordDecls to ASTRecordLayouts. /// @@ -1620,7 +1620,7 @@ class ASTContext : public RefCountedBase { /// Return the uniqued reference to the type for a member pointer to /// the specified type in the specified nested name. - QualType getMemberPointerType(QualType T, NestedNameSpecifier *Qualifier, + QualType getMemberPointerType(QualType T, NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const; /// Return a non-unique reference to the type for a variable array of @@ -1921,7 +1921,7 @@ class ASTContext : public RefCountedBase { const IdentifierInfo *MacroII) const; QualType getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const; QualType getDependentTemplateSpecializationType( @@ -2486,7 +2486,7 @@ class ASTContext : public RefCountedBase { UnresolvedSetIterator End) const; TemplateName getAssumedTemplateName(DeclarationName Name) const; - TemplateName getQualifiedTemplateName(NestedNameSpecifier *NNS, + TemplateName getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const; TemplateName @@ -2928,32 +2928,6 @@ class ASTContext : public RefCountedBase { /// Determine if two types are similar, ignoring only CVR qualifiers. bool hasCvrSimilarType(QualType T1, QualType T2); - /// Retrieves the "canonical" nested name specifier for a - /// given nested name specifier. - /// - /// The canonical nested name specifier is a nested name specifier - /// that uniquely identifies a type or namespace within the type - /// system. For example, given: - /// - /// \code - /// namespace N { - /// struct S { - /// template struct X { typename T* type; }; - /// }; - /// } - /// - /// template struct Y { - /// typename N::S::X::type member; - /// }; - /// \endcode - /// - /// Here, the nested-name-specifier for N::S::X:: will be - /// S::X, since 'S' and 'X' are uniquely defined - /// by declarations in the type system and the canonical type for - /// the template type parameter 'T' is template-param-0-0. - NestedNameSpecifier * - getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const; - /// Retrieves the default calling convention for the current context. /// /// The context's default calling convention may differ from the current diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index c40b92666a2ff..4a0ca45b785a9 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -404,7 +404,7 @@ class TypeSourceInfo; /// /// \returns The equivalent nested-name-specifier in the "to" /// context, or the import error. - llvm::Expected Import(NestedNameSpecifier *FromNNS); + llvm::Expected Import(NestedNameSpecifier FromNNS); /// Import the given nested-name-specifier-loc from the "from" /// context into the "to" context. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 1d846a1f9df35..d9dc8290b0e49 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -394,12 +394,14 @@ class ASTNodeTraverser } void VisitMemberPointerType(const MemberPointerType *T) { // FIXME: Provide a NestedNameSpecifier visitor. - NestedNameSpecifier *Qualifier = T->getQualifier(); - if (NestedNameSpecifier::SpecifierKind K = Qualifier->getKind(); - K == NestedNameSpecifier::TypeSpec) - Visit(Qualifier->getAsType()); + NestedNameSpecifier Qualifier = T->getQualifier(); + if (NestedNameSpecifier::Kind K = Qualifier.getKind(); + K == NestedNameSpecifier::Kind::Type) + Visit(Qualifier.getAsType()); if (T->isSugared()) - Visit(T->getMostRecentCXXRecordDecl()->getTypeForDecl()); + Visit(cast(T->getCanonicalTypeUnqualified()) + ->getQualifier() + .getAsType()); Visit(T->getPointeeType()); } void VisitArrayType(const ArrayType *T) { Visit(T->getElementType()); } diff --git a/clang/include/clang/AST/ASTTypeTraits.h b/clang/include/clang/AST/ASTTypeTraits.h index d63cbf405fba1..6f40705fb7436 100644 --- a/clang/include/clang/AST/ASTTypeTraits.h +++ b/clang/include/clang/AST/ASTTypeTraits.h @@ -336,9 +336,9 @@ class DynTypedNode { NodeKind)) { auto NNSLA = getUnchecked(); auto NNSLB = Other.getUnchecked(); - return std::make_pair(NNSLA.getNestedNameSpecifier(), + return std::make_pair(NNSLA.getNestedNameSpecifier().getAsVoidPointer(), NNSLA.getOpaqueData()) < - std::make_pair(NNSLB.getNestedNameSpecifier(), + std::make_pair(NNSLB.getNestedNameSpecifier().getAsVoidPointer(), NNSLB.getOpaqueData()); } @@ -393,8 +393,9 @@ class DynTypedNode { if (ASTNodeKind::getFromNodeKind().isSame( Val.NodeKind)) { auto NNSL = Val.getUnchecked(); - return llvm::hash_combine(NNSL.getNestedNameSpecifier(), - NNSL.getOpaqueData()); + return llvm::hash_combine( + NNSL.getNestedNameSpecifier().getAsVoidPointer(), + NNSL.getOpaqueData()); } assert(Val.getMemoizationData()); @@ -539,8 +540,8 @@ struct DynTypedNode::BaseConverter< : public DynCastPtrConverter {}; template <> -struct DynTypedNode::BaseConverter< - NestedNameSpecifier, void> : public PtrConverter {}; +struct DynTypedNode::BaseConverter + : public ValueConverter {}; template <> struct DynTypedNode::BaseConverter< diff --git a/clang/include/clang/AST/AbstractBasicReader.h b/clang/include/clang/AST/AbstractBasicReader.h index 8f5fdc9d93c78..26052b8086cf7 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -252,39 +252,34 @@ class DataStreamBasicReader : public BasicReaderBase { return EffectConditionExpr{asImpl().readExprRef()}; } - NestedNameSpecifier *readNestedNameSpecifier() { + NestedNameSpecifier readNestedNameSpecifier() { auto &ctx = getASTContext(); // We build this up iteratively. - NestedNameSpecifier *cur = nullptr; + NestedNameSpecifier cur = std::nullopt; uint32_t depth = asImpl().readUInt32(); for (uint32_t i = 0; i != depth; ++i) { auto kind = asImpl().readNestedNameSpecifierKind(); switch (kind) { - case NestedNameSpecifier::Identifier: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + cur = + NestedNameSpecifier(ctx, asImpl().readNamespaceBaseDeclRef(), cur); continue; - - case NestedNameSpecifier::Namespace: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readNamespaceBaseDeclRef()); + case NestedNameSpecifier::Kind::Type: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readQualType().getTypePtr()); continue; - - case NestedNameSpecifier::TypeSpec: - cur = NestedNameSpecifier::Create(ctx, cur, - asImpl().readQualType().getTypePtr()); + case NestedNameSpecifier::Kind::Global: + assert(!cur); + cur = NestedNameSpecifier::getGlobal(); continue; - - case NestedNameSpecifier::Global: - cur = NestedNameSpecifier::GlobalSpecifier(ctx); - continue; - - case NestedNameSpecifier::Super: - cur = NestedNameSpecifier::SuperSpecifier(ctx, - asImpl().readCXXRecordDeclRef()); + case NestedNameSpecifier::Kind::MicrosoftSuper: + assert(!cur); + cur = NestedNameSpecifier(asImpl().readCXXRecordDeclRef()); continue; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/AbstractBasicWriter.h b/clang/include/clang/AST/AbstractBasicWriter.h index fbbaba5f7327b..d41e655986ef9 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -229,42 +229,43 @@ class DataStreamBasicWriter : public BasicWriterBase { asImpl().writeExprRef(CE.getCondition()); } - void writeNestedNameSpecifier(NestedNameSpecifier *NNS) { + void writeNestedNameSpecifier(NestedNameSpecifier NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. - SmallVector nestedNames; + SmallVector nestedNames; // Push each of the NNS's onto a stack for serialization in reverse order. while (NNS) { nestedNames.push_back(NNS); - NNS = NNS->getPrefix(); + NNS = NNS.getKind() == NestedNameSpecifier::Kind::Namespace + ? NNS.getAsNamespaceAndPrefix().Prefix + : std::nullopt; } asImpl().writeUInt32(nestedNames.size()); while (!nestedNames.empty()) { NNS = nestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind kind = NNS->getKind(); + NestedNameSpecifier::Kind kind = NNS.getKind(); asImpl().writeNestedNameSpecifierKind(kind); switch (kind) { - case NestedNameSpecifier::Identifier: - asImpl().writeIdentifier(NNS->getAsIdentifier()); + case NestedNameSpecifier::Kind::Namespace: + asImpl().writeNamespaceBaseDeclRef( + NNS.getAsNamespaceAndPrefix().Namespace); continue; - - case NestedNameSpecifier::Namespace: - asImpl().writeNamespaceBaseDeclRef(NNS->getAsNamespace()); - continue; - - case NestedNameSpecifier::TypeSpec: - asImpl().writeQualType(QualType(NNS->getAsType(), 0)); + case NestedNameSpecifier::Kind::Type: + asImpl().writeQualType(QualType(NNS.getAsType(), 0)); continue; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // Don't need to write an associated value. continue; - case NestedNameSpecifier::Super: - asImpl().writeDeclRef(NNS->getAsRecordDecl()); + case NestedNameSpecifier::Kind::MicrosoftSuper: + asImpl().writeDeclRef(NNS.getAsMicrosoftSuper()); continue; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("bad nested name specifier kind"); } diff --git a/clang/include/clang/AST/CanonicalType.h b/clang/include/clang/AST/CanonicalType.h index 10dab7fbdfa77..b5a4e94e1330a 100644 --- a/clang/include/clang/AST/CanonicalType.h +++ b/clang/include/clang/AST/CanonicalType.h @@ -453,7 +453,7 @@ template<> struct CanProxyAdaptor : public CanProxyBase { LLVM_CLANG_CANPROXY_TYPE_ACCESSOR(getPointeeType) - LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier *, getQualifier) + LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(NestedNameSpecifier, getQualifier) LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(const CXXRecordDecl *, getMostRecentCXXRecordDecl) }; diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index f95a98d88adb9..400d3686076ae 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -20,7 +20,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/ExternalASTSource.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/Redeclarable.h" #include "clang/AST/Type.h" #include "clang/Basic/AddressSpaces.h" @@ -833,9 +833,9 @@ class DeclaratorDecl : public ValueDecl { /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location @@ -3943,9 +3943,9 @@ class TagDecl : public TypeDecl, /// Retrieve the nested-name-specifier that qualifies the name of this /// declaration, if it was present in the source. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return hasExtInfo() ? getExtInfo()->QualifierLoc.getNestedNameSpecifier() - : nullptr; + : std::nullopt; } /// Retrieve the nested-name-specifier (with source-location diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index d9b222067c41b..1d2ef0f4f2319 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -3136,7 +3136,7 @@ class UsingDirectiveDecl : public NamedDecl { /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3257,7 +3257,7 @@ class NamespaceAliasDecl : public NamespaceBaseDecl, /// Retrieve the nested-name-specifier that qualifies the /// name of the namespace. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3619,7 +3619,7 @@ class UsingDecl : public BaseUsingDecl, public Mergeable { NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3809,13 +3809,11 @@ class UsingEnumDecl : public BaseUsingDecl, public Mergeable { /// The source location of the 'enum' keyword. SourceLocation getEnumLoc() const { return EnumLocation; } void setEnumLoc(SourceLocation L) { EnumLocation = L; } - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } NestedNameSpecifierLoc getQualifierLoc() const { - if (auto ETL = EnumType->getTypeLoc().getAs()) - return ETL.getQualifierLoc(); - return NestedNameSpecifierLoc(); + return getEnumTypeLoc().getPrefix(); } // Returns the "qualifier::Name" part as a TypeLoc. TypeLoc getEnumTypeLoc() const { @@ -3975,7 +3973,7 @@ class UnresolvedUsingValueDecl : public ValueDecl, NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -4065,7 +4063,7 @@ class UnresolvedUsingTypenameDecl NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; } /// Retrieve the nested-name-specifier that qualifies the name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DependenceFlags.h b/clang/include/clang/AST/DependenceFlags.h index bdcaabc143cc4..c4395259f0758 100644 --- a/clang/include/clang/AST/DependenceFlags.h +++ b/clang/include/clang/AST/DependenceFlags.h @@ -293,7 +293,7 @@ inline TypeDependence toSemanticDependence(TypeDependence D) { } inline NestedNameSpecifierDependence -toNestedNameSpecifierDependendence(TypeDependence D) { +toNestedNameSpecifierDependence(TypeDependence D) { return Dependence(D).nestedNameSpecifier(); } diff --git a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h index 0bcd67322c7f6..7b5bdca318348 100644 --- a/clang/include/clang/AST/DynamicRecursiveASTVisitor.h +++ b/clang/include/clang/AST/DynamicRecursiveASTVisitor.h @@ -134,8 +134,7 @@ template class DynamicRecursiveASTVisitorBase { /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - virtual bool - TraverseNestedNameSpecifier(MaybeConst *NNS); + virtual bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 523c0326d47ef..d973e2cb822bd 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -1366,7 +1366,7 @@ class DeclRefExpr final /// If the name was qualified, retrieves the nested-name-specifier /// that precedes the name. Otherwise, returns NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } @@ -3393,7 +3393,7 @@ class MemberExpr final /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return getQualifierLoc().getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index a22c32241ac61..f8fa782f3fb68 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -2780,7 +2780,7 @@ class CXXPseudoDestructorExpr : public Expr { /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name. Otherwise, returns /// null. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3221,7 +3221,7 @@ class OverloadExpr : public Expr { SourceLocation getNameLoc() const { return NameInfo.getLoc(); } /// Fetches the nested-name qualifier, if one was given. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3497,7 +3497,7 @@ class DependentScopeDeclRefExpr final /// Retrieve the nested-name-specifier that qualifies this /// declaration. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } @@ -3912,7 +3912,7 @@ class CXXDependentScopeMemberExpr final } /// Retrieve the nested-name-specifier that qualifies the member name. - NestedNameSpecifier *getQualifier() const { + NestedNameSpecifier getQualifier() const { return QualifierLoc.getNestedNameSpecifier(); } diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 1614f9d7c94e4..f198a8bca9078 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -6,507 +6,266 @@ // //===----------------------------------------------------------------------===// // -// This file defines the NestedNameSpecifier class, which represents -// a C++ nested-name-specifier. +// This file completes the definition of the NestedNameSpecifier class. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H #define LLVM_CLANG_AST_NESTEDNAMESPECIFIER_H -#include "clang/AST/DependenceFlags.h" -#include "clang/Basic/Diagnostic.h" -#include "clang/Basic/SourceLocation.h" +#include "clang/AST/Decl.h" +#include "clang/AST/NestedNameSpecifierBase.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "llvm/ADT/DenseMapInfo.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/PointerIntPair.h" -#include "llvm/Support/Compiler.h" -#include -#include -#include namespace clang { -class ASTContext; -class CXXRecordDecl; -class IdentifierInfo; -class LangOptions; -class NamespaceBaseDecl; -struct PrintingPolicy; -class Type; -class TypeLoc; - -/// Represents a C++ nested name specifier, such as -/// "\::std::vector::". -/// -/// C++ nested name specifiers are the prefixes to qualified -/// names. For example, "foo::" in "foo::x" is a nested name -/// specifier. Nested name specifiers are made up of a sequence of -/// specifiers, each of which can be a namespace, type, identifier -/// (for dependent names), decltype specifier, or the global specifier ('::'). -/// The last two specifiers can only appear at the start of a -/// nested-namespace-specifier. -class NestedNameSpecifier : public llvm::FoldingSetNode { - /// Enumeration describing - enum StoredSpecifierKind { - StoredIdentifier = 0, - StoredDecl = 1, - StoredTypeSpec = 2 - }; - - /// The nested name specifier that precedes this nested name - /// specifier. - /// - /// The pointer is the nested-name-specifier that precedes this - /// one. The integer stores one of the first four values of type - /// SpecifierKind. - llvm::PointerIntPair Prefix; - - /// The last component in the nested name specifier, which - /// can be an identifier, a declaration, or a type. - /// - /// When the pointer is NULL, this specifier represents the global - /// specifier '::'. Otherwise, the pointer is one of - /// IdentifierInfo*, Namespace*, or Type*, depending on the kind of - /// specifier as encoded within the prefix. - void* Specifier = nullptr; - -public: - /// The kind of specifier that completes this nested name - /// specifier. - enum SpecifierKind { - /// An identifier, stored as an IdentifierInfo*. - Identifier, - - /// A namespace-like entity, stored as a NamespaceBaseDecl*. - Namespace, - - /// A type, stored as a Type*. - TypeSpec, - - /// The global specifier '::'. There is no stored value. - Global, - - /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of - /// the class it appeared in. - Super - }; - -private: - /// Builds the global specifier. - NestedNameSpecifier() : Prefix(nullptr, StoredIdentifier) {} - - /// Copy constructor used internally to clone nested name - /// specifiers. - NestedNameSpecifier(const NestedNameSpecifier &Other) = default; - - /// Either find or insert the given nested name specifier - /// mockup in the given context. - static NestedNameSpecifier *FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup); - -public: - NestedNameSpecifier &operator=(const NestedNameSpecifier &) = delete; - - /// Builds a specifier combining a prefix and an identifier. - /// - /// The prefix must be dependent, since nested name specifiers - /// referencing an identifier are only permitted when the identifier - /// cannot be resolved. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II); - - /// Builds a nested name specifier that names a namespace or namespace alias. - static NestedNameSpecifier *Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceBaseDecl *NS); - - /// Builds a nested name specifier that names a type. - static NestedNameSpecifier * - Create(const ASTContext &Context, NestedNameSpecifier *Prefix, const Type *T); - - /// Builds a specifier that consists of just an identifier. - /// - /// The nested-name-specifier is assumed to be dependent, but has no - /// prefix because the prefix is implied by something outside of the - /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent - /// type. - static NestedNameSpecifier *Create(const ASTContext &Context, - const IdentifierInfo *II); - - /// Returns the nested name specifier representing the global - /// scope. - static NestedNameSpecifier *GlobalSpecifier(const ASTContext &Context); - - /// Returns the nested name specifier representing the __super scope - /// for the given CXXRecordDecl. - static NestedNameSpecifier *SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD); - - /// Return the prefix of this nested name specifier. - /// - /// The prefix contains all of the parts of the nested name - /// specifier that precede this current specifier. For example, for a - /// nested name specifier that represents "foo::bar::", the current - /// specifier will contain "bar::" and the prefix will contain - /// "foo::". - NestedNameSpecifier *getPrefix() const { return Prefix.getPointer(); } - - /// Determine what kind of nested name specifier is stored. - SpecifierKind getKind() const; - - /// Retrieve the identifier stored in this nested name - /// specifier. - IdentifierInfo *getAsIdentifier() const { - if (Prefix.getInt() == StoredIdentifier) - return (IdentifierInfo *)Specifier; - - return nullptr; +auto NestedNameSpecifier::getKind() const -> Kind { + if (!isStoredKind()) { + switch (getFlagKind()) { + case FlagKind::Null: + return Kind::Null; + case FlagKind::Global: + return Kind::Global; + case FlagKind::Invalid: + llvm_unreachable("use of invalid NestedNameSpecifier"); + } + llvm_unreachable("unhandled FlagKind"); } + switch (auto [K, Ptr] = getStored(); K) { + case StoredKind::Type: + return Kind::Type; + case StoredKind::NamespaceWithGlobal: + case StoredKind::NamespaceWithNamespace: + return Kind::Namespace; + case StoredKind::NamespaceOrSuper: + switch (static_cast(Ptr)->getKind()) { + case Decl::Namespace: + case Decl::NamespaceAlias: + return Kind::Namespace; + case Decl::CXXRecord: + case Decl::ClassTemplateSpecialization: + case Decl::ClassTemplatePartialSpecialization: + return Kind::MicrosoftSuper; + default: + llvm_unreachable("unexpected decl kind"); + } + } + llvm_unreachable("unknown StoredKind"); +} - /// Retrieve the namespace or namespace alias stored in this nested name - /// specifier. - NamespaceBaseDecl *getAsNamespace() const; - - /// Retrieve the record declaration stored in this nested name - /// specifier. - CXXRecordDecl *getAsRecordDecl() const; - - /// Retrieve the type stored in this nested name specifier. - const Type *getAsType() const { - if (Prefix.getInt() == StoredTypeSpec) - return (const Type *)Specifier; +NestedNameSpecifier::NestedNameSpecifier(const Type *T) + : NestedNameSpecifier({StoredKind::Type, T}) { + assert(getKind() == Kind::Type); +} - return nullptr; +auto NestedNameSpecifier::MakeNamespacePtrKind( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) -> PtrKind { + switch (Prefix.getKind()) { + case Kind::Null: + return {StoredKind::NamespaceOrSuper, Namespace}; + case Kind::Global: + return {StoredKind::NamespaceWithGlobal, Namespace}; + case Kind::Namespace: + return {StoredKind::NamespaceWithNamespace, + MakeNamespaceAndPrefixStorage(Ctx, Namespace, Prefix)}; + case Kind::MicrosoftSuper: + case Kind::Type: + llvm_unreachable("invalid prefix for namespace"); } + llvm_unreachable("unhandled kind"); +} - /// Fully translate this nested name specifier to a type. - /// Unlike getAsType, this will convert this entire nested - /// name specifier chain into its equivalent type. - const Type *translateToType(const ASTContext &Context) const; +/// Builds a nested name specifier that names a namespace. +NestedNameSpecifier::NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NestedNameSpecifier(MakeNamespacePtrKind(Ctx, Namespace, Prefix)) { + assert(getKind() == Kind::Namespace); +} - NestedNameSpecifierDependence getDependence() const; +/// Builds a nested name specifier that names a class through microsoft's +/// __super specifier. +NestedNameSpecifier::NestedNameSpecifier(CXXRecordDecl *RD) + : NestedNameSpecifier({StoredKind::NamespaceOrSuper, RD}) { + assert(getKind() == Kind::MicrosoftSuper); +} - /// Whether this nested name specifier refers to a dependent - /// type or not. - bool isDependent() const; +CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { + switch (getKind()) { + case Kind::MicrosoftSuper: + return getAsMicrosoftSuper(); + case Kind::Type: + return getAsType()->getAsCXXRecordDecl(); + case Kind::Global: + case Kind::Namespace: + case Kind::Null: + return nullptr; + } + llvm_unreachable("Invalid NNS Kind!"); +} - /// Whether this nested name specifier involves a template - /// parameter. - bool isInstantiationDependent() const; +NestedNameSpecifier NestedNameSpecifier::getCanonical() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // These are canonical and unique. + return *this; + case NestedNameSpecifier::Kind::Namespace: { + // A namespace is canonical; build a nested-name-specifier with + // this namespace and no prefix. + const NamespaceBaseDecl *ND = getAsNamespaceAndPrefix().Namespace; + return NestedNameSpecifier( + {StoredKind::NamespaceOrSuper, ND->getNamespace()->getCanonicalDecl()}); + } + case NestedNameSpecifier::Kind::Type: + return NestedNameSpecifier( + getAsType()->getCanonicalTypeInternal().getTypePtr()); + } + llvm_unreachable("unhandled kind"); +} - /// Whether this nested-name-specifier contains an unexpanded - /// parameter pack (for C++11 variadic templates). - bool containsUnexpandedParameterPack() const; +bool NestedNameSpecifier::isCanonical() const { + return *this == getCanonical(); +} - /// Whether this nested name specifier contains an error. - bool containsErrors() const; +TypeLoc NestedNameSpecifierLoc::castAsTypeLoc() const { + return TypeLoc(Qualifier.getAsType(), LoadPointer(/*Offset=*/0)); +} - /// Print this nested name specifier to the given output stream. If - /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. - /// `ns::SomeTemplate` instead of - /// `ns::SomeTemplate`. - void print(raw_ostream &OS, const PrintingPolicy &Policy, - bool ResolveTemplateArguments = false, - bool PrintFinalScopeResOp = true) const; +TypeLoc NestedNameSpecifierLoc::getAsTypeLoc() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) + return TypeLoc(); + return castAsTypeLoc(); +} - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Prefix.getOpaqueValue()); - ID.AddPointer(Specifier); +unsigned +NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier Qualifier) { + // Location of the trailing '::'. + unsigned Length = sizeof(SourceLocation::UIntTy); + + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Global: + // Nothing more to add. + break; + + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // The location of the identifier or namespace name. + Length += sizeof(SourceLocation::UIntTy); + break; + + case NestedNameSpecifier::Kind::Type: + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + Length += sizeof(void *); + break; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("Expected a non-NULL qualifier"); } - /// Dump the nested name specifier to standard output to aid - /// in debugging. - void dump(const LangOptions &LO) const; - void dump() const; - void dump(llvm::raw_ostream &OS) const; - void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; -}; + return Length; +} -/// A C++ nested-name-specifier augmented with source location -/// information. -class NestedNameSpecifierLoc { - NestedNameSpecifier *Qualifier = nullptr; - void *Data = nullptr; - - /// Determines the data length for the last component in the - /// given nested-name-specifier. - static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); - - /// Determines the data length for the entire - /// nested-name-specifier. - static unsigned getDataLength(NestedNameSpecifier *Qualifier); - -public: - /// Construct an empty nested-name-specifier. - NestedNameSpecifierLoc() = default; - - /// Construct a nested-name-specifier with source location information - /// from - NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) - : Qualifier(Qualifier), Data(Data) {} - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - explicit operator bool() const { return Qualifier; } - - /// Evaluates true when this nested-name-specifier location is - /// non-empty. - bool hasQualifier() const { return Qualifier; } - - /// Retrieve the nested-name-specifier to which this instance - /// refers. - NestedNameSpecifier *getNestedNameSpecifier() const { - return Qualifier; - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::castAsNamespaceAndPrefix() const { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + return {Namespace, NestedNameSpecifierLoc(Prefix, Data)}; +} - /// Retrieve the opaque pointer that refers to source-location data. - void *getOpaqueData() const { return Data; } - - /// Retrieve the source range covering the entirety of this - /// nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the returned source range would cover - /// from the initial '::' to the last '::'. - SourceRange getSourceRange() const LLVM_READONLY { - return SourceRange(getBeginLoc(), getEndLoc()); - } +NamespaceAndPrefixLoc NestedNameSpecifierLoc::getAsNamespaceAndPrefix() const { + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + return {}; + return castAsNamespaceAndPrefix(); +} - /// Retrieve the source range covering just the last part of - /// this nested-name-specifier, not including the prefix. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the returned source range would cover - /// from "vector" to the last '::'. - SourceRange getLocalSourceRange() const; - - /// Retrieve the location of the beginning of this - /// nested-name-specifier. - SourceLocation getBeginLoc() const { - if (!Qualifier) - return SourceLocation(); - - NestedNameSpecifierLoc First = *this; - while (NestedNameSpecifierLoc Prefix = First.getPrefix()) - First = Prefix; - return First.getLocalSourceRange().getBegin(); +unsigned NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier Qualifier) { + unsigned Length = 0; + for (; Qualifier; Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) { + Length += getLocalDataLength(Qualifier); + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Namespace) + break; } + return Length; +} - /// Retrieve the location of the end of this - /// nested-name-specifier. - SourceLocation getEndLoc() const { return getLocalSourceRange().getEnd(); } +unsigned NestedNameSpecifierLoc::getDataLength() const { + return getDataLength(Qualifier); +} - /// Retrieve the location of the beginning of this - /// component of the nested-name-specifier. - SourceLocation getLocalBeginLoc() const { - return getLocalSourceRange().getBegin(); +SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { + switch (auto Kind = Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return SourceRange(); + case NestedNameSpecifier::Kind::Global: + return LoadSourceLocation(/*Offset=*/0); + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::MicrosoftSuper: { + unsigned Offset = + Kind == NestedNameSpecifier::Kind::Namespace + ? getDataLength(Qualifier.getAsNamespaceAndPrefix().Prefix) + : 0; + return SourceRange( + LoadSourceLocation(Offset), + LoadSourceLocation(Offset + sizeof(SourceLocation::UIntTy))); } - - /// Retrieve the location of the end of this component of the - /// nested-name-specifier. - SourceLocation getLocalEndLoc() const { - return getLocalSourceRange().getEnd(); + case NestedNameSpecifier::Kind::Type: { + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + void *TypeData = LoadPointer(/*Offset=*/0); + TypeLoc TL(Qualifier.getAsType(), TypeData); + return SourceRange(TL.getBeginLoc(), LoadSourceLocation(sizeof(void *))); } - - /// Return the prefix of this nested-name-specifier. - /// - /// For example, if this instance refers to a nested-name-specifier - /// \c \::std::vector::, the prefix is \c \::std::. Note that the - /// returned prefix may be empty, if this is the first component of - /// the nested-name-specifier. - NestedNameSpecifierLoc getPrefix() const { - if (!Qualifier) - return *this; - - return NestedNameSpecifierLoc(Qualifier->getPrefix(), Data); } - /// For a nested-name-specifier that refers to a type, - /// retrieve the type with source-location information. - TypeLoc getTypeLoc() const; + llvm_unreachable("Invalid NNS Kind!"); +} - /// Determines the data length for the entire - /// nested-name-specifier. - unsigned getDataLength() const { return getDataLength(Qualifier); } +SourceRange NestedNameSpecifierLoc::getSourceRange() const { + return SourceRange(getBeginLoc(), getEndLoc()); +} - friend bool operator==(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return X.Qualifier == Y.Qualifier && X.Data == Y.Data; - } +SourceLocation NestedNameSpecifierLoc::getEndLoc() const { + return getLocalSourceRange().getEnd(); +} - friend bool operator!=(NestedNameSpecifierLoc X, - NestedNameSpecifierLoc Y) { - return !(X == Y); - } -}; +/// Retrieve the location of the beginning of this +/// component of the nested-name-specifier. +SourceLocation NestedNameSpecifierLoc::getLocalBeginLoc() const { + return getLocalSourceRange().getBegin(); +} -/// Class that aids in the construction of nested-name-specifiers along -/// with source-location information for all of the components of the +/// Retrieve the location of the end of this component of the /// nested-name-specifier. -class NestedNameSpecifierLocBuilder { - /// The current representation of the nested-name-specifier we're - /// building. - NestedNameSpecifier *Representation = nullptr; - - /// Buffer used to store source-location information for the - /// nested-name-specifier. - /// - /// Note that we explicitly manage the buffer (rather than using a - /// SmallVector) because \c Declarator expects it to be possible to memcpy() - /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. - char *Buffer = nullptr; - - /// The size of the buffer used to store source-location information - /// for the nested-name-specifier. - unsigned BufferSize = 0; - - /// The capacity of the buffer used to store source-location - /// information for the nested-name-specifier. - unsigned BufferCapacity = 0; - -public: - NestedNameSpecifierLocBuilder() = default; - NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); - - NestedNameSpecifierLocBuilder & - operator=(const NestedNameSpecifierLocBuilder &Other); - - ~NestedNameSpecifierLocBuilder() { - if (BufferCapacity) - free(Buffer); - } +SourceLocation NestedNameSpecifierLoc::getLocalEndLoc() const { + return getLocalSourceRange().getEnd(); +} - /// Retrieve the representation of the nested-name-specifier. - NestedNameSpecifier *getRepresentation() const { return Representation; } - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'type::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param TL The TypeLoc that describes the type preceding the '::'. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'identifier::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Identifier The identifier. - /// - /// \param IdentifierLoc The location of the identifier. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, SourceLocation ColonColonLoc); - - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'namespace::'. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param Namespace The namespace or namespace alias. - /// - /// \param NamespaceLoc The location of the namespace name or the namespace - // alias. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void Extend(ASTContext &Context, NamespaceBaseDecl *Namespace, - SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); - - /// Turn this (empty) nested-name-specifier into the global - /// nested-name-specifier '::'. - void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - - /// Turns this (empty) nested-name-specifier into '__super' - /// nested-name-specifier. - /// - /// \param Context The AST context in which this nested-name-specifier - /// resides. - /// - /// \param RD The declaration of the class in which nested-name-specifier - /// appeared. - /// - /// \param SuperLoc The location of the '__super' keyword. - /// name. - /// - /// \param ColonColonLoc The location of the trailing '::'. - void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, SourceLocation ColonColonLoc); - - /// Make a new nested-name-specifier from incomplete source-location - /// information. - /// - /// This routine should be used very, very rarely, in cases where we - /// need to synthesize a nested-name-specifier. Most code should instead use - /// \c Adopt() with a proper \c NestedNameSpecifierLoc. - void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceRange R); - - /// Adopt an existing nested-name-specifier (with source-range - /// information). - void Adopt(NestedNameSpecifierLoc Other); - - /// Retrieve the source range covered by this nested-name-specifier. - SourceRange getSourceRange() const LLVM_READONLY { - return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); - } +SourceRange NestedNameSpecifierLocBuilder::getSourceRange() const { + return NestedNameSpecifierLoc(Representation, Buffer).getSourceRange(); +} - /// Retrieve a nested-name-specifier with location information, - /// copied into the given AST context. - /// - /// \param Context The context into which this nested-name-specifier will be - /// copied. - NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; - - /// Retrieve a nested-name-specifier with location - /// information based on the information in this builder. - /// - /// This loc will contain references to the builder's internal data and may - /// be invalidated by any change to the builder. - NestedNameSpecifierLoc getTemporary() const { - return NestedNameSpecifierLoc(Representation, Buffer); - } +} // namespace clang + +namespace llvm { + +template <> struct DenseMapInfo { + static clang::NestedNameSpecifier getEmptyKey() { return std::nullopt; } - /// Clear out this builder, and prepare it to build another - /// nested-name-specifier with source-location information. - void Clear() { - Representation = nullptr; - BufferSize = 0; + static clang::NestedNameSpecifier getTombstoneKey() { + return clang::NestedNameSpecifier::getInvalid(); } - /// Retrieve the underlying buffer. - /// - /// \returns A pair containing a pointer to the buffer of source-location - /// data and the size of the source-location data that resides in that - /// buffer. - std::pair getBuffer() const { - return std::make_pair(Buffer, BufferSize); + static unsigned getHashValue(const clang::NestedNameSpecifier &V) { + return hash_combine(V.getAsVoidPointer()); } }; -/// Insertion operator for diagnostics. This allows sending -/// NestedNameSpecifiers into a diagnostic with <<. -inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, - NestedNameSpecifier *NNS) { - DB.AddTaggedVal(reinterpret_cast(NNS), - DiagnosticsEngine::ak_nestednamespec); - return DB; -} - -} // namespace clang - -namespace llvm { - template <> struct DenseMapInfo { - using FirstInfo = DenseMapInfo; + using FirstInfo = DenseMapInfo; using SecondInfo = DenseMapInfo; static clang::NestedNameSpecifierLoc getEmptyKey() { diff --git a/clang/include/clang/AST/NestedNameSpecifierBase.h b/clang/include/clang/AST/NestedNameSpecifierBase.h new file mode 100644 index 0000000000000..73c60ba695419 --- /dev/null +++ b/clang/include/clang/AST/NestedNameSpecifierBase.h @@ -0,0 +1,586 @@ +//===- NestedNameSpecifier.h - C++ nested name specifiers -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H +#define LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H + +#include "clang/AST/DependenceFlags.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/PointerLikeTypeTraits.h" +#include +#include +#include + +namespace clang { + +class ASTContext; +class CXXRecordDecl; +class NamedDecl; +class IdentifierInfo; +class LangOptions; +class NamespaceBaseDecl; +struct PrintingPolicy; +class Type; +class TypeLoc; + +struct NamespaceAndPrefix; +struct alignas(8) NamespaceAndPrefixStorage; + +/// Represents a C++ nested name specifier, such as +/// "\::std::vector::". +/// +/// C++ nested name specifiers are the prefixes to qualified +/// names. For example, "foo::" in "foo::x" is a nested name +/// specifier. Nested name specifiers are made up of a sequence of +/// specifiers, each of which can be a namespace, type, decltype specifier, or +/// the global specifier ('::'). The last two specifiers can only appear at the +/// start of a nested-namespace-specifier. +class NestedNameSpecifier { + enum class FlagKind { Null, Global, Invalid }; + enum class StoredKind { + Type, + NamespaceOrSuper, + NamespaceWithGlobal, + NamespaceWithNamespace + }; + static constexpr uintptr_t FlagBits = 2, FlagMask = (1u << FlagBits) - 1u, + FlagOffset = 1, PtrOffset = FlagBits + FlagOffset, + PtrMask = (1u << PtrOffset) - 1u; + + uintptr_t StoredOrFlag; + + explicit NestedNameSpecifier(uintptr_t StoredOrFlag) + : StoredOrFlag(StoredOrFlag) {} + struct PtrKind { + StoredKind SK; + const void *Ptr; + }; + explicit NestedNameSpecifier(PtrKind PK) + : StoredOrFlag(uintptr_t(PK.Ptr) | (uintptr_t(PK.SK) << FlagOffset)) { + assert(PK.Ptr != nullptr); + assert((uintptr_t(PK.Ptr) & ((1u << PtrOffset) - 1u)) == 0); + assert((uintptr_t(PK.Ptr) >> PtrOffset) != 0); + } + + explicit constexpr NestedNameSpecifier(FlagKind K) + : StoredOrFlag(uintptr_t(K) << FlagOffset) {} + + bool isStoredKind() const { return (StoredOrFlag >> PtrOffset) != 0; } + + std::pair getStored() const { + assert(isStoredKind()); + return {StoredKind(StoredOrFlag >> FlagOffset & FlagMask), + reinterpret_cast(StoredOrFlag & ~PtrMask)}; + } + + FlagKind getFlagKind() const { + assert(!isStoredKind()); + return FlagKind(StoredOrFlag >> FlagOffset); + } + + static const NamespaceAndPrefixStorage * + MakeNamespaceAndPrefixStorage(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + static inline PtrKind MakeNamespacePtrKind(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + +public: + static constexpr NestedNameSpecifier getInvalid() { + return NestedNameSpecifier(FlagKind::Invalid); + } + + static constexpr NestedNameSpecifier getGlobal() { + return NestedNameSpecifier(FlagKind::Global); + } + + NestedNameSpecifier() : NestedNameSpecifier(FlagKind::Invalid) {} + + /// The kind of specifier that completes this nested name + /// specifier. + enum class Kind { + /// Empty. + Null, + + /// The global specifier '::'. There is no stored value. + Global, + + /// A type, stored as a Type*. + Type, + + /// A namespace-like entity, stored as a NamespaceBaseDecl*. + Namespace, + + /// Microsoft's '__super' specifier, stored as a CXXRecordDecl* of + /// the class it appeared in. + MicrosoftSuper, + }; + + inline Kind getKind() const; + + NestedNameSpecifier(std::nullopt_t) : StoredOrFlag(0) {} + + explicit inline NestedNameSpecifier(const Type *T); + + /// Builds a nested name specifier that names a namespace. + inline NestedNameSpecifier(const ASTContext &Ctx, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix); + + /// Builds a nested name specifier that names a class through microsoft's + /// __super specifier. + explicit inline NestedNameSpecifier(CXXRecordDecl *RD); + + explicit operator bool() const { return StoredOrFlag != 0; } + + void *getAsVoidPointer() const { + return reinterpret_cast(StoredOrFlag); + } + static NestedNameSpecifier getFromVoidPointer(const void *Ptr) { + return NestedNameSpecifier(reinterpret_cast(Ptr)); + } + + const Type *getAsType() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::Type); + assert(Ptr != nullptr); + return static_cast(Ptr); + } + + inline NamespaceAndPrefix getAsNamespaceAndPrefix() const; + + CXXRecordDecl *getAsMicrosoftSuper() const { + auto [Kind, Ptr] = getStored(); + assert(Kind == StoredKind::NamespaceOrSuper); + assert(Ptr != nullptr); + return static_cast(const_cast(Ptr)); + } + + /// Retrieve the record declaration stored in this nested name + /// specifier, or null. + inline CXXRecordDecl *getAsRecordDecl() const; + + friend bool operator==(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag == RHS.StoredOrFlag; + } + friend bool operator!=(NestedNameSpecifier LHS, NestedNameSpecifier RHS) { + return LHS.StoredOrFlag != RHS.StoredOrFlag; + } + + /// Retrieves the "canonical" nested name specifier for a + /// given nested name specifier. + /// + /// The canonical nested name specifier is a nested name specifier + /// that uniquely identifies a type or namespace within the type + /// system. For example, given: + /// + /// \code + /// namespace N { + /// struct S { + /// template struct X { typename T* type; }; + /// }; + /// } + /// + /// template struct Y { + /// typename N::S::X::type member; + /// }; + /// \endcode + /// + /// Here, the nested-name-specifier for N::S::X:: will be + /// S::X, since 'S' and 'X' are uniquely defined + /// by declarations in the type system and the canonical type for + /// the template type parameter 'T' is template-param-0-0. + inline NestedNameSpecifier getCanonical() const; + + /// Whether this nested name specifier is canonical. + inline bool isCanonical() const; + + /// Whether this nested name specifier starts with a '::'. + bool isFullyQualified() const; + + NestedNameSpecifierDependence getDependence() const; + + /// Whether this nested name specifier refers to a dependent + /// type or not. + bool isDependent() const { + return getDependence() & NestedNameSpecifierDependence::Dependent; + } + + /// Whether this nested name specifier involves a template + /// parameter. + bool isInstantiationDependent() const { + return getDependence() & NestedNameSpecifierDependence::Instantiation; + } + + /// Whether this nested-name-specifier contains an unexpanded + /// parameter pack (for C++11 variadic templates). + bool containsUnexpandedParameterPack() const { + return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; + } + + /// Whether this nested name specifier contains an error. + bool containsErrors() const { + return getDependence() & NestedNameSpecifierDependence::Error; + } + + /// Print this nested name specifier to the given output stream. If + /// `ResolveTemplateArguments` is true, we'll print actual types, e.g. + /// `ns::SomeTemplate` instead of + /// `ns::SomeTemplate`. + void print(raw_ostream &OS, const PrintingPolicy &Policy, + bool ResolveTemplateArguments = false, + bool PrintFinalScopeResOp = true) const; + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(StoredOrFlag); + } + + /// Dump the nested name specifier to aid in debugging. + void dump(llvm::raw_ostream *OS = nullptr, + const LangOptions *LO = nullptr) const; + void dump(const LangOptions &LO) const; + void dump(llvm::raw_ostream &OS) const; + void dump(llvm::raw_ostream &OS, const LangOptions &LO) const; + + static constexpr auto NumLowBitsAvailable = FlagOffset; +}; + +struct NamespaceAndPrefix { + const NamespaceBaseDecl *Namespace; + NestedNameSpecifier Prefix; +}; + +struct alignas(8) NamespaceAndPrefixStorage : NamespaceAndPrefix, + llvm::FoldingSetNode { + NamespaceAndPrefixStorage(const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) + : NamespaceAndPrefix{Namespace, Prefix} {} + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, Namespace, Prefix); } + static void Profile(llvm::FoldingSetNodeID &ID, + const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { + ID.AddPointer(Namespace); + Prefix.Profile(ID); + } +}; + +NamespaceAndPrefix NestedNameSpecifier::getAsNamespaceAndPrefix() const { + auto [Kind, Ptr] = getStored(); + switch (Kind) { + case StoredKind::NamespaceOrSuper: + case StoredKind::NamespaceWithGlobal: + return {static_cast(Ptr), + Kind == StoredKind::NamespaceWithGlobal + ? NestedNameSpecifier::getGlobal() + : std::nullopt}; + case StoredKind::NamespaceWithNamespace: + return *static_cast(Ptr); + case StoredKind::Type:; + } + llvm_unreachable("unexpected stored kind"); +} + +struct NamespaceAndPrefixLoc; + +/// A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier Qualifier = std::nullopt; + void *Data = nullptr; + + /// Load a (possibly unaligned) source location from a given address + /// and offset. + SourceLocation LoadSourceLocation(unsigned Offset) const { + SourceLocation::UIntTy Raw; + memcpy(&Raw, static_cast(Data) + Offset, sizeof(Raw)); + return SourceLocation::getFromRawEncoding(Raw); + } + + /// Load a (possibly unaligned) pointer from a given address and + /// offset. + void *LoadPointer(unsigned Offset) const { + void *Result; + memcpy(&Result, static_cast(Data) + Offset, sizeof(void *)); + return Result; + } + + /// Determines the data length for the last component in the + /// given nested-name-specifier. + static inline unsigned getLocalDataLength(NestedNameSpecifier Qualifier); + + /// Determines the data length for the entire + /// nested-name-specifier. + static inline unsigned getDataLength(NestedNameSpecifier Qualifier); + +public: + /// Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() = default; + + /// Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) {} + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + explicit operator bool() const { return bool(Qualifier); } + + /// Evaluates true when this nested-name-specifier location is + /// non-empty. + bool hasQualifier() const { return bool(Qualifier); } + + /// Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier getNestedNameSpecifier() const { return Qualifier; } + + /// Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// Retrieve the source range covering the entirety of this + /// nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector::, the returned source range would cover + /// from the initial '::' to the last '::'. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve the source range covering just the last part of + /// this nested-name-specifier, not including the prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::vector::, the returned source range would cover + /// from "vector" to the last '::'. + inline SourceRange getLocalSourceRange() const; + + /// Retrieve the location of the beginning of this + /// nested-name-specifier. + SourceLocation getBeginLoc() const; + + /// Retrieve the location of the end of this + /// nested-name-specifier. + inline SourceLocation getEndLoc() const; + + /// Retrieve the location of the beginning of this + /// component of the nested-name-specifier. + inline SourceLocation getLocalBeginLoc() const; + + /// Retrieve the location of the end of this component of the + /// nested-name-specifier. + inline SourceLocation getLocalEndLoc() const; + + /// For a nested-name-specifier that refers to a namespace, + /// retrieve the namespace and its prefix. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c \::std::chrono::, the prefix is \c \::std::. Note that the + /// returned prefix may be empty, if this is the first component of + /// the nested-name-specifier. + inline NamespaceAndPrefixLoc castAsNamespaceAndPrefix() const; + inline NamespaceAndPrefixLoc getAsNamespaceAndPrefix() const; + + /// For a nested-name-specifier that refers to a type, + /// retrieve the type with source-location information. + inline TypeLoc castAsTypeLoc() const; + inline TypeLoc getAsTypeLoc() const; + + /// Determines the data length for the entire + /// nested-name-specifier. + inline unsigned getDataLength() const; + + friend bool operator==(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return X.Qualifier == Y.Qualifier && X.Data == Y.Data; + } + + friend bool operator!=(NestedNameSpecifierLoc X, NestedNameSpecifierLoc Y) { + return !(X == Y); + } +}; + +struct NamespaceAndPrefixLoc { + const NamespaceBaseDecl *Namespace = nullptr; + NestedNameSpecifierLoc Prefix; + + explicit operator bool() const { return Namespace != nullptr; } +}; + +/// Class that aids in the construction of nested-name-specifiers along +/// with source-location information for all of the components of the +/// nested-name-specifier. +class NestedNameSpecifierLocBuilder { + /// The current representation of the nested-name-specifier we're + /// building. + NestedNameSpecifier Representation = std::nullopt; + + /// Buffer used to store source-location information for the + /// nested-name-specifier. + /// + /// Note that we explicitly manage the buffer (rather than using a + /// SmallVector) because \c Declarator expects it to be possible to memcpy() + /// a \c CXXScopeSpec, and CXXScopeSpec uses a NestedNameSpecifierLocBuilder. + char *Buffer = nullptr; + + /// The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize = 0; + + /// The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity = 0; + + void PushTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R); + +public: + NestedNameSpecifierLocBuilder() = default; + NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other); + + NestedNameSpecifierLocBuilder & + operator=(const NestedNameSpecifierLocBuilder &Other); + + ~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); + } + + /// Retrieve the representation of the nested-name-specifier. + NestedNameSpecifier getRepresentation() const { return Representation; } + + /// Make a nested-name-specifier of the form 'type::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param TL The TypeLoc that describes the type preceding the '::'. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Make(ASTContext &Context, TypeLoc TL, SourceLocation ColonColonLoc); + + /// Extend the current nested-name-specifier by another + /// nested-name-specifier component of the form 'namespace::'. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param Namespace The namespace. + /// + /// \param NamespaceLoc The location of the namespace name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void Extend(ASTContext &Context, const NamespaceBaseDecl *Namespace, + SourceLocation NamespaceLoc, SourceLocation ColonColonLoc); + + /// Turn this (empty) nested-name-specifier into the global + /// nested-name-specifier '::'. + void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); + + /// Turns this (empty) nested-name-specifier into '__super' + /// nested-name-specifier. + /// + /// \param Context The AST context in which this nested-name-specifier + /// resides. + /// + /// \param RD The declaration of the class in which nested-name-specifier + /// appeared. + /// + /// \param SuperLoc The location of the '__super' keyword. + /// name. + /// + /// \param ColonColonLoc The location of the trailing '::'. + void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc); + + /// Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// This routine should be used very, very rarely, in cases where we + /// need to synthesize a nested-name-specifier. Most code should instead use + /// \c Adopt() with a proper \c NestedNameSpecifierLoc. + void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, + SourceRange R) { + Representation = Qualifier; + BufferSize = 0; + PushTrivial(Context, Qualifier, R); + } + + /// Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + + /// Retrieve the source range covered by this nested-name-specifier. + inline SourceRange getSourceRange() const LLVM_READONLY; + + /// Retrieve a nested-name-specifier with location information, + /// copied into the given AST context. + /// + /// \param Context The context into which this nested-name-specifier will be + /// copied. + NestedNameSpecifierLoc getWithLocInContext(ASTContext &Context) const; + + /// Retrieve a nested-name-specifier with location + /// information based on the information in this builder. + /// + /// This loc will contain references to the builder's internal data and may + /// be invalidated by any change to the builder. + NestedNameSpecifierLoc getTemporary() const { + return NestedNameSpecifierLoc(Representation, Buffer); + } + + /// Clear out this builder, and prepare it to build another + /// nested-name-specifier with source-location information. + void Clear() { + Representation = std::nullopt; + BufferSize = 0; + } + + /// Retrieve the underlying buffer. + /// + /// \returns A pair containing a pointer to the buffer of source-location + /// data and the size of the source-location data that resides in that + /// buffer. + std::pair getBuffer() const { + return std::make_pair(Buffer, BufferSize); + } +}; + +/// Insertion operator for diagnostics. This allows sending +/// NestedNameSpecifiers into a diagnostic with <<. +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, + NestedNameSpecifier NNS) { + DB.AddTaggedVal(reinterpret_cast(NNS.getAsVoidPointer()), + DiagnosticsEngine::ak_nestednamespec); + return DB; +} + +} // namespace clang + +namespace llvm { + +template <> struct PointerLikeTypeTraits { + static void *getAsVoidPointer(clang::NestedNameSpecifier P) { + return P.getAsVoidPointer(); + } + static clang::NestedNameSpecifier getFromVoidPointer(const void *P) { + return clang::NestedNameSpecifier::getFromVoidPointer(P); + } + static constexpr int NumLowBitsAvailable = + clang::NestedNameSpecifier::NumLowBitsAvailable; +}; + +} // namespace llvm + +#endif // LLVM_CLANG_AST_NESTEDNAMESPECIFIERBASE_H diff --git a/clang/include/clang/AST/ODRHash.h b/clang/include/clang/AST/ODRHash.h index 11f917a1a4634..ae3fab697786a 100644 --- a/clang/include/clang/AST/ODRHash.h +++ b/clang/include/clang/AST/ODRHash.h @@ -93,7 +93,7 @@ class ODRHash { void AddQualType(QualType T); void AddStmt(const Stmt *S); void AddIdentifierInfo(const IdentifierInfo *II); - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS); + void AddNestedNameSpecifier(NestedNameSpecifier NNS); void AddDependentTemplateName(const DependentTemplateStorage &Name); void AddTemplateName(TemplateName Name); void AddDeclarationNameInfo(DeclarationNameInfo NameInfo, diff --git a/clang/include/clang/AST/PropertiesBase.td b/clang/include/clang/AST/PropertiesBase.td index 0438e4dfbafac..5b10127526e4e 100644 --- a/clang/include/clang/AST/PropertiesBase.td +++ b/clang/include/clang/AST/PropertiesBase.td @@ -127,9 +127,8 @@ def LValuePathSerializationHelper : PropertyType<"APValue::LValuePathSerializationHelper"> { let BufferElementTypes = [ LValuePathEntry ]; } -def NestedNameSpecifier : PropertyType<"NestedNameSpecifier *">; -def NestedNameSpecifierKind : - EnumPropertyType<"NestedNameSpecifier::SpecifierKind">; +def NestedNameSpecifier : PropertyType<"NestedNameSpecifier">; +def NestedNameSpecifierKind : EnumPropertyType<"NestedNameSpecifier::Kind">; def OverloadedOperatorKind : EnumPropertyType; def Qualifiers : PropertyType; def QualType : DefaultValuePropertyType; diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 05134422797b3..248b89200eace 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -242,7 +242,7 @@ template class RecursiveASTVisitor { /// Recursively visit a C++ nested-name-specifier. /// /// \returns false if the visitation was terminated early, true otherwise. - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); /// Recursively visit a C++ nested-name-specifier with location /// information. @@ -787,46 +787,43 @@ bool RecursiveASTVisitor::TraverseDecl(Decl *D) { template bool RecursiveASTVisitor::TraverseNestedNameSpecifier( - NestedNameSpecifier *NNS) { - if (!NNS) + NestedNameSpecifier NNS) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; - - if (NNS->getPrefix()) - TRY_TO(TraverseNestedNameSpecifier(NNS->getPrefix())); - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO(TraverseNestedNameSpecifier(NNS.getAsNamespaceAndPrefix().Prefix)); + return true; + case NestedNameSpecifier::Kind::Type: { + auto *T = const_cast(NNS.getAsType()); + TRY_TO(TraverseNestedNameSpecifier(T->getPrefix())); + TRY_TO(TraverseType(QualType(T, 0), /*TraverseQualifier=*/false)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseType(QualType(NNS->getAsType(), 0))); } - - return true; + } + llvm_unreachable("unhandled kind"); } template bool RecursiveASTVisitor::TraverseNestedNameSpecifierLoc( NestedNameSpecifierLoc NNS) { - if (!NNS) + switch (NNS.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; - - if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) - TRY_TO(TraverseNestedNameSpecifierLoc(Prefix)); - - switch (NNS.getNestedNameSpecifier()->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Namespace: + TRY_TO( + TraverseNestedNameSpecifierLoc(NNS.castAsNamespaceAndPrefix().Prefix)); return true; - - case NestedNameSpecifier::TypeSpec: - TRY_TO(TraverseTypeLoc(NNS.getTypeLoc())); - break; + case NestedNameSpecifier::Kind::Type: { + TypeLoc TL = NNS.castAsTypeLoc(); + TRY_TO(TraverseNestedNameSpecifierLoc(TL.getPrefix())); + TRY_TO(TraverseTypeLoc(TL, /*TraverseQualifier=*/false)); + return true; + } } return true; @@ -1011,10 +1008,11 @@ DEF_TRAVERSE_TYPE(RValueReferenceType, { TRY_TO(TraverseType(T->getPointeeType())); }) DEF_TRAVERSE_TYPE(MemberPointerType, { - TRY_TO(TraverseNestedNameSpecifier(T->getQualifier())); - if (T->isSugared()) - TRY_TO(TraverseType( - QualType(T->getMostRecentCXXRecordDecl()->getTypeForDecl(), 0))); + NestedNameSpecifier Qualifier = + T->isSugared() ? cast(T->getCanonicalTypeUnqualified()) + ->getQualifier() + : T->getQualifier(); + TRY_TO(TraverseNestedNameSpecifier(Qualifier)); TRY_TO(TraverseType(T->getPointeeType())); }) @@ -1279,8 +1277,10 @@ DEF_TRAVERSE_TYPE(PredefinedSugarType, {}) } template -bool -RecursiveASTVisitor::TraverseQualifiedTypeLoc(QualifiedTypeLoc TL) { +bool RecursiveASTVisitor::TraverseQualifiedTypeLoc( + QualifiedTypeLoc TL, bool TraverseQualifier) { + assert(TraverseQualifier && + "Qualifiers should never occur within NestedNameSpecifiers"); // Move this over to the 'main' typeloc tree. Note that this is a // move -- we pretend that we were really looking at the unqualified // typeloc all along -- rather than a recursion, so we don't follow diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index 86c155dc17c51..ac0c0cc7e0286 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -15,7 +15,7 @@ #define LLVM_CLANG_AST_TEMPLATEBASE_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" @@ -476,31 +476,25 @@ class TemplateArgument { /// Location information for a TemplateArgument. struct TemplateArgumentLocInfo { -private: struct TemplateTemplateArgLocInfo { - // FIXME: We'd like to just use the qualifier in the TemplateName, - // but template arguments get canonicalized too quickly. - NestedNameSpecifier *Qualifier; void *QualifierLocData; + SourceLocation TemplateKwLoc; SourceLocation TemplateNameLoc; SourceLocation EllipsisLoc; }; - llvm::PointerUnion - Pointer; - TemplateTemplateArgLocInfo *getTemplate() const { return cast(Pointer); } -public: TemplateArgumentLocInfo() {} TemplateArgumentLocInfo(TypeSourceInfo *Declarator) { Pointer = Declarator; } TemplateArgumentLocInfo(Expr *E) { Pointer = E; } // Ctx is used for allocation -- this case is unusually large and also rare, // so we store the payload out-of-line. - TemplateArgumentLocInfo(ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, + TemplateArgumentLocInfo(ASTContext &Ctx, SourceLocation TemplateKwLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc); @@ -510,10 +504,8 @@ struct TemplateArgumentLocInfo { Expr *getAsExpr() const { return cast(Pointer); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { - const auto *Template = getTemplate(); - return NestedNameSpecifierLoc(Template->Qualifier, - Template->QualifierLocData); + SourceLocation getTemplateKwLoc() const { + return getTemplate()->TemplateKwLoc; } SourceLocation getTemplateNameLoc() const { @@ -560,14 +552,10 @@ class TemplateArgumentLoc { } TemplateArgumentLoc(ASTContext &Ctx, const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, - SourceLocation EllipsisLoc = SourceLocation()) - : Argument(Argument), - LocInfo(Ctx, QualifierLoc, TemplateNameLoc, EllipsisLoc) { - assert(Argument.getKind() == TemplateArgument::Template || - Argument.getKind() == TemplateArgument::TemplateExpansion); - } + SourceLocation EllipsisLoc = SourceLocation()); /// - Fetches the primary location of the argument. SourceLocation getLocation() const { @@ -616,13 +604,15 @@ class TemplateArgumentLoc { return LocInfo.getAsExpr(); } - NestedNameSpecifierLoc getTemplateQualifierLoc() const { + SourceLocation getTemplateKWLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) - return NestedNameSpecifierLoc(); - return LocInfo.getTemplateQualifierLoc(); + return SourceLocation(); + return LocInfo.getTemplateKwLoc(); } + NestedNameSpecifierLoc getTemplateQualifierLoc() const; + SourceLocation getTemplateNameLoc() const { if (Argument.getKind() != TemplateArgument::Template && Argument.getKind() != TemplateArgument::TemplateExpansion) diff --git a/clang/include/clang/AST/TemplateName.h b/clang/include/clang/AST/TemplateName.h index 63949f898f6a2..37ea401a0045a 100644 --- a/clang/include/clang/AST/TemplateName.h +++ b/clang/include/clang/AST/TemplateName.h @@ -14,7 +14,7 @@ #define LLVM_CLANG_AST_TEMPLATENAME_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/UnsignedOrNone.h" @@ -335,10 +335,18 @@ class TemplateName { /// structure, if any. QualifiedTemplateName *getAsQualifiedTemplateName() const; + /// Retrieve the underlying qualified template name, + /// looking through underlying nodes. + QualifiedTemplateName *getAsAdjustedQualifiedTemplateName() const; + /// Retrieve the underlying dependent template name /// structure, if any. DependentTemplateName *getAsDependentTemplateName() const; + // Retrieve the qualifier stored in either a underlying DependentTemplateName + // or QualifiedTemplateName. + NestedNameSpecifier getQualifier() const; + /// Retrieve the using shadow declaration through which the underlying /// template declaration is introduced, if any. UsingShadowDecl *getAsUsingShadowDecl() const; @@ -503,7 +511,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// "template" keyword is always redundant in this case (otherwise, /// the template name would be a dependent name and we would express /// this name with DependentTemplateName). - llvm::PointerIntPair Qualifier; + llvm::PointerIntPair Qualifier; /// The underlying template name, it is either /// 1) a Template -- a template declaration that this qualified name refers @@ -512,7 +520,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { /// using-shadow declaration. TemplateName UnderlyingTemplate; - QualifiedTemplateName(NestedNameSpecifier *NNS, bool TemplateKeyword, + QualifiedTemplateName(NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName Template) : Qualifier(NNS, TemplateKeyword ? 1 : 0), UnderlyingTemplate(Template) { assert(UnderlyingTemplate.getKind() == TemplateName::Template || @@ -521,7 +529,7 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { public: /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } /// Whether the template name was prefixed by the "template" /// keyword. @@ -534,9 +542,9 @@ class QualifiedTemplateName : public llvm::FoldingSetNode { Profile(ID, getQualifier(), hasTemplateKeyword(), UnderlyingTemplate); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, bool TemplateKeyword, TemplateName TN) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(TemplateKeyword); ID.AddPointer(TN.getAsVoidPointer()); } @@ -585,18 +593,18 @@ class DependentTemplateStorage { /// /// The bit stored in this qualifier describes whether the \c Name field /// was preceeded by a template keyword. - llvm::PointerIntPair Qualifier; + llvm::PointerIntPair Qualifier; /// The dependent template name. IdentifierOrOverloadedOperator Name; public: - DependentTemplateStorage(NestedNameSpecifier *Qualifier, + DependentTemplateStorage(NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword); /// Return the nested name specifier that qualifies this name. - NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); } + NestedNameSpecifier getQualifier() const { return Qualifier.getPointer(); } IdentifierOrOverloadedOperator getName() const { return Name; } @@ -609,10 +617,10 @@ class DependentTemplateStorage { Profile(ID, getQualifier(), getName(), hasTemplateKeyword()); } - static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS, + static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier NNS, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) { - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddBoolean(HasTemplateKeyword); Name.Profile(ID); } diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index 1917a8ac29f05..6d2795111685a 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -211,7 +211,7 @@ class TextNodeDumper void dumpAccessSpecifier(AccessSpecifier AS); void dumpCleanupObject(const ExprWithCleanups::CleanupObject &C); void dumpTemplateSpecializationKind(TemplateSpecializationKind TSK); - void dumpNestedNameSpecifier(const NestedNameSpecifier *NNS); + void dumpNestedNameSpecifier(NestedNameSpecifier NNS); void dumpConceptReference(const ConceptReference *R); void dumpTemplateArgument(const TemplateArgument &TA); void dumpBareTemplateName(TemplateName TN); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 23a683ededa87..c0874ef01697f 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -18,7 +18,7 @@ #define LLVM_CLANG_AST_TYPE_H #include "clang/AST/DependenceFlags.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateName.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Basic/AttrKinds.h" @@ -2956,6 +2956,11 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// qualifiers from the outermost type. const ArrayType *castAsArrayTypeUnsafe() const; + /// If this type represents a qualified-id, this returns its nested name + /// specifier. For example, for the qualified-id "foo::bar::baz", this returns + /// "foo::bar". Returns null if this type represents an unqualified-id. + NestedNameSpecifier getPrefix() const; + /// Determine whether this type had the specified attribute applied to it /// (looking through top-level type sugar). bool hasAttr(attr::Kind AK) const; @@ -3633,12 +3638,12 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { /// The class of which the pointee is a member. Must ultimately be a /// CXXRecordType, but could be a typedef or a template parameter too. - NestedNameSpecifier *Qualifier; + NestedNameSpecifier Qualifier; - MemberPointerType(QualType Pointee, NestedNameSpecifier *Qualifier, + MemberPointerType(QualType Pointee, NestedNameSpecifier Qualifier, QualType CanonicalPtr) : Type(MemberPointer, CanonicalPtr, - (toTypeDependence(Qualifier->getDependence()) & + (toTypeDependence(Qualifier.getDependence()) & ~TypeDependence::VariablyModified) | Pointee->getDependence()), PointeeType(Pointee), Qualifier(Qualifier) {} @@ -3658,7 +3663,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { return !PointeeType->isFunctionProtoType(); } - NestedNameSpecifier *getQualifier() const { return Qualifier; } + NestedNameSpecifier getQualifier() const { return Qualifier; } /// Note: this can trigger extra deserialization when external AST sources are /// used. Prefer `getCXXRecordDecl()` unless you really need the most recent /// decl. @@ -3677,7 +3682,7 @@ class MemberPointerType : public Type, public llvm::FoldingSetNode { } static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier *Qualifier, + const NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls); static bool classof(const Type *T) { @@ -7280,24 +7285,24 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { friend class ASTContext; // ASTContext creates these /// The nested name specifier containing the qualifier. - NestedNameSpecifier *NNS; + NestedNameSpecifier NNS; /// The type that this typename specifier refers to. const IdentifierInfo *Name; - DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, + DependentNameType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS, const IdentifierInfo *Name, QualType CanonType) : TypeWithKeyword(Keyword, DependentName, CanonType, TypeDependence::DependentInstantiation | - toTypeDependence(NNS->getDependence())), + (NNS ? toTypeDependence(NNS.getDependence()) + : TypeDependence::Dependent)), NNS(NNS), Name(Name) { - assert(NNS); assert(Name); } public: /// Retrieve the qualification on this type. - NestedNameSpecifier *getQualifier() const { return NNS; } + NestedNameSpecifier getQualifier() const { return NNS; } /// Retrieve the identifier that terminates this type name. /// For example, "type" in "typename T::type". @@ -7313,9 +7318,9 @@ class DependentNameType : public TypeWithKeyword, public llvm::FoldingSetNode { } static void Profile(llvm::FoldingSetNodeID &ID, ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, const IdentifierInfo *Name) { + NestedNameSpecifier NNS, const IdentifierInfo *Name) { ID.AddInteger(llvm::to_underlying(Keyword)); - ID.AddPointer(NNS); + NNS.Profile(ID); ID.AddPointer(Name); } diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index 0a8bcd2428ef7..f6021f67e278e 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -16,7 +16,7 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/DeclarationName.h" -#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/NestedNameSpecifierBase.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" #include "clang/Basic/LLVM.h" @@ -193,6 +193,21 @@ class TypeLoc { /// Get the SourceLocation of the template keyword (if any). SourceLocation getTemplateKeywordLoc() const; + /// If this type represents a qualified-id, this returns it's nested name + /// specifier. For example, for the qualified-id "foo::bar::baz", this returns + /// "foo::bar". Returns null if this type represents an unqualified-id. + NestedNameSpecifierLoc getPrefix() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword, and name qualifiers. This will the 'template' keyword if + /// present, or the name location otherwise. + SourceLocation getNonPrefixBeginLoc() const; + + /// This returns the position of the type after any elaboration, such as the + /// 'struct' keyword. This may be the position of the name qualifiers, + /// 'template' keyword, or the name location otherwise. + SourceLocation getNonElaboratedBeginLoc() const; + /// Initializes this to state that every location in this /// type is the given location. /// @@ -1520,7 +1535,7 @@ class MemberPointerTypeLoc : public PointerLikeTypeLocgetQualifier()) { + if (NestedNameSpecifier Qualifier = getTypePtr()->getQualifier()) { NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, Qualifier, Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 02d79b7488f82..cbd931cabd806 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -7775,7 +7775,7 @@ AST_MATCHER_FUNCTION_P_OVERLOAD( /// matches "A::" AST_MATCHER_P(NestedNameSpecifier, specifiesType, internal::Matcher, InnerMatcher) { - if (!Node.getAsType()) + if (Node.getKind() != NestedNameSpecifier::Kind::Type) return false; return InnerMatcher.matches(QualType(Node.getAsType(), 0), Finder, Builder); } @@ -7793,8 +7793,12 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType, /// matches "A::" AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, internal::Matcher, InnerMatcher) { - return Node && Node.getNestedNameSpecifier()->getAsType() && - InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder); + if (!Node) + return false; + TypeLoc TL = Node.getAsTypeLoc(); + if (!TL) + return false; + return InnerMatcher.matches(TL, Finder, Builder); } /// Matches on the prefix of a \c NestedNameSpecifier. @@ -7809,10 +7813,21 @@ AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix, internal::Matcher, InnerMatcher, 0) { - const NestedNameSpecifier *NextNode = Node.getPrefix(); + NestedNameSpecifier NextNode = std::nullopt; + switch (Node.getKind()) { + case NestedNameSpecifier::Kind::Namespace: + NextNode = Node.getAsNamespaceAndPrefix().Prefix; + break; + case NestedNameSpecifier::Kind::Type: + NextNode = Node.getAsType()->getPrefix(); + break; + default: + break; + } + if (!NextNode) return false; - return InnerMatcher.matches(*NextNode, Finder, Builder); + return InnerMatcher.matches(NextNode, Finder, Builder); } /// Matches on the prefix of a \c NestedNameSpecifierLoc. @@ -7827,7 +7842,12 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifier, hasPrefix, AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix, internal::Matcher, InnerMatcher, 1) { - NestedNameSpecifierLoc NextNode = Node.getPrefix(); + NestedNameSpecifierLoc NextNode; + if (TypeLoc TL = Node.getAsTypeLoc()) + NextNode = TL.getPrefix(); + else + NextNode = Node.getAsNamespaceAndPrefix().Prefix; + if (!NextNode) return false; return InnerMatcher.matches(NextNode, Finder, Builder); @@ -7845,9 +7865,13 @@ AST_MATCHER_P_OVERLOAD(NestedNameSpecifierLoc, hasPrefix, /// matches "ns::" AST_MATCHER_P(NestedNameSpecifier, specifiesNamespace, internal::Matcher, InnerMatcher) { - if (auto *NS = dyn_cast_if_present(Node.getAsNamespace())) - return InnerMatcher.matches(*NS, Finder, Builder); - return false; + if (Node.getKind() != NestedNameSpecifier::Kind::Namespace) + return false; + const auto *Namespace = + dyn_cast(Node.getAsNamespaceAndPrefix().Namespace); + if (!Namespace) + return false; + return InnerMatcher.matches(*Namespace, Finder, Builder); } /// Matches attributes. diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index f074bc5fed2cc..1ab6f11a23e12 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1783,7 +1783,7 @@ class LocMatcher : public MatcherInterface { private: static DynTypedNode extract(const NestedNameSpecifierLoc &Loc) { - return DynTypedNode::create(*Loc.getNestedNameSpecifier()); + return DynTypedNode::create(Loc.getNestedNameSpecifier()); } }; diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index 4ac744459031e..4859225ef4ced 100644 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -440,9 +440,8 @@ class DeclarationFragmentsBuilder { DeclarationFragments &); /// Build DeclarationFragments for a NestedNameSpecifier. - static DeclarationFragments getFragmentsForNNS(const NestedNameSpecifier *, - ASTContext &, - DeclarationFragments &); + static DeclarationFragments + getFragmentsForNNS(NestedNameSpecifier, ASTContext &, DeclarationFragments &); /// Build DeclarationFragments for Qualifiers. static DeclarationFragments getFragmentsForQualifiers(const Qualifiers quals); diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index 2dd27593778c7..c26f4e33d289c 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -162,7 +162,8 @@ SimplifiedTypeClass getSimplifiedTypeClass(CanQualType T); /// Determine the type that this declaration will have if it is used /// as a type or in an expression. -QualType getDeclUsageType(ASTContext &C, const NamedDecl *ND); +QualType getDeclUsageType(ASTContext &C, NestedNameSpecifier Qualifier, + const NamedDecl *ND); /// Determine the priority to be given to a macro code completion result /// with the given name. @@ -867,7 +868,7 @@ class CodeCompletionResult { /// If the result should have a nested-name-specifier, this is it. /// When \c QualifierIsInformative, the nested-name-specifier is /// informative rather than required. - NestedNameSpecifier *Qualifier = nullptr; + NestedNameSpecifier Qualifier = std::nullopt; /// If this Decl was unshadowed by using declaration, this can store a /// pointer to the UsingShadowDecl which was used in the unshadowing process. @@ -882,7 +883,7 @@ class CodeCompletionResult { /// Build a result that refers to a declaration. CodeCompletionResult(const NamedDecl *Declaration, unsigned Priority, - NestedNameSpecifier *Qualifier = nullptr, + NestedNameSpecifier Qualifier = std::nullopt, bool QualifierIsInformative = false, bool Accessible = true, std::vector FixIts = std::vector()) diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 797ef9b601ebc..c1a99a1fddc80 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -91,12 +91,11 @@ class CXXScopeSpec { } /// Retrieve the representation of the nested-name-specifier. - NestedNameSpecifier *getScopeRep() const { + NestedNameSpecifier getScopeRep() const { return Builder.getRepresentation(); } - /// Extend the current nested-name-specifier by another - /// nested-name-specifier component of the form 'type::'. + /// Make a nested-name-specifier of the form 'type::'. /// /// \param Context The AST context in which this nested-name-specifier /// resides. @@ -140,8 +139,9 @@ class CXXScopeSpec { /// name. /// /// \param ColonColonLoc The location of the trailing '::'. - void MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, SourceLocation ColonColonLoc); + void MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc); /// Make a new nested-name-specifier from incomplete source-location /// information. @@ -149,7 +149,7 @@ class CXXScopeSpec { /// FIXME: This routine should be used very, very rarely, in cases where we /// need to synthesize a nested-name-specifier. Most code should instead use /// \c Adopt() with a proper \c NestedNameSpecifierLoc. - void MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, + void MakeTrivial(ASTContext &Context, NestedNameSpecifier Qualifier, SourceRange R); /// Adopt an existing nested-name-specifier (with source-range diff --git a/clang/include/clang/Sema/HeuristicResolver.h b/clang/include/clang/Sema/HeuristicResolver.h index e193c0bc14cd9..71588bee92d16 100644 --- a/clang/include/clang/Sema/HeuristicResolver.h +++ b/clang/include/clang/Sema/HeuristicResolver.h @@ -67,8 +67,7 @@ class HeuristicResolver { // Try to heuristically resolve a dependent nested name specifier // to the type it likely denotes. Note that *dependent* name specifiers always // denote types, not namespaces. - QualType - resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS) const; + QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS) const; // Perform an imprecise lookup of a dependent name in `RD`. // This function does not follow strict semantic rules and should be used diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 24dccffcd5675..1655c855d119e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3218,7 +3218,7 @@ class Sema final : public SemaBase { /// current instantiation (C++0x [temp.dep.type]p1). /// /// \param NNS a dependent nested name specifier. - CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); + CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier NNS); /// The parser has parsed a global nested-name-specifier '::'. /// @@ -3255,7 +3255,7 @@ class Sema final : public SemaBase { /// (e.g., Base::), perform name lookup for that identifier as a /// nested-name-specifier within the given scope, and return the result of /// that name lookup. - NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); + NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier NNS); /// Keeps information about an identifier in a nested-name-spec. /// @@ -7618,7 +7618,7 @@ class Sema final : public SemaBase { /// "real" base class is checked as appropriate when checking the access of /// the member name. ExprResult PerformObjectMemberConversion(Expr *From, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); @@ -10196,7 +10196,7 @@ class Sema final : public SemaBase { ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj, FunctionDecl *Fun); ExprResult PerformImplicitObjectArgumentInitialization( - Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, + Expr *From, NestedNameSpecifier Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); /// PerformContextuallyConvertToBool - Perform a contextual conversion @@ -13741,8 +13741,9 @@ class Sema final : public SemaBase { SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName - SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, - SourceLocation Loc, + SubstTemplateName(SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc &QualifierLoc, TemplateName Name, + SourceLocation NameLoc, const MultiLevelTemplateArgumentList &TemplateArgs); bool SubstTypeConstraint(TemplateTypeParmDecl *Inst, const TypeConstraint *TC, diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h index 4d0da1102bb59..c6287f4c76a11 100644 --- a/clang/include/clang/Sema/SemaInternal.h +++ b/clang/include/clang/Sema/SemaInternal.h @@ -208,7 +208,7 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { class NamespaceSpecifierSet { struct SpecifierInfo { DeclContext* DeclCtx; - NestedNameSpecifier* NameSpecifier; + NestedNameSpecifier NameSpecifier; unsigned EditDistance; }; @@ -228,9 +228,9 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { static DeclContextList buildContextChain(DeclContext *Start); unsigned buildNestedNameSpecifier(DeclContextList &DeclChain, - NestedNameSpecifier *&NNS); + NestedNameSpecifier &NNS); - public: + public: NamespaceSpecifierSet(ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec); @@ -275,7 +275,7 @@ class TypoCorrectionConsumer : public VisibleDeclConsumer { }; void addName(StringRef Name, NamedDecl *ND, - NestedNameSpecifier *NNS = nullptr, bool isKeyword = false); + NestedNameSpecifier NNS = std::nullopt, bool isKeyword = false); /// Find any visible decls for the given typo correction candidate. /// If none are found, it to the set of candidates for which qualified lookups diff --git a/clang/include/clang/Sema/TypoCorrection.h b/clang/include/clang/Sema/TypoCorrection.h index 09de164297e7b..1d780c45efd55 100644 --- a/clang/include/clang/Sema/TypoCorrection.h +++ b/clang/include/clang/Sema/TypoCorrection.h @@ -57,15 +57,15 @@ class TypoCorrection { static const unsigned CallbackDistanceWeight = 150U; TypoCorrection(const DeclarationName &Name, NamedDecl *NameDecl, - NestedNameSpecifier *NNS = nullptr, unsigned CharDistance = 0, - unsigned QualifierDistance = 0) + NestedNameSpecifier NNS = std::nullopt, + unsigned CharDistance = 0, unsigned QualifierDistance = 0) : CorrectionName(Name), CorrectionNameSpec(NNS), CharDistance(CharDistance), QualifierDistance(QualifierDistance) { if (NameDecl) CorrectionDecls.push_back(NameDecl); } - TypoCorrection(NamedDecl *Name, NestedNameSpecifier *NNS = nullptr, + TypoCorrection(NamedDecl *Name, NestedNameSpecifier NNS = std::nullopt, unsigned CharDistance = 0) : CorrectionName(Name->getDeclName()), CorrectionNameSpec(NNS), CharDistance(CharDistance) { @@ -73,7 +73,7 @@ class TypoCorrection { CorrectionDecls.push_back(Name); } - TypoCorrection(DeclarationName Name, NestedNameSpecifier *NNS = nullptr, + TypoCorrection(DeclarationName Name, NestedNameSpecifier NNS = std::nullopt, unsigned CharDistance = 0) : CorrectionName(Name), CorrectionNameSpec(NNS), CharDistance(CharDistance) {} @@ -88,13 +88,13 @@ class TypoCorrection { } /// Gets the NestedNameSpecifier needed to use the typo correction - NestedNameSpecifier *getCorrectionSpecifier() const { + NestedNameSpecifier getCorrectionSpecifier() const { return CorrectionNameSpec; } - void setCorrectionSpecifier(NestedNameSpecifier *NNS) { + void setCorrectionSpecifier(NestedNameSpecifier NNS) { CorrectionNameSpec = NNS; - ForceSpecifierReplacement = (NNS != nullptr); + ForceSpecifierReplacement = !!NNS; } void WillReplaceSpecifier(bool ForceReplacement) { @@ -264,7 +264,7 @@ class TypoCorrection { // Results. DeclarationName CorrectionName; - NestedNameSpecifier *CorrectionNameSpec = nullptr; + NestedNameSpecifier CorrectionNameSpec = std::nullopt; SmallVector CorrectionDecls; unsigned CharDistance = 0; unsigned QualifierDistance = 0; @@ -282,8 +282,9 @@ class CorrectionCandidateCallback { public: static const unsigned InvalidDistance = TypoCorrection::InvalidDistance; - explicit CorrectionCandidateCallback(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + explicit CorrectionCandidateCallback( + const IdentifierInfo *Typo = nullptr, + NestedNameSpecifier TypoNNS = std::nullopt) : Typo(Typo), TypoNNS(TypoNNS) {} virtual ~CorrectionCandidateCallback() = default; @@ -320,7 +321,7 @@ class CorrectionCandidateCallback { virtual std::unique_ptr clone() = 0; void setTypoName(const IdentifierInfo *II) { Typo = II; } - void setTypoNNS(NestedNameSpecifier *NNS) { TypoNNS = NNS; } + void setTypoNNS(NestedNameSpecifier NNS) { TypoNNS = NNS; } // Flags for context-dependent keywords. WantFunctionLikeCasts is only // used/meaningful when WantCXXNamedCasts is false. @@ -346,13 +347,13 @@ class CorrectionCandidateCallback { } const IdentifierInfo *Typo; - NestedNameSpecifier *TypoNNS; + NestedNameSpecifier TypoNNS; }; class DefaultFilterCCC final : public CorrectionCandidateCallback { public: explicit DefaultFilterCCC(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + NestedNameSpecifier TypoNNS = std::nullopt) : CorrectionCandidateCallback(Typo, TypoNNS) {} std::unique_ptr clone() override { @@ -366,7 +367,7 @@ template class DeclFilterCCC final : public CorrectionCandidateCallback { public: explicit DeclFilterCCC(const IdentifierInfo *Typo = nullptr, - NestedNameSpecifier *TypoNNS = nullptr) + NestedNameSpecifier TypoNNS = std::nullopt) : CorrectionCandidateCallback(Typo, TypoNNS) {} bool ValidateCandidate(const TypoCorrection &candidate) override { diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 1472497ff5e7e..aed1b7d309001 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -223,7 +223,7 @@ class ASTRecordReader void readQualifierInfo(QualifierInfo &Info); /// Return a nested name specifier, advancing Idx. - // NestedNameSpecifier *readNestedNameSpecifier(); (inherited) + // NestedNameSpecifier readNestedNameSpecifier(); (inherited) NestedNameSpecifierLoc readNestedNameSpecifierLoc(); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index 97178a4aa980c..9849ea6b395ab 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -279,7 +279,7 @@ class ASTRecordWriter void AddQualifierInfo(const QualifierInfo &Info); /// Emit a nested name specifier. - void AddNestedNameSpecifier(NestedNameSpecifier *NNS) { + void AddNestedNameSpecifier(NestedNameSpecifier NNS) { writeNestedNameSpecifier(NNS); } diff --git a/clang/include/clang/Tooling/Refactoring/Lookup.h b/clang/include/clang/Tooling/Refactoring/Lookup.h index dcb40b7eee66c..fe0df8656bce1 100644 --- a/clang/include/clang/Tooling/Refactoring/Lookup.h +++ b/clang/include/clang/Tooling/Refactoring/Lookup.h @@ -38,8 +38,7 @@ namespace tooling { /// \param ReplacementString The replacement nested name. Must be fully /// qualified including a leading "::". /// \returns The new name to be inserted in place of the current nested name. -std::string replaceNestedName(const NestedNameSpecifier *Use, - SourceLocation UseLoc, +std::string replaceNestedName(NestedNameSpecifier Use, SourceLocation UseLoc, const DeclContext *UseContext, const NamedDecl *FromDecl, StringRef ReplacementString); diff --git a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h index 271232e66626e..319569fd5ab33 100644 --- a/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h +++ b/clang/include/clang/Tooling/Refactoring/RecursiveSymbolVisitor.h @@ -108,19 +108,21 @@ class RecursiveSymbolVisitor bool VisitTypedefTypeLoc(TypedefTypeLoc TL) { const SourceLocation TypeEndLoc = Lexer::getLocForEndOfToken(TL.getBeginLoc(), 0, SM, LangOpts); - return visit(TL.getTypedefNameDecl(), TL.getBeginLoc(), TypeEndLoc); + return visit(TL.getDecl(), TL.getBeginLoc(), TypeEndLoc); } - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) { // The base visitor will visit NNSL prefixes, so we should only look at // the current NNS. - if (NNS) { - const auto *ND = dyn_cast_if_present( - NNS.getNestedNameSpecifier()->getAsNamespace()); - if (!visit(ND, NNS.getLocalBeginLoc(), NNS.getLocalEndLoc())) + if (NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) { + const auto *ND = dyn_cast( + Qualifier.getAsNamespaceAndPrefix().Namespace); + if (!visit(ND, QualifierLoc.getLocalBeginLoc(), + QualifierLoc.getLocalEndLoc())) return false; } - return BaseType::TraverseNestedNameSpecifierLoc(NNS); + return BaseType::TraverseNestedNameSpecifierLoc(QualifierLoc); } bool VisitDesignatedInitExpr(const DesignatedInitExpr *E) { diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index 91ab66f4639fc..b25757ba43455 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ExprConcepts.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/PrettyPrinter.h" #include "llvm/ADT/StringExtras.h" @@ -92,10 +93,16 @@ ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, FoundDecl, NamedConcept, ArgsAsWritten); } +SourceLocation ConceptReference::getBeginLoc() const { + // Note that if the qualifier is null the template KW must also be null. + if (auto QualifierLoc = getNestedNameSpecifierLoc()) + return QualifierLoc.getBeginLoc(); + return getConceptNameInfo().getBeginLoc(); +} + void ConceptReference::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpec) - NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy); + NestedNameSpec.getNestedNameSpecifier().print(OS, Policy); ConceptName.printName(OS, Policy); if (hasExplicitTemplateArgs()) { OS << "<"; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 399e993bfc9f5..42dddd61ed88c 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4163,14 +4163,13 @@ QualType ASTContext::getRValueReferenceType(QualType T) const { } QualType ASTContext::getMemberPointerType(QualType T, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) const { if (!Qualifier) { assert(Cls && "At least one of Qualifier or Cls must be provided"); - Qualifier = NestedNameSpecifier::Create(*this, /*Prefix=*/nullptr, - getTypeDeclType(Cls).getTypePtr()); + Qualifier = NestedNameSpecifier(getCanonicalTagType(Cls).getTypePtr()); } else if (!Cls) { - Cls = Qualifier->getAsRecordDecl(); + Cls = Qualifier.getAsRecordDecl(); } // Unique pointers, to guarantee there is only one pointer of a particular // structure. @@ -4182,12 +4181,11 @@ QualType ASTContext::getMemberPointerType(QualType T, MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); - NestedNameSpecifier *CanonicalQualifier = [&] { + NestedNameSpecifier CanonicalQualifier = [&] { if (!Cls) - return getCanonicalNestedNameSpecifier(Qualifier); - NestedNameSpecifier *R = NestedNameSpecifier::Create( - *this, /*Prefix=*/nullptr, Cls->getCanonicalDecl()->getTypeForDecl()); - assert(R == getCanonicalNestedNameSpecifier(R)); + return Qualifier.getCanonical(); + NestedNameSpecifier R(getCanonicalTagType(Cls).getTypePtr()); + assert(R.isCanonical()); return R; }(); // If the pointee or class type isn't canonical, this won't be a canonical @@ -6101,7 +6099,7 @@ getCanonicalElaboratedTypeKeyword(ElaboratedTypeKeyword Keyword) { } QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, - NestedNameSpecifier *NNS, + NestedNameSpecifier NNS, const IdentifierInfo *Name) const { llvm::FoldingSetNodeID ID; DependentNameType::Profile(ID, Keyword, NNS, Name); @@ -6113,7 +6111,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); QualType Canon; if (CanonKeyword != Keyword || CanonNNS != NNS) { @@ -6152,13 +6150,13 @@ QualType ASTContext::getDependentTemplateSpecializationType( ID, InsertPos)) return QualType(T, 0); - NestedNameSpecifier *NNS = Name.getQualifier(); + NestedNameSpecifier NNS = Name.getQualifier(); QualType Canon; if (!IsCanonical) { ElaboratedTypeKeyword CanonKeyword = getCanonicalElaboratedTypeKeyword(Keyword); - NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + NestedNameSpecifier CanonNNS = NNS.getCanonical(); bool AnyNonCanonArgs = false; auto CanonArgs = ::getCanonicalTemplateArguments(*this, Args, AnyNonCanonArgs); @@ -6178,7 +6176,7 @@ QualType ASTContext::getDependentTemplateSpecializationType( } else { assert(Keyword == getCanonicalElaboratedTypeKeyword(Keyword)); assert(Name.hasTemplateKeyword()); - assert(NNS == getCanonicalNestedNameSpecifier(NNS)); + assert(NNS.isCanonical()); #ifndef NDEBUG for (const auto &Arg : Args) assert(Arg.structurallyEquals(getCanonicalTemplateArgument(Arg))); @@ -7216,8 +7214,8 @@ bool ASTContext::UnwrapSimilarTypes(QualType &T1, QualType &T2, *RD2 = T2MPType->getMostRecentCXXRecordDecl(); RD1 != RD2 && RD1->getCanonicalDecl() != RD2->getCanonicalDecl()) return false; - if (getCanonicalNestedNameSpecifier(T1MPType->getQualifier()) != - getCanonicalNestedNameSpecifier(T2MPType->getQualifier())) + if (T1MPType->getQualifier().getCanonical() != + T2MPType->getQualifier().getCanonical()) return false; T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); @@ -7374,9 +7372,8 @@ TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name, case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); - NestedNameSpecifier *Qualifier = DTN->getQualifier(); - NestedNameSpecifier *CanonQualifier = - getCanonicalNestedNameSpecifier(Qualifier); + NestedNameSpecifier Qualifier = DTN->getQualifier(); + NestedNameSpecifier CanonQualifier = Qualifier.getCanonical(); if (Qualifier != CanonQualifier || !DTN->hasTemplateKeyword()) return getDependentTemplateName({CanonQualifier, DTN->getName(), /*HasTemplateKeyword=*/true}); @@ -7593,38 +7590,40 @@ bool ASTContext::isSameDefaultTemplateArgument(const NamedDecl *X, return hasSameTemplateName(TAX.getAsTemplate(), TAY.getAsTemplate()); } -static bool isSameQualifier(const NestedNameSpecifier *X, - const NestedNameSpecifier *Y) { - if (X->getKind() != Y->getKind()) +static bool isSameQualifier(const NestedNameSpecifier X, + const NestedNameSpecifier Y) { + if (X == Y) + return true; + if (!X || !Y) + return false; + + auto Kind = X.getKind(); + if (Kind != Y.getKind()) return false; // FIXME: For namespaces and types, we're permitted to check that the entity // is named via the same tokens. We should probably do so. - switch (X->getKind()) { - case NestedNameSpecifier::Identifier: - if (X->getAsIdentifier() != Y->getAsIdentifier()) - return false; - break; - case NestedNameSpecifier::Namespace: - if (!declaresSameEntity(X->getAsNamespace(), Y->getAsNamespace())) + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [NamespaceX, PrefixX] = X.getAsNamespaceAndPrefix(); + auto [NamespaceY, PrefixY] = Y.getAsNamespaceAndPrefix(); + if (!declaresSameEntity(NamespaceX->getNamespace(), + NamespaceY->getNamespace())) return false; - break; - case NestedNameSpecifier::TypeSpec: - if (X->getAsType()->getCanonicalTypeInternal() != - Y->getAsType()->getCanonicalTypeInternal()) + return isSameQualifier(PrefixX, PrefixY); + } + case NestedNameSpecifier::Kind::Type: { + const auto *TX = X.getAsType(), *TY = Y.getAsType(); + if (TX->getCanonicalTypeInternal() != TY->getCanonicalTypeInternal()) return false; - break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + return isSameQualifier(TX->getPrefix(), TY->getPrefix()); + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return true; } - - // Recurse into earlier portion of NNS, if any. - auto *PX = X->getPrefix(); - auto *PY = Y->getPrefix(); - if (PX && PY) - return isSameQualifier(PX, PY); - return !PX && !PY; + llvm_unreachable("unhandled qualifier kind"); } static bool hasSameCudaAttrs(const FunctionDecl *A, const FunctionDecl *B) { @@ -8017,63 +8016,6 @@ bool ASTContext::isSameTemplateArgument(const TemplateArgument &Arg1, llvm_unreachable("Unhandled template argument kind"); } -NestedNameSpecifier * -ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { - if (!NNS) - return nullptr; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - // Canonicalize the prefix but keep the identifier the same. - return NestedNameSpecifier::Create(*this, - getCanonicalNestedNameSpecifier(NNS->getPrefix()), - NNS->getAsIdentifier()); - - case NestedNameSpecifier::Namespace: - // A namespace is canonical; build a nested-name-specifier with - // this namespace and no prefix. - return NestedNameSpecifier::Create( - *this, nullptr, NNS->getAsNamespace()->getNamespace()->getFirstDecl()); - - // The difference between TypeSpec and TypeSpecWithTemplate is that the - // latter will have the 'template' keyword when printed. - case NestedNameSpecifier::TypeSpec: { - const Type *T = getCanonicalType(NNS->getAsType()); - - // If we have some kind of dependent-named type (e.g., "typename T::type"), - // break it apart into its prefix and identifier, then reconsititute those - // as the canonical nested-name-specifier. This is required to canonicalize - // a dependent nested-name-specifier involving typedefs of dependent-name - // types, e.g., - // typedef typename T::type T1; - // typedef typename T1::type T2; - if (const auto *DNT = T->getAs()) - return NestedNameSpecifier::Create(*this, DNT->getQualifier(), - DNT->getIdentifier()); - if (const auto *DTST = T->getAs()) { - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - QualType NewT = getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {/*NNS=*/nullptr, DTN.getName(), /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - assert(NewT.isCanonical()); - NestedNameSpecifier *Prefix = DTN.getQualifier(); - if (!Prefix) - Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); - return NestedNameSpecifier::Create(*this, Prefix, NewT.getTypePtr()); - } - return NestedNameSpecifier::Create(*this, nullptr, T); - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // The global specifier and __super specifer are canonical and unique. - return NNS; - } - - llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); -} - const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { @@ -10480,7 +10422,7 @@ TemplateName ASTContext::getAssumedTemplateName(DeclarationName Name) const { /// Retrieve the template name that represents a qualified /// template name such as \c std::vector. -TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier Qualifier, bool TemplateKeyword, TemplateName Template) const { assert(Template.getKind() == TemplateName::Template || @@ -13854,163 +13796,101 @@ static auto getCommonTemplateArguments(const ASTContext &Ctx, } template -static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y) { - return X->getKeyword() == Y->getKeyword() ? X->getKeyword() - : ElaboratedTypeKeyword::None; +static ElaboratedTypeKeyword getCommonTypeKeyword(const T *X, const T *Y, + bool IsSame) { + ElaboratedTypeKeyword KX = X->getKeyword(), KY = Y->getKeyword(); + if (KX == KY) + return KX; + KX = getCanonicalElaboratedTypeKeyword(KX); + assert(!IsSame || KX == getCanonicalElaboratedTypeKeyword(KY)); + return KX; } /// Returns a NestedNameSpecifier which has only the common sugar /// present in both NNS1 and NNS2. -static NestedNameSpecifier *getCommonNNS(ASTContext &Ctx, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2, - bool IsSame) { +static NestedNameSpecifier getCommonNNS(const ASTContext &Ctx, + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2, bool IsSame) { // If they are identical, all sugar is common. if (NNS1 == NNS2) return NNS1; - // IsSame implies both NNSes are equivalent. - NestedNameSpecifier *Canon = Ctx.getCanonicalNestedNameSpecifier(NNS1); - if (Canon != Ctx.getCanonicalNestedNameSpecifier(NNS2)) { + // IsSame implies both Qualifiers are equivalent. + NestedNameSpecifier Canon = NNS1.getCanonical(); + if (Canon != NNS2.getCanonical()) { assert(!IsSame && "Should be the same NestedNameSpecifier"); // If they are not the same, there is nothing to unify. - // FIXME: It would be useful here if we could represent a canonically - // empty NNS, which is not identical to an empty-as-written NNS. - return nullptr; + return std::nullopt; } - NestedNameSpecifier *R = nullptr; - NestedNameSpecifier::SpecifierKind K1 = NNS1->getKind(), K2 = NNS2->getKind(); - switch (K1) { - case NestedNameSpecifier::SpecifierKind::Identifier: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Identifier); - IdentifierInfo *II = NNS1->getAsIdentifier(); - assert(II == NNS2->getAsIdentifier()); - // For an identifier, the prefixes are significant, so they must be the - // same. - NestedNameSpecifier *P = ::getCommonNNS(Ctx, NNS1->getPrefix(), - NNS2->getPrefix(), /*IsSame=*/true); - R = NestedNameSpecifier::Create(Ctx, P, II); - break; - } - case NestedNameSpecifier::SpecifierKind::Namespace: { - assert(K2 == NestedNameSpecifier::SpecifierKind::Namespace); - // The prefixes for namespaces are not significant, its declaration - // identifies it uniquely. - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), - /*IsSame=*/false); - NamespaceBaseDecl *Namespace1 = NNS1->getAsNamespace(), - *Namespace2 = NNS2->getAsNamespace(); + NestedNameSpecifier R = std::nullopt; + NestedNameSpecifier::Kind Kind = NNS1.getKind(); + assert(Kind == NNS2.getKind()); + switch (Kind) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); auto Kind = Namespace1->getKind(); if (Kind != Namespace2->getKind() || (Kind == Decl::NamespaceAlias && !declaresSameEntity(Namespace1, Namespace2))) { - R = NestedNameSpecifier::Create( - Ctx, P, + R = NestedNameSpecifier( + Ctx, ::getCommonDeclChecked(Namespace1->getNamespace(), - Namespace2->getNamespace())); + Namespace2->getNamespace()), + /*Prefix=*/std::nullopt); break; } - R = NestedNameSpecifier::Create( - Ctx, P, ::getCommonDeclChecked(Namespace1, Namespace2)); + // The prefixes for namespaces are not significant, its declaration + // identifies it uniquely. + NestedNameSpecifier Prefix = ::getCommonNNS(Ctx, Prefix1, Prefix2, + /*IsSame=*/false); + R = NestedNameSpecifier(Ctx, ::getCommonDeclChecked(Namespace1, Namespace2), + Prefix); break; } - case NestedNameSpecifier::SpecifierKind::TypeSpec: { - // FIXME: See comment below, on Super case. - if (K2 == NestedNameSpecifier::SpecifierKind::Super) - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - - assert(K2 == NestedNameSpecifier::SpecifierKind::TypeSpec); - - const Type *T1 = NNS1->getAsType(), *T2 = NNS2->getAsType(); - if (T1 == T2) { - // If the types are indentical, then only the prefixes differ. - // A well-formed NNS never has these types, as they have - // special normalized forms. - assert((!isa(T1))); - // Only for a DependentTemplateSpecializationType the prefix - // is actually significant. A DependentName, which would be another - // plausible case, cannot occur here, as explained above. - bool IsSame = isa(T1); - NestedNameSpecifier *P = - ::getCommonNNS(Ctx, NNS1->getPrefix(), NNS2->getPrefix(), IsSame); - R = NestedNameSpecifier::Create(Ctx, P, T1); - break; - } - // TODO: Try to salvage the original prefix. - // If getCommonSugaredType removed any top level sugar, the original prefix - // is not applicable anymore. + case NestedNameSpecifier::Kind::Type: { + const Type *T1 = NNS1.getAsType(), *T2 = NNS2.getAsType(); const Type *T = Ctx.getCommonSugaredType(QualType(T1, 0), QualType(T2, 0), /*Unqualified=*/true) .getTypePtr(); - - // A NestedNameSpecifier has special normalization rules for certain types. - switch (T->getTypeClass()) { - case Type::Elaborated: { - // An ElaboratedType is stripped off, it's Qualifier becomes the prefix. - auto *ET = cast(T); - R = NestedNameSpecifier::Create(Ctx, ET->getQualifier(), - ET->getNamedType().getTypePtr()); - break; - } - case Type::DependentName: { - // A DependentName is turned into an Identifier NNS. - auto *DN = cast(T); - R = NestedNameSpecifier::Create(Ctx, DN->getQualifier(), - DN->getIdentifier()); - break; - } - case Type::DependentTemplateSpecialization: { - // A DependentTemplateSpecializationType loses it's Qualifier, which - // is turned into the prefix. - auto *DTST = cast(T); - const DependentTemplateStorage &DTN = DTST->getDependentTemplateName(); - DependentTemplateStorage NewDTN(/*Qualifier=*/nullptr, DTN.getName(), - DTN.hasTemplateKeyword()); - T = Ctx.getDependentTemplateSpecializationType(DTST->getKeyword(), NewDTN, - DTST->template_arguments()) - .getTypePtr(); - R = NestedNameSpecifier::Create(Ctx, DTN.getQualifier(), T); - break; - } - default: - R = NestedNameSpecifier::Create(Ctx, /*Prefix=*/nullptr, T); - break; - } + R = NestedNameSpecifier(T); break; } - case NestedNameSpecifier::SpecifierKind::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: { // FIXME: Can __super even be used with data members? // If it's only usable in functions, we will never see it here, // unless we save the qualifiers used in function types. // In that case, it might be possible NNS2 is a type, // in which case we should degrade the result to // a CXXRecordType. - return Ctx.getCanonicalNestedNameSpecifier(NNS1); - case NestedNameSpecifier::SpecifierKind::Global: - // The global NNS is a singleton. - assert(K2 == NestedNameSpecifier::SpecifierKind::Global && - "Global NNS cannot be equivalent to any other kind"); - llvm_unreachable("Global NestedNameSpecifiers did not compare equal"); - } - assert(Ctx.getCanonicalNestedNameSpecifier(R) == Canon); + R = NestedNameSpecifier(getCommonDeclChecked(NNS1.getAsMicrosoftSuper(), + NNS2.getAsMicrosoftSuper())); + break; + } + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + // These are singletons. + llvm_unreachable("singletons did not compare equal"); + } + assert(R.getCanonical() == Canon); return R; } template -static NestedNameSpecifier *getCommonQualifier(ASTContext &Ctx, const T *X, - const T *Y, bool IsSame) { +static NestedNameSpecifier getCommonQualifier(const ASTContext &Ctx, const T *X, + const T *Y, bool IsSame) { return ::getCommonNNS(Ctx, X->getQualifier(), Y->getQualifier(), IsSame); } template -static QualType getCommonElementType(ASTContext &Ctx, const T *X, const T *Y) { +static QualType getCommonElementType(const ASTContext &Ctx, const T *X, + const T *Y) { return Ctx.getCommonSugaredType(X->getElementType(), Y->getElementType()); } template -static QualType getCommonArrayElementType(ASTContext &Ctx, const T *X, +static QualType getCommonArrayElementType(const ASTContext &Ctx, const T *X, Qualifiers &QX, const T *Y, Qualifiers &QY) { QualType EX = X->getElementType(), EY = Y->getElementType(); diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index ee09b92715b93..d7fd411ab464c 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -458,13 +458,12 @@ void clang::FormatASTNodeDiagnosticArgument( ND->getNameForDiagnostic(OS, Context.getPrintingPolicy(), Qualified); break; } - case DiagnosticsEngine::ak_nestednamespec: { - NestedNameSpecifier *NNS = reinterpret_cast(Val); - NNS->print(OS, Context.getPrintingPolicy(), + case DiagnosticsEngine::ak_nestednamespec: + NestedNameSpecifier::getFromVoidPointer(reinterpret_cast(Val)) + .print(OS, Context.getPrintingPolicy(), /*ResolveTemplateArguments=*/false, /*PrintFinalScopeResOp=*/false); break; - } case DiagnosticsEngine::ak_declcontext: { DeclContext *DC = reinterpret_cast (Val); assert(DC && "Should never have a null declaration context"); diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 46d64b16a7624..ced24c4522db3 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -9972,46 +9972,34 @@ Expected ASTImporter::Import(Stmt *FromS) { return ToSOrErr; } -Expected -ASTImporter::Import(NestedNameSpecifier *FromNNS) { - if (!FromNNS) - return nullptr; - - NestedNameSpecifier *Prefix = nullptr; - if (Error Err = importInto(Prefix, FromNNS->getPrefix())) - return std::move(Err); - - switch (FromNNS->getKind()) { - case NestedNameSpecifier::Identifier: - assert(FromNNS->getAsIdentifier() && "NNS should contain identifier."); - return NestedNameSpecifier::Create(ToContext, Prefix, - Import(FromNNS->getAsIdentifier())); - - case NestedNameSpecifier::Namespace: - if (ExpectedDecl NSOrErr = Import(FromNNS->getAsNamespace())) { - return NestedNameSpecifier::Create(ToContext, Prefix, - cast(*NSOrErr)); - } else +Expected ASTImporter::Import(NestedNameSpecifier FromNNS) { + switch (FromNNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + return FromNNS; + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = FromNNS.getAsNamespaceAndPrefix(); + auto NSOrErr = Import(Namespace); + if (!NSOrErr) return NSOrErr.takeError(); - - case NestedNameSpecifier::Global: - return NestedNameSpecifier::GlobalSpecifier(ToContext); - - case NestedNameSpecifier::Super: - if (ExpectedDecl RDOrErr = Import(FromNNS->getAsRecordDecl())) - return NestedNameSpecifier::SuperSpecifier(ToContext, - cast(*RDOrErr)); + auto PrefixOrErr = Import(Prefix); + if (!PrefixOrErr) + return PrefixOrErr.takeError(); + return NestedNameSpecifier(ToContext, cast(*NSOrErr), + Prefix); + } + case NestedNameSpecifier::Kind::MicrosoftSuper: + if (ExpectedDecl RDOrErr = Import(FromNNS.getAsMicrosoftSuper())) + return NestedNameSpecifier(cast(*RDOrErr)); else return RDOrErr.takeError(); - - case NestedNameSpecifier::TypeSpec: - if (ExpectedTypePtr TyOrErr = Import(FromNNS->getAsType())) { - return NestedNameSpecifier::Create(ToContext, Prefix, *TyOrErr); + case NestedNameSpecifier::Kind::Type: + if (ExpectedTypePtr TyOrErr = Import(FromNNS.getAsType())) { + return NestedNameSpecifier(*TyOrErr); } else { return TyOrErr.takeError(); } } - llvm_unreachable("Invalid nested name specifier kind"); } @@ -10025,64 +10013,62 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { // serialization in reverse order. while (NNS) { NestedNames.push_back(NNS); - NNS = NNS.getPrefix(); + NNS = NNS.getAsNamespaceAndPrefix().Prefix; } NestedNameSpecifierLocBuilder Builder; while (!NestedNames.empty()) { NNS = NestedNames.pop_back_val(); - NestedNameSpecifier *Spec = nullptr; + NestedNameSpecifier Spec = std::nullopt; if (Error Err = importInto(Spec, NNS.getNestedNameSpecifier())) return std::move(Err); - NestedNameSpecifier::SpecifierKind Kind = Spec->getKind(); + NestedNameSpecifier::Kind Kind = Spec.getKind(); SourceLocation ToLocalBeginLoc, ToLocalEndLoc; - if (Kind != NestedNameSpecifier::Super) { + if (Kind != NestedNameSpecifier::Kind::MicrosoftSuper) { if (Error Err = importInto(ToLocalBeginLoc, NNS.getLocalBeginLoc())) return std::move(Err); - if (Kind != NestedNameSpecifier::Global) + if (Kind != NestedNameSpecifier::Kind::Global) if (Error Err = importInto(ToLocalEndLoc, NNS.getLocalEndLoc())) return std::move(Err); } switch (Kind) { - case NestedNameSpecifier::Identifier: - Builder.Extend(getToContext(), Spec->getAsIdentifier(), ToLocalBeginLoc, - ToLocalEndLoc); - break; - - case NestedNameSpecifier::Namespace: - Builder.Extend(getToContext(), Spec->getAsNamespace(), ToLocalBeginLoc, - ToLocalEndLoc); + case NestedNameSpecifier::Kind::Namespace: + Builder.Extend(getToContext(), Spec.getAsNamespaceAndPrefix().Namespace, + ToLocalBeginLoc, ToLocalEndLoc); break; - case NestedNameSpecifier::TypeSpec: { + case NestedNameSpecifier::Kind::Type: { SourceLocation ToTLoc; - if (Error Err = importInto(ToTLoc, NNS.getTypeLoc().getBeginLoc())) + if (Error Err = importInto(ToTLoc, NNS.castAsTypeLoc().getBeginLoc())) return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( - QualType(Spec->getAsType(), 0), ToTLoc); - Builder.Extend(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); + QualType(Spec.getAsType(), 0), ToTLoc); + Builder.Make(getToContext(), TSI->getTypeLoc(), ToLocalEndLoc); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: Builder.MakeGlobal(getToContext(), ToLocalBeginLoc); break; - case NestedNameSpecifier::Super: { + case NestedNameSpecifier::Kind::MicrosoftSuper: { auto ToSourceRangeOrErr = Import(NNS.getSourceRange()); if (!ToSourceRangeOrErr) return ToSourceRangeOrErr.takeError(); - Builder.MakeSuper(getToContext(), Spec->getAsRecordDecl(), - ToSourceRangeOrErr->getBegin(), - ToSourceRangeOrErr->getEnd()); + Builder.MakeMicrosoftSuper(getToContext(), Spec.getAsMicrosoftSuper(), + ToSourceRangeOrErr->getBegin(), + ToSourceRangeOrErr->getEnd()); + break; + } + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - } } return Builder.getWithLocInContext(getToContext()); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index f7c8c14d071e4..dd42a99ccd19c 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -110,8 +110,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const TemplateArgumentLoc &Arg1, const TemplateArgumentLoc &Arg2); static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2); + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2); static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, const IdentifierInfo *Name2); @@ -577,35 +577,30 @@ static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, /// Determine whether two nested-name-specifiers are equivalent. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, - NestedNameSpecifier *NNS1, - NestedNameSpecifier *NNS2) { - if (NNS1->getKind() != NNS2->getKind()) - return false; - - NestedNameSpecifier *Prefix1 = NNS1->getPrefix(), - *Prefix2 = NNS2->getPrefix(); - if ((bool)Prefix1 != (bool)Prefix2) - return false; - - if (Prefix1) - if (!IsStructurallyEquivalent(Context, Prefix1, Prefix2)) - return false; - - switch (NNS1->getKind()) { - case NestedNameSpecifier::Identifier: - return IsStructurallyEquivalent(NNS1->getAsIdentifier(), - NNS2->getAsIdentifier()); - case NestedNameSpecifier::Namespace: - return IsStructurallyEquivalent(Context, NNS1->getAsNamespace(), - NNS2->getAsNamespace()); - case NestedNameSpecifier::TypeSpec: - return IsStructurallyEquivalent(Context, QualType(NNS1->getAsType(), 0), - QualType(NNS2->getAsType(), 0)); - case NestedNameSpecifier::Global: + NestedNameSpecifier NNS1, + NestedNameSpecifier NNS2) { + auto Kind = NNS1.getKind(); + if (Kind != NNS2.getKind()) + return false; + switch (Kind) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: return true; - case NestedNameSpecifier::Super: - return IsStructurallyEquivalent(Context, NNS1->getAsRecordDecl(), - NNS2->getAsRecordDecl()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace1, Prefix1] = NNS1.getAsNamespaceAndPrefix(); + auto [Namespace2, Prefix2] = NNS2.getAsNamespaceAndPrefix(); + if (!IsStructurallyEquivalent(Context, + const_cast(Namespace1), + const_cast(Namespace2))) + return false; + return IsStructurallyEquivalent(Context, Prefix1, Prefix2); + } + case NestedNameSpecifier::Kind::Type: + return IsStructurallyEquivalent(Context, QualType(NNS1.getAsType(), 0), + QualType(NNS2.getAsType(), 0)); + case NestedNameSpecifier::Kind::MicrosoftSuper: + return IsStructurallyEquivalent(Context, NNS1.getAsMicrosoftSuper(), + NNS2.getAsMicrosoftSuper()); } return false; } @@ -613,9 +608,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const DependentTemplateStorage &S1, const DependentTemplateStorage &S2) { - if (NestedNameSpecifier *NNS1 = S1.getQualifier(), *NNS2 = S2.getQualifier(); - !NNS1 != !NNS2 || - (NNS1 && !IsStructurallyEquivalent(Context, NNS1, NNS2))) + if (!IsStructurallyEquivalent(Context, S1.getQualifier(), S2.getQualifier())) return false; IdentifierOrOverloadedOperator IO1 = S1.getName(), IO2 = S2.getName(); diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 99916f523aa95..d2f7fdbbad04d 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -194,8 +194,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS, else if (const NestedNameSpecifier *NNS = get()) NNS->print(OS, PP); else if (const NestedNameSpecifierLoc *NNSL = get()) { - if (const NestedNameSpecifier *NNS = NNSL->getNestedNameSpecifier()) - NNS->print(OS, PP); + if (NestedNameSpecifier NNS = NNSL->getNestedNameSpecifier()) + NNS.print(OS, PP); else OS << "(empty NestedNameSpecifierLoc)"; } else if (const QualType *QT = get()) @@ -234,13 +234,39 @@ void DynTypedNode::dump(llvm::raw_ostream &OS, OS << "Unable to dump values of type " << NodeKind.asStringRef() << "\n"; } -SourceRange DynTypedNode::getSourceRange() const { +SourceRange DynTypedNode::getSourceRange(bool IncludeQualifier) const { if (const CXXCtorInitializer *CCI = get()) return CCI->getSourceRange(); if (const NestedNameSpecifierLoc *NNSL = get()) return NNSL->getSourceRange(); - if (const TypeLoc *TL = get()) - return TL->getSourceRange(); + if (const TypeLoc *TL = get()) { + if (IncludeQualifier) + return TL->getSourceRange(); + switch (TL->getTypeLocClass()) { + case TypeLoc::DependentName: + return TL->castAs().getNameLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = TL->castAs(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = TL->castAs(); + return SourceRange(T.getTemplateNameLoc(), T.getEndLoc()); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return TL->castAs().getNameLoc(); + case TypeLoc::Typedef: + return TL->castAs().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return TL->castAs().getNameLoc(); + case TypeLoc::Using: + return TL->castAs().getNameLoc(); + default: + return TL->getSourceRange(); + } + } if (const Decl *D = get()) return D->getSourceRange(); if (const Stmt *S = get()) diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 698b956214309..e95bcd75634fa 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -500,9 +500,8 @@ ExprDependence clang::computeDependence(OMPIteratorExpr *E) { ExprDependence clang::computeDependence(DeclRefExpr *E, const ASTContext &Ctx) { auto Deps = ExprDependence::None; - if (auto *NNS = E->getQualifier()) - Deps |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); if (auto *FirstArg = E->getTemplateArgs()) { unsigned NumArgs = E->getNumTemplateArgs(); @@ -673,9 +672,8 @@ ExprDependence clang::computeDependence(MemberExpr *E) { auto D = E->getBase()->getDependence(); D |= getDependenceInExpr(E->getMemberNameInfo()); - if (auto *NNS = E->getQualifier()) - D |= toExprDependence(NNS->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (const auto &A : E->template_arguments()) D |= toExprDependence(A.getArgument().getDependence()); @@ -783,9 +781,8 @@ ExprDependence clang::computeDependence(CXXPseudoDestructorExpr *E) { if (auto *ST = E->getScopeTypeInfo()) D |= turnTypeToValueDependence( toExprDependenceAsWritten(ST->getType()->getDependence())); - if (auto *Q = E->getQualifier()) - D |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + D |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); return D; } @@ -801,9 +798,8 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, if (KnownContainsUnexpandedParameterPack) Deps |= ExprDependence::UnexpandedPack; Deps |= getDependenceInExpr(E->getNameInfo()); - if (auto *Q = E->getQualifier()) - Deps |= toExprDependence(Q->getDependence() & - ~NestedNameSpecifierDependence::Dependent); + Deps |= toExprDependence(E->getQualifier().getDependence() & + ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || isa(D)) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 891f0f3a0b45b..69ee5cc20710c 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1880,18 +1880,13 @@ bool NamedDecl::declarationReplaces(const NamedDecl *OldD, // Using declarations can be replaced if they import the same name from the // same context. - if (const auto *UD = dyn_cast(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast(OldD)->getQualifier()); - } - if (const auto *UUVD = dyn_cast(this)) { - ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) == - Context.getCanonicalNestedNameSpecifier( - cast(OldD)->getQualifier()); - } + if (const auto *UD = dyn_cast(this)) + return UD->getQualifier().getCanonical() == + + cast(OldD)->getQualifier().getCanonical(); + if (const auto *UUVD = dyn_cast(this)) + return UUVD->getQualifier().getCanonical() == + cast(OldD)->getQualifier().getCanonical(); if (isRedeclarable(getKind())) { if (getCanonicalDecl() != OldD->getCanonicalDecl()) diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 7393233a64080..ca1d601370f23 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -708,11 +708,8 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto += D->getQualifiedNameAsString(); } else { llvm::raw_string_ostream OS(Proto); - if (!Policy.SuppressScope) { - if (const NestedNameSpecifier *NS = D->getQualifier()) { - NS->print(OS, Policy); - } - } + if (!Policy.SuppressScope) + D->getQualifier().print(OS, Policy); D->getNameInfo().printName(OS, Policy); } diff --git a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp index f5c42b8fec1bc..8821cd332e918 100644 --- a/clang/lib/AST/DynamicRecursiveASTVisitor.cpp +++ b/clang/lib/AST/DynamicRecursiveASTVisitor.cpp @@ -176,7 +176,7 @@ template struct Impl : RecursiveASTVisitor> { return Visitor.TraverseLambdaCapture(LE, C, Init); } - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) { return Visitor.TraverseNestedNameSpecifier(NNS); } @@ -301,7 +301,6 @@ FORWARD_TO_BASE(TraverseAttr, Attr, *) FORWARD_TO_BASE(TraverseConstructorInitializer, CXXCtorInitializer, *) FORWARD_TO_BASE(TraverseDecl, Decl, *) FORWARD_TO_BASE(TraverseStmt, Stmt, *) -FORWARD_TO_BASE(TraverseNestedNameSpecifier, NestedNameSpecifier, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, ClassTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, VarTemplateDecl, *) FORWARD_TO_BASE(TraverseTemplateInstantiations, FunctionTemplateDecl, *) @@ -318,8 +317,22 @@ FORWARD_TO_BASE_EXACT(TraverseTemplateArgument, const TemplateArgument &) FORWARD_TO_BASE_EXACT(TraverseTemplateArguments, ArrayRef) FORWARD_TO_BASE_EXACT(TraverseTemplateArgumentLoc, const TemplateArgumentLoc &) FORWARD_TO_BASE_EXACT(TraverseTemplateName, TemplateName) -FORWARD_TO_BASE_EXACT(TraverseType, QualType) -FORWARD_TO_BASE_EXACT(TraverseTypeLoc, TypeLoc) +FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifier, NestedNameSpecifier) + +template +bool DynamicRecursiveASTVisitorBase::TraverseType( + QualType T, bool TraverseQualifier) { + return Impl(*this).RecursiveASTVisitor>::TraverseType( + T, TraverseQualifier); +} + +template +bool DynamicRecursiveASTVisitorBase::TraverseTypeLoc( + TypeLoc TL, bool TraverseQualifier) { + return Impl(*this).RecursiveASTVisitor>::TraverseTypeLoc( + TL, TraverseQualifier); +} + FORWARD_TO_BASE_EXACT(TraverseTypeConstraint, const TypeConstraint *) FORWARD_TO_BASE_EXACT(TraverseObjCProtocolLoc, ObjCProtocolLoc) FORWARD_TO_BASE_EXACT(TraverseNestedNameSpecifierLoc, NestedNameSpecifierLoc) diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 0d17fff38152a..21640c87ab424 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -1675,10 +1675,9 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() { // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; - auto *NNS = getQualifier(); - if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { - const Type *T = getQualifier()->getAsType(); - assert(T && "qualifier in member expression does not name type"); + if (NestedNameSpecifier Qualifier = getQualifier(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type) { + const Type *T = getQualifier().getAsType(); Record = T->getAsCXXRecordDecl(); assert(Record && "qualifier in member expression does not name record"); } diff --git a/clang/lib/AST/ExprConcepts.cpp b/clang/lib/AST/ExprConcepts.cpp index ac0e566fe6e72..36f910da49bfb 100644 --- a/clang/lib/AST/ExprConcepts.cpp +++ b/clang/lib/AST/ExprConcepts.cpp @@ -41,10 +41,10 @@ ConceptSpecializationExpr::ConceptSpecializationExpr( assert(!Loc->getNestedNameSpecifierLoc() || (!Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->isInstantiationDependent() && + .isInstantiationDependent() && !Loc->getNestedNameSpecifierLoc() .getNestedNameSpecifier() - ->containsUnexpandedParameterPack())); + .containsUnexpandedParameterPack())); assert((!isValueDependent() || isInstantiationDependent()) && "should not be value-dependent"); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 0e5a0d5db8e8c..a3f8000e8c5f9 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -463,9 +463,7 @@ class CXXNameMangler { void mangleVendorType(StringRef Name); private: - bool mangleSubstitution(const NamedDecl *ND); - bool mangleSubstitution(NestedNameSpecifier *NNS); bool mangleSubstitution(QualType T); bool mangleSubstitution(TemplateName Template); bool mangleSubstitution(uintptr_t Ptr); @@ -479,21 +477,15 @@ class CXXNameMangler { addSubstitution(reinterpret_cast(ND)); } - void addSubstitution(NestedNameSpecifier *NNS) { - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - - addSubstitution(reinterpret_cast(NNS)); - } void addSubstitution(QualType T); void addSubstitution(TemplateName Template); void addSubstitution(uintptr_t Ptr); // Destructive copy substitutions from other mangler. void extendSubstitutions(CXXNameMangler* Other); - void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + void mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive = false); - void mangleUnresolvedName(NestedNameSpecifier *qualifier, - DeclarationName name, + void mangleUnresolvedName(NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned KnownArity = UnknownArity); @@ -542,7 +534,7 @@ class CXXNameMangler { void mangleNestedNameWithClosurePrefix(GlobalDecl GD, const NamedDecl *PrefixND, const AbiTagList *AdditionalAbiTags); - void manglePrefix(NestedNameSpecifier *qualifier); + void manglePrefix(NestedNameSpecifier Qualifier); void manglePrefix(const DeclContext *DC, bool NoFunction=false); void manglePrefix(QualType type); void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false); @@ -588,12 +580,10 @@ class CXXNameMangler { void mangleMemberExprBase(const Expr *base, bool isArrow); void mangleMemberExpr(const Expr *base, bool isArrow, - NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, - DeclarationName name, + NestedNameSpecifier Qualifier, + NamedDecl *firstQualifierLookup, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, - unsigned NumTemplateArgs, - unsigned knownArity); + unsigned NumTemplateArgs, unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleInitListElements(const InitListExpr *InitList); void mangleRequirement(SourceLocation RequiresExprLoc, @@ -1360,7 +1350,7 @@ void CXXNameMangler::manglePrefix(QualType type) { /// /// \param recursive - true if this is being called recursively, /// i.e. if there is more prefix "to the right". -void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier Qualifier, bool recursive) { // x, ::x @@ -1377,8 +1367,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // ::= [gs] sr + E // - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); + + case NestedNameSpecifier::Kind::Global: Out << "gs"; // We want an 'sr' unless this is the entire NNS. @@ -1388,27 +1381,29 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // We never want an 'E' here. return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + if (Prefix) + mangleUnresolvedPrefix(Prefix, /*recursive*/ true); else Out << "sr"; - mangleSourceNameWithAbiTags(qualifier->getAsNamespace()); + mangleSourceNameWithAbiTags(Namespace); break; + } - case NestedNameSpecifier::TypeSpec: { - const Type *type = qualifier->getAsType(); + case NestedNameSpecifier::Kind::Type: { + const Type *type = Qualifier.getAsType(); // We only want to use an unresolved-type encoding if this is one of: // - a decltype // - a template type parameter // - a template template parameter with arguments // In all of these cases, we should have no prefix. - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { + if (NestedNameSpecifier Prefix = type->getPrefix()) { mangleUnresolvedPrefix(Prefix, /*recursive=*/true); } else { @@ -1421,18 +1416,6 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, break; } - - case NestedNameSpecifier::Identifier: - // Member expressions can have these without prefixes. - if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), - /*recursive*/ true); - else - Out << "sr"; - - mangleSourceName(qualifier->getAsIdentifier()); - // An Identifier has no type information, so we can't emit abi tags for it. - break; } // If this was the innermost part of the NNS, and we fell out to @@ -1444,10 +1427,11 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, /// Mangle an unresolved-name, which is generally used for names which /// weren't resolved to specific entities. void CXXNameMangler::mangleUnresolvedName( - NestedNameSpecifier *qualifier, DeclarationName name, + NestedNameSpecifier Qualifier, DeclarationName name, const TemplateArgumentLoc *TemplateArgs, unsigned NumTemplateArgs, unsigned knownArity) { - if (qualifier) mangleUnresolvedPrefix(qualifier); + if (Qualifier) + mangleUnresolvedPrefix(Qualifier); switch (name.getNameKind()) { // ::= case DeclarationName::Identifier: @@ -2185,49 +2169,22 @@ void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) { Lambda->getLambdaStaticInvoker()); } -void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { - switch (qualifier->getKind()) { - case NestedNameSpecifier::Global: +void CXXNameMangler::manglePrefix(NestedNameSpecifier Qualifier) { + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: // nothing return; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: llvm_unreachable("Can't mangle __super specifier"); - case NestedNameSpecifier::Namespace: - mangleName(qualifier->getAsNamespace()->getNamespace()); + case NestedNameSpecifier::Kind::Namespace: + mangleName(Qualifier.getAsNamespaceAndPrefix().Namespace->getNamespace()); return; - case NestedNameSpecifier::TypeSpec: - if (NestedNameSpecifier *Prefix = qualifier->getPrefix()) { - const auto *DTST = - cast(qualifier->getAsType()); - QualType NewT = getASTContext().getDependentTemplateSpecializationType( - DTST->getKeyword(), - {Prefix, DTST->getDependentTemplateName().getName(), - /*HasTemplateKeyword=*/true}, - DTST->template_arguments(), /*IsCanonical=*/true); - manglePrefix(NewT); - return; - } - manglePrefix(QualType(qualifier->getAsType(), 0)); - return; - - case NestedNameSpecifier::Identifier: - // Clang 14 and before did not consider this substitutable. - bool Clang14Compat = isCompatibleWith(LangOptions::ClangABI::Ver14); - if (!Clang14Compat && mangleSubstitution(qualifier)) - return; - - // Member expressions can have these without prefixes, but that - // should end up in mangleUnresolvedPrefix instead. - assert(qualifier->getPrefix()); - manglePrefix(qualifier->getPrefix()); - - mangleSourceName(qualifier->getAsIdentifier()); - - if (!Clang14Compat) - addSubstitution(qualifier); + case NestedNameSpecifier::Kind::Type: + manglePrefix(QualType(Qualifier.getAsType(), 0)); return; } @@ -2287,8 +2244,7 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { if (!Clang11Compat && mangleSubstitution(Template)) return; - if (NestedNameSpecifier *Qualifier = Dependent->getQualifier()) - manglePrefix(Qualifier); + manglePrefix(Dependent->getQualifier()); if (Clang11Compat && mangleSubstitution(Template)) return; @@ -3892,16 +3848,10 @@ void CXXNameMangler::mangleType(const IncompleteArrayType *T) { // ::= M void CXXNameMangler::mangleType(const MemberPointerType *T) { Out << 'M'; - if (auto *RD = T->getMostRecentCXXRecordDecl()) { + if (auto *RD = T->getMostRecentCXXRecordDecl()) mangleCXXRecordDecl(RD); - } else { - NestedNameSpecifier *NNS = T->getQualifier(); - if (auto *II = NNS->getAsIdentifier()) - mangleType(getASTContext().getDependentNameType( - ElaboratedTypeKeyword::None, NNS->getPrefix(), II)); - else - manglePrefix(NNS); - } + else + mangleType(QualType(T->getQualifier().getAsType(), 0)); QualType PointeeType = T->getPointeeType(); if (const FunctionProtoType *FPT = dyn_cast(PointeeType)) { mangleType(FPT); @@ -4785,9 +4735,8 @@ void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { } /// Mangles a member expression. -void CXXNameMangler::mangleMemberExpr(const Expr *base, - bool isArrow, - NestedNameSpecifier *qualifier, +void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier Qualifier, NamedDecl *firstQualifierLookup, DeclarationName member, const TemplateArgumentLoc *TemplateArgs, @@ -5247,7 +5196,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity, const auto *PDE = cast(E); if (const Expr *Base = PDE->getBase()) mangleMemberExprBase(Base, PDE->isArrow()); - NestedNameSpecifier *Qualifier = PDE->getQualifier(); + NestedNameSpecifier Qualifier = PDE->getQualifier(); if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { if (Qualifier) { mangleUnresolvedPrefix(Qualifier, @@ -7023,14 +6972,6 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { return mangleSubstitution(reinterpret_cast(ND)); } -bool CXXNameMangler::mangleSubstitution(NestedNameSpecifier *NNS) { - assert(NNS->getKind() == NestedNameSpecifier::Identifier && - "mangleSubstitution(NestedNameSpecifier *) is only used for " - "identifier nested name specifiers."); - NNS = Context.getASTContext().getCanonicalNestedNameSpecifier(NNS); - return mangleSubstitution(reinterpret_cast(NNS)); -} - /// Determine whether the given type has any qualifiers that are relevant for /// substitutions. static bool hasMangledSubstitutionQualifiers(QualType T) { diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index 246e5322acb3d..b3f12a1cce2ec 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -898,9 +898,9 @@ void JSONNodeDumper::VisitNamespaceAliasDecl(const NamespaceAliasDecl *NAD) { void JSONNodeDumper::VisitUsingDecl(const UsingDecl *UD) { std::string Name; - if (const NestedNameSpecifier *NNS = UD->getQualifier()) { + if (NestedNameSpecifier Qualifier = UD->getQualifier()) { llvm::raw_string_ostream SOS(Name); - NNS->print(SOS, UD->getASTContext().getPrintingPolicy()); + Qualifier.print(SOS, UD->getASTContext().getPrintingPolicy()); } Name += UD->getNameAsString(); JOS.attribute("name", Name); diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 872983f553e19..c6af91f5c0083 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -34,250 +34,67 @@ using namespace clang; -NestedNameSpecifier * -NestedNameSpecifier::FindOrInsert(const ASTContext &Context, - const NestedNameSpecifier &Mockup) { +const NamespaceAndPrefixStorage * +NestedNameSpecifier::MakeNamespaceAndPrefixStorage( + const ASTContext &Ctx, const NamespaceBaseDecl *Namespace, + NestedNameSpecifier Prefix) { llvm::FoldingSetNodeID ID; - Mockup.Profile(ID); + NamespaceAndPrefixStorage::Profile(ID, Namespace, Prefix); void *InsertPos = nullptr; - NestedNameSpecifier *NNS - = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); - if (!NNS) { - NNS = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(Mockup); - Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); + NamespaceAndPrefixStorage *S = + Ctx.NamespaceAndPrefixStorages.FindNodeOrInsertPos(ID, InsertPos); + if (!S) { + S = new (Ctx, alignof(NamespaceAndPrefixStorage)) + NamespaceAndPrefixStorage(Namespace, Prefix); + Ctx.NamespaceAndPrefixStorages.InsertNode(S, InsertPos); } - - return NNS; -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); - - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const NamespaceBaseDecl *NS) { - assert(NS && "Namespace cannot be NULL"); - assert((!Prefix || - (Prefix->getAsType() == nullptr && - Prefix->getAsIdentifier() == nullptr)) && - "Broken nested name specifier"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = const_cast(NS); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, - const Type *T) { - assert(T && "Type cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredTypeSpec); - Mockup.Specifier = const_cast(T); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, - const IdentifierInfo *II) { - assert(II && "Identifier cannot be NULL"); - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = const_cast(II); - return FindOrInsert(Context, Mockup); -} - -NestedNameSpecifier * -NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { - if (!Context.GlobalNestedNameSpecifier) - Context.GlobalNestedNameSpecifier = - new (Context, alignof(NestedNameSpecifier)) NestedNameSpecifier(); - return Context.GlobalNestedNameSpecifier; -} - -NestedNameSpecifier * -NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, - CXXRecordDecl *RD) { - NestedNameSpecifier Mockup; - Mockup.Prefix.setPointer(nullptr); - Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = RD; - return FindOrInsert(Context, Mockup); + return S; } -NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { - if (!Specifier) - return Global; - - switch (Prefix.getInt()) { - case StoredIdentifier: - return Identifier; - - case StoredDecl: { - NamedDecl *ND = static_cast(Specifier); - return isa(ND) ? Super : Namespace; - } - - case StoredTypeSpec: - return TypeSpec; - } - - llvm_unreachable("Invalid NNS Kind!"); -} - -/// Retrieve the namespace or namespace alias stored in this nested name -/// specifier. -NamespaceBaseDecl *NestedNameSpecifier::getAsNamespace() const { - if (Prefix.getInt() == StoredDecl) - return dyn_cast(static_cast(Specifier)); - - return nullptr; -} - -/// Retrieve the record declaration stored in this nested name specifier. -CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { - switch (Prefix.getInt()) { - case StoredIdentifier: - return nullptr; - - case StoredDecl: - return dyn_cast(static_cast(Specifier)); - - case StoredTypeSpec: - return getAsType()->getAsCXXRecordDecl(); +bool NestedNameSpecifier::isFullyQualified() const { + switch (getKind()) { + case NestedNameSpecifier::Kind::Global: + return true; + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::MicrosoftSuper: + return false; + case NestedNameSpecifier::Kind::Namespace: + return getAsNamespaceAndPrefix().Prefix.isFullyQualified(); + case NestedNameSpecifier::Kind::Type: + return getAsType()->getPrefix().isFullyQualified(); } - llvm_unreachable("Invalid NNS Kind!"); } NestedNameSpecifierDependence NestedNameSpecifier::getDependence() const { switch (getKind()) { - case Identifier: { - // Identifier specifiers always represent dependent types - auto F = NestedNameSpecifierDependence::Dependent | - NestedNameSpecifierDependence::Instantiation; - // Prefix can contain unexpanded template parameters. - if (getPrefix()) - return F | getPrefix()->getDependence(); - return F; - } - - case Namespace: - case Global: - return NestedNameSpecifierDependence::None; - - case Super: { - CXXRecordDecl *RD = static_cast(Specifier); - for (const auto &Base : RD->bases()) - if (Base.getType()->isDependentType()) - // FIXME: must also be instantiation-dependent. - return NestedNameSpecifierDependence::Dependent; + case Kind::Null: + case Kind::Global: + case Kind::Namespace: return NestedNameSpecifierDependence::None; + case Kind::MicrosoftSuper: { + CXXRecordDecl *RD = getAsMicrosoftSuper(); + return RD->isDependentContext() + ? NestedNameSpecifierDependence::DependentInstantiation | + NestedNameSpecifierDependence::Dependent + : NestedNameSpecifierDependence::None; } - - case TypeSpec: { - NestedNameSpecifierDependence Dep = - toNestedNameSpecifierDependendence(getAsType()->getDependence()); - if (NestedNameSpecifier *Prefix = getPrefix()) - Dep |= - Prefix->getDependence() & ~NestedNameSpecifierDependence::Dependent; - return Dep; - } + case Kind::Type: + return toNestedNameSpecifierDependence(getAsType()->getDependence()); } llvm_unreachable("Invalid NNS Kind!"); } -bool NestedNameSpecifier::isDependent() const { - return getDependence() & NestedNameSpecifierDependence::Dependent; -} - -bool NestedNameSpecifier::isInstantiationDependent() const { - return getDependence() & NestedNameSpecifierDependence::Instantiation; -} - -bool NestedNameSpecifier::containsUnexpandedParameterPack() const { - return getDependence() & NestedNameSpecifierDependence::UnexpandedPack; -} - -bool NestedNameSpecifier::containsErrors() const { - return getDependence() & NestedNameSpecifierDependence::Error; -} - -const Type * -NestedNameSpecifier::translateToType(const ASTContext &Context) const { - NestedNameSpecifier *Prefix = getPrefix(); - switch (getKind()) { - case SpecifierKind::Identifier: - return Context - .getDependentNameType(ElaboratedTypeKeyword::None, Prefix, - getAsIdentifier()) - .getTypePtr(); - case SpecifierKind::TypeSpec: { - const Type *T = getAsType(); - switch (T->getTypeClass()) { - case Type::DependentTemplateSpecialization: { - const auto *DT = cast(T); - const DependentTemplateStorage &DTN = DT->getDependentTemplateName(); - return Context - .getDependentTemplateSpecializationType( - ElaboratedTypeKeyword::None, - {Prefix, DTN.getName(), DTN.hasTemplateKeyword()}, - DT->template_arguments()) - .getTypePtr(); - } - case Type::Record: - case Type::TemplateSpecialization: - case Type::Using: - case Type::Enum: - case Type::Typedef: - case Type::UnresolvedUsing: - return Context - .getElaboratedType(ElaboratedTypeKeyword::None, Prefix, - QualType(T, 0)) - .getTypePtr(); - default: - assert(Prefix == nullptr && "unexpected type with elaboration"); - return T; - } - } - case SpecifierKind::Global: - case SpecifierKind::Namespace: - case SpecifierKind::Super: - // These are not representable as types. - return nullptr; - } - llvm_unreachable("Unhandled SpecifierKind enum"); -} - /// Print this nested name specifier to the given output /// stream. void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, bool ResolveTemplateArguments, bool PrintFinalScopeResOp) const { - if (getPrefix()) - getPrefix()->print(OS, Policy); - switch (getKind()) { - case Identifier: - OS << getAsIdentifier()->getName(); - break; - - case Namespace: { - NamespaceBaseDecl *Namespace = getAsNamespace(); + case Kind::Namespace: { + auto [Namespace, Prefix] = getAsNamespaceAndPrefix(); + Prefix.print(OS, Policy); if (const auto *NS = dyn_cast(Namespace)) { assert(!NS->isAnonymousNamespace()); OS << NS->getName(); @@ -286,134 +103,49 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy, } break; } - - case Global: + case Kind::Global: OS << "::"; return; - - case Super: + case Kind::MicrosoftSuper: OS << "__super"; break; - - case TypeSpec: { + case Kind::Type: { PrintingPolicy InnerPolicy(Policy); - InnerPolicy.SuppressScope = true; InnerPolicy.SuppressTagKeyword = true; QualType(getAsType(), 0).print(OS, InnerPolicy); break; } + case Kind::Null: + return; } - if (PrintFinalScopeResOp) OS << "::"; } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { - dump(llvm::errs(), LO); +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream *OS, + const LangOptions *LO) const { + print(OS ? *OS : llvm::errs(), LO ? *LO : LangOptions()); } -LLVM_DUMP_METHOD void NestedNameSpecifier::dump() const { dump(llvm::errs()); } - +LLVM_DUMP_METHOD void NestedNameSpecifier::dump(const LangOptions &LO) const { + dump(/*OS=*/nullptr, &LO); +} LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS) const { - LangOptions LO; - dump(OS, LO); + dump(&OS); } - LLVM_DUMP_METHOD void NestedNameSpecifier::dump(llvm::raw_ostream &OS, const LangOptions &LO) const { - print(OS, PrintingPolicy(LO)); -} - -unsigned -NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { - assert(Qualifier && "Expected a non-NULL qualifier"); - - // Location of the trailing '::'. - unsigned Length = sizeof(SourceLocation::UIntTy); - - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - // Nothing more to add. - break; - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Super: - // The location of the identifier or namespace name. - Length += sizeof(SourceLocation::UIntTy); - break; - - case NestedNameSpecifier::TypeSpec: - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - Length += sizeof(void *); - break; - } - - return Length; -} - -unsigned -NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { - unsigned Length = 0; - for (; Qualifier; Qualifier = Qualifier->getPrefix()) - Length += getLocalDataLength(Qualifier); - return Length; -} - -/// Load a (possibly unaligned) source location from a given address -/// and offset. -static SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { - SourceLocation::UIntTy Raw; - memcpy(&Raw, static_cast(Data) + Offset, sizeof(Raw)); - return SourceLocation::getFromRawEncoding(Raw); + dump(&OS, &LO); } -/// Load a (possibly unaligned) pointer from a given address and -/// offset. -static void *LoadPointer(void *Data, unsigned Offset) { - void *Result; - memcpy(&Result, static_cast(Data) + Offset, sizeof(void*)); - return Result; -} - -SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { +SourceLocation NestedNameSpecifierLoc::getBeginLoc() const { if (!Qualifier) - return SourceRange(); - - unsigned Offset = getDataLength(Qualifier->getPrefix()); - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - return LoadSourceLocation(Data, Offset); - - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Super: - return SourceRange( - LoadSourceLocation(Data, Offset), - LoadSourceLocation(Data, Offset + sizeof(SourceLocation::UIntTy))); - - case NestedNameSpecifier::TypeSpec: { - // The "void*" that points at the TypeLoc data. - // Note: the 'template' keyword is part of the TypeLoc. - void *TypeData = LoadPointer(Data, Offset); - TypeLoc TL(Qualifier->getAsType(), TypeData); - return SourceRange(TL.getBeginLoc(), - LoadSourceLocation(Data, Offset + sizeof(void*))); - } - } + return SourceLocation(); - llvm_unreachable("Invalid NNS Kind!"); -} - -TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { - if (Qualifier->getKind() != NestedNameSpecifier::TypeSpec) - return TypeLoc(); - - // The "void*" that points at the TypeLoc data. - unsigned Offset = getDataLength(Qualifier->getPrefix()); - void *TypeData = LoadPointer(Data, Offset); - return TypeLoc(Qualifier->getAsType(), TypeData); + NestedNameSpecifierLoc First = *this; + while (NestedNameSpecifierLoc Prefix = First.getAsNamespaceAndPrefix().Prefix) + First = Prefix; + return First.getLocalSourceRange().getBegin(); } static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, @@ -515,10 +247,10 @@ operator=(const NestedNameSpecifierLocBuilder &Other) { return *this; } -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, - SourceLocation ColonColonLoc) { - Representation = - NestedNameSpecifier::Create(Context, Representation, TL.getTypePtr()); +void NestedNameSpecifierLocBuilder::Make(ASTContext &Context, TypeLoc TL, + SourceLocation ColonColonLoc) { + assert(!Representation); + Representation = NestedNameSpecifier(TL.getTypePtr()); // Push source-location info into the buffer. SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); @@ -526,23 +258,10 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, TypeLoc TL, } void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Identifier); - - // Push source-location info into the buffer. - SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); - SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); -} - -void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, - NamespaceBaseDecl *Namespace, + const NamespaceBaseDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::Create(Context, Representation, - Namespace); + Representation = NestedNameSpecifier(Context, Namespace, Representation); // Push source-location info into the buffer. SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); @@ -552,60 +271,48 @@ void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc) { assert(!Representation && "Already have a nested-name-specifier!?"); - Representation = NestedNameSpecifier::GlobalSpecifier(Context); + Representation = NestedNameSpecifier::getGlobal(); // Push source-location info into the buffer. SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, - CXXRecordDecl *RD, - SourceLocation SuperLoc, - SourceLocation ColonColonLoc) { - Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); +void NestedNameSpecifierLocBuilder::MakeMicrosoftSuper( + ASTContext &Context, CXXRecordDecl *RD, SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier(RD); // Push source-location info into the buffer. SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } -void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, - NestedNameSpecifier *Qualifier, +void NestedNameSpecifierLocBuilder::PushTrivial(ASTContext &Context, + NestedNameSpecifier Qualifier, SourceRange R) { - Representation = Qualifier; - // Construct bogus (but well-formed) source information for the // nested-name-specifier. - BufferSize = 0; - SmallVector Stack; - for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) - Stack.push_back(NNS); - while (!Stack.empty()) { - NestedNameSpecifier *NNS = Stack.pop_back_val(); - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); - break; - - case NestedNameSpecifier::TypeSpec: { - TypeSourceInfo *TSInfo - = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), - R.getBegin()); - SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, - BufferCapacity); - break; - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - break; - } - - // Save the location of the '::'. - SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), - Buffer, BufferSize, BufferCapacity); + switch (Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + return; + case NestedNameSpecifier::Kind::Namespace: { + auto [_1, Prefix] = Qualifier.getAsNamespaceAndPrefix(); + PushTrivial(Context, Prefix, R.getBegin()); + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Type: { + TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo( + QualType(Qualifier.getAsType(), 0), R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + break; } + SaveSourceLocation(R.getEnd(), Buffer, BufferSize, BufferCapacity); } void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index c7a69d7c5ba42..fb95f58092c49 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -111,34 +111,28 @@ void ODRHash::AddDeclarationNameInfoImpl(DeclarationNameInfo NameInfo) { } } -void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - assert(NNS && "Expecting non-null pointer."); - const auto *Prefix = NNS->getPrefix(); - AddBoolean(Prefix); - if (Prefix) { - AddNestedNameSpecifier(Prefix); - } - auto Kind = NNS->getKind(); - ID.AddInteger(Kind); +void ODRHash::AddNestedNameSpecifier(NestedNameSpecifier NNS) { + auto Kind = NNS.getKind(); + ID.AddInteger(llvm::to_underlying(Kind)); switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierInfo(NNS->getAsIdentifier()); - break; - case NestedNameSpecifier::Namespace: - AddDecl(NNS->getAsNamespace()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); + AddDecl(Namespace); + AddNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: - AddType(NNS->getAsType()); + } + case NestedNameSpecifier::Kind::Type: + AddType(NNS.getAsType()); break; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: break; } } void ODRHash::AddDependentTemplateName(const DependentTemplateStorage &Name) { - if (NestedNameSpecifier *NNS = Name.getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(Name.getQualifier()); if (IdentifierOrOverloadedOperator IO = Name.getName(); const IdentifierInfo *II = IO.getIdentifier()) AddIdentifierInfo(II); @@ -156,8 +150,7 @@ void ODRHash::AddTemplateName(TemplateName Name) { break; case TemplateName::QualifiedTemplate: { QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); - if (NestedNameSpecifier *NNS = QTN->getQualifier()) - AddNestedNameSpecifier(NNS); + AddNestedNameSpecifier(QTN->getQualifier()); AddBoolean(QTN->hasTemplateKeyword()); AddTemplateName(QTN->getUnderlyingTemplate()); break; @@ -889,11 +882,8 @@ class ODRTypeVisitor : public TypeVisitor { } } - void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) { - Hash.AddBoolean(NNS); - if (NNS) { - Hash.AddNestedNameSpecifier(NNS); - } + void AddNestedNameSpecifier(NestedNameSpecifier NNS) { + Hash.AddNestedNameSpecifier(NNS); } void AddIdentifierInfo(const IdentifierInfo *II) { diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index de8b5996818de..588b0dcc6d7b8 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -2350,17 +2350,16 @@ void OMPClausePrinter::VisitOMPReductionClause(OMPReductionClause *Node) { if (Node->getModifierLoc().isValid()) OS << getOpenMPSimpleClauseTypeName(OMPC_reduction, Node->getModifier()) << ", "; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2373,17 +2372,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( OMPTaskReductionClause *Node) { if (!Node->varlist_empty()) { OS << "task_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2395,17 +2393,16 @@ void OMPClausePrinter::VisitOMPTaskReductionClause( void OMPClausePrinter::VisitOMPInReductionClause(OMPInReductionClause *Node) { if (!Node->varlist_empty()) { OS << "in_reduction("; - NestedNameSpecifier *QualifierLoc = + NestedNameSpecifier Qualifier = Node->getQualifierLoc().getNestedNameSpecifier(); OverloadedOperatorKind OOK = Node->getNameInfo().getName().getCXXOverloadedOperator(); - if (QualifierLoc == nullptr && OOK != OO_None) { + if (!Qualifier && OOK != OO_None) { // Print reduction identifier in C format OS << getOperatorSpelling(OOK); } else { // Use C++ format - if (QualifierLoc != nullptr) - QualifierLoc->print(OS, Policy); + Qualifier.print(OS, Policy); OS << Node->getNameInfo(); } OS << ":"; @@ -2508,10 +2505,9 @@ template static void PrintMapper(raw_ostream &OS, T *Node, const PrintingPolicy &Policy) { OS << '('; - NestedNameSpecifier *MapperNNS = + NestedNameSpecifier MapperNNS = Node->getMapperQualifierLoc().getNestedNameSpecifier(); - if (MapperNNS) - MapperNNS->print(OS, Policy); + MapperNNS.print(OS, Policy); OS << Node->getMapperIdInfo() << ')'; } diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 68dfe4d5d22cb..acc011cb2faa4 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -438,10 +438,12 @@ class ParentMapContext::ParentMap::ASTVisitor DeclNode, DeclNode, [&] { return VisitorBase::TraverseDecl(DeclNode); }, &Map.PointerParents); } - bool TraverseTypeLoc(TypeLoc TypeLocNode) { + bool TraverseTypeLoc(TypeLoc TypeLocNode, bool TraverseQualifier = true) { return TraverseNode( TypeLocNode, DynTypedNode::create(TypeLocNode), - [&] { return VisitorBase::TraverseTypeLoc(TypeLocNode); }, + [&] { + return VisitorBase::TraverseTypeLoc(TypeLocNode, TraverseQualifier); + }, &Map.OtherParents); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLocNode) { diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index f5ae7686241e0..319becd8a5a98 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -24,10 +24,9 @@ namespace TypeName { /// is requested. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, - const NamespaceDecl *Namesp, - bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namesp, + bool WithGlobalNsPrefix); /// Create a NestedNameSpecifier for TagDecl and its enclosing /// scopes. @@ -39,22 +38,24 @@ static NestedNameSpecifier *createNestedNameSpecifier( /// qualified names. /// \param[in] WithGlobalNsPrefix - Indicate whether the global namespace /// specifier "::" should be prepended or not. -static NestedNameSpecifier *createNestedNameSpecifier( - const ASTContext &Ctx, const TypeDecl *TD, - bool FullyQualify, bool WithGlobalNsPrefix); +static NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *decl, - bool FullyQualified, bool WithGlobalNsPrefix); +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *decl, + bool FullyQualified, + bool WithGlobalNsPrefix); -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *scope, bool WithGlobalNsPrefix); +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier NNS, bool WithGlobalNsPrefix); static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, TemplateName &TName, bool WithGlobalNsPrefix) { bool Changed = false; - NestedNameSpecifier *NNS = nullptr; + NestedNameSpecifier NNS = std::nullopt; TemplateDecl *ArgTDecl = TName.getAsTemplateDecl(); // ArgTDecl won't be NULL because we asserted that this isn't a @@ -65,13 +66,13 @@ static bool getFullyQualifiedTemplateName(const ASTContext &Ctx, if (QTName && !QTName->hasTemplateKeyword() && (NNS = QTName->getQualifier())) { - NestedNameSpecifier *QNNS = getFullyQualifiedNestedNameSpecifier( - Ctx, NNS, WithGlobalNsPrefix); + NestedNameSpecifier QNNS = + getFullyQualifiedNestedNameSpecifier(Ctx, NNS, WithGlobalNsPrefix); if (QNNS != NNS) { Changed = true; NNS = QNNS; } else { - NNS = nullptr; + NNS = std::nullopt; } } else { NNS = createNestedNameSpecifierForScopeOf( @@ -116,76 +117,81 @@ static bool getFullyQualifiedTemplateArgument(const ASTContext &Ctx, } static const Type *getFullyQualifiedTemplateType(const ASTContext &Ctx, - const Type *TypePtr, + const TagType *TSTRecord, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier Qualifier, bool WithGlobalNsPrefix) { - // DependentTemplateTypes exist within template declarations and - // definitions. Therefore we shouldn't encounter them at the end of - // a translation unit. If we do, the caller has made an error. - assert(!isa(TypePtr)); - // In case of template specializations, iterate over the arguments - // and fully qualify them as well. - if (const auto *TST = dyn_cast(TypePtr)) { - bool MightHaveChanged = false; - SmallVector FQArgs; - // Cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument. - for (TemplateArgument Arg : TST->template_arguments()) { - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + // We are asked to fully qualify and we have a Record Type, + // which can point to a template instantiation with no sugar in any of + // its template argument, however we still need to fully qualify them. + + const auto *TD = TSTRecord->getOriginalDecl(); + const auto *TSTDecl = dyn_cast(TD); + if (!TSTDecl) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + + const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); + + bool MightHaveChanged = false; + SmallVector FQArgs; + for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { + // cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument + TemplateArgument Arg(TemplateArgs[I]); + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); + } - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - QualType QT = Ctx.getTemplateSpecializationType( - TST->getTemplateName(), FQArgs, - /*CanonicalArgs=*/{}, TST->desugar()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } else if (const auto *TSTRecord = dyn_cast(TypePtr)) { - // We are asked to fully qualify and we have a Record Type, - // which can point to a template instantiation with no sugar in any of - // its template argument, however we still need to fully qualify them. - - if (const auto *TSTDecl = - dyn_cast(TSTRecord->getDecl())) { - const TemplateArgumentList &TemplateArgs = TSTDecl->getTemplateArgs(); - - bool MightHaveChanged = false; - SmallVector FQArgs; - for (unsigned int I = 0, E = TemplateArgs.size(); I != E; ++I) { - // cheap to copy and potentially modified by - // getFullyQualifedTemplateArgument - TemplateArgument Arg(TemplateArgs[I]); - MightHaveChanged |= getFullyQualifiedTemplateArgument( - Ctx, Arg, WithGlobalNsPrefix); - FQArgs.push_back(Arg); - } + if (!MightHaveChanged) + return Ctx.getTagType(Keyword, Qualifier, TD, /*OwnsTag=*/false) + .getTypePtr(); + // If a fully qualified arg is different from the unqualified arg, + // allocate new type in the AST. + TemplateName TN = Ctx.getQualifiedTemplateName( + Qualifier, /*TemplateKeyword=*/false, + TemplateName(TSTDecl->getSpecializedTemplate())); + QualType QT = Ctx.getTemplateSpecializationType( + Keyword, TN, FQArgs, + /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return QT.getTypePtr(); +} - // If a fully qualified arg is different from the unqualified arg, - // allocate new type in the AST. - if (MightHaveChanged) { - TemplateName TN(TSTDecl->getSpecializedTemplate()); - QualType QT = Ctx.getTemplateSpecializationType( - TN, FQArgs, - /*CanonicalArgs=*/{}, TSTRecord->getCanonicalTypeInternal()); - // getTemplateSpecializationType returns a fully qualified - // version of the specialization itself, so no need to qualify - // it. - return QT.getTypePtr(); - } - } +static const Type * +getFullyQualifiedTemplateType(const ASTContext &Ctx, + const TemplateSpecializationType *TST, + bool WithGlobalNsPrefix) { + TemplateName TName = TST->getTemplateName(); + bool MightHaveChanged = + getFullyQualifiedTemplateName(Ctx, TName, WithGlobalNsPrefix); + SmallVector FQArgs; + // Cheap to copy and potentially modified by + // getFullyQualifedTemplateArgument. + for (TemplateArgument Arg : TST->template_arguments()) { + MightHaveChanged |= + getFullyQualifiedTemplateArgument(Ctx, Arg, WithGlobalNsPrefix); + FQArgs.push_back(Arg); } - return TypePtr; + + if (!MightHaveChanged) + return TST; + + QualType NewQT = + Ctx.getTemplateSpecializationType(TST->getKeyword(), TName, FQArgs, + /*CanonicalArgs=*/{}, TST->desugar()); + // getTemplateSpecializationType returns a fully qualified + // version of the specialization itself, so no need to qualify + // it. + return NewQT.getTypePtr(); } -static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, - bool FullyQualify, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier createOuterNNS(const ASTContext &Ctx, const Decl *D, + bool FullyQualify, + bool WithGlobalNsPrefix) { const DeclContext *DC = D->getDeclContext(); if (const auto *NS = dyn_cast(DC)) { while (NS && NS->isInline()) { @@ -195,71 +201,63 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, if (NS && NS->getDeclName()) { return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); } - return nullptr; // no starting '::', no anonymous - } else if (const auto *TD = dyn_cast(DC)) { - return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast(DC)) { - return createNestedNameSpecifier( - Ctx, TDD, FullyQualify, WithGlobalNsPrefix); - } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return std::nullopt; // no starting '::', no anonymous } - return nullptr; // no starting '::' if |WithGlobalNsPrefix| is false + if (const auto *TD = dyn_cast(DC)) + return createNestedNameSpecifier(Ctx, TD, FullyQualify, WithGlobalNsPrefix); + if (const auto *TDD = dyn_cast(DC)) + return createNestedNameSpecifier(Ctx, TDD, FullyQualify, + WithGlobalNsPrefix); + if (WithGlobalNsPrefix && DC->isTranslationUnit()) + return NestedNameSpecifier::getGlobal(); + return std::nullopt; // no starting '::' if |WithGlobalNsPrefix| is false } /// Return a fully qualified version of this name specifier. -static NestedNameSpecifier *getFullyQualifiedNestedNameSpecifier( - const ASTContext &Ctx, NestedNameSpecifier *Scope, - bool WithGlobalNsPrefix) { - switch (Scope->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - // Already fully qualified - return Scope; - case NestedNameSpecifier::Namespace: - return TypeName::createNestedNameSpecifier( - Ctx, Scope->getAsNamespace()->getNamespace(), WithGlobalNsPrefix); - case NestedNameSpecifier::Identifier: - // A function or some other construct that makes it un-namable - // at the end of the TU. Skip the current component of the name, - // but use the name of it's prefix. - return getFullyQualifiedNestedNameSpecifier( - Ctx, Scope->getPrefix(), WithGlobalNsPrefix); - case NestedNameSpecifier::TypeSpec: { - const Type *Type = Scope->getAsType(); - // Find decl context. - const TagDecl *TD = nullptr; - if (const TagType *TagDeclType = Type->getAs()) { - TD = TagDeclType->getDecl(); - } else { - TD = Type->getAsCXXRecordDecl(); - } - if (TD) { - return TypeName::createNestedNameSpecifier(Ctx, TD, - true /*FullyQualified*/, - WithGlobalNsPrefix); - } else if (const auto *TDD = dyn_cast(Type)) { - return TypeName::createNestedNameSpecifier(Ctx, TDD->getDecl(), - true /*FullyQualified*/, - WithGlobalNsPrefix); - } +static NestedNameSpecifier getFullyQualifiedNestedNameSpecifier( + const ASTContext &Ctx, NestedNameSpecifier Scope, bool WithGlobalNsPrefix) { + switch (Scope.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("can't fully qualify the empty nested name specifier"); + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + // Already fully qualified + return Scope; + case NestedNameSpecifier::Kind::Namespace: + return TypeName::createNestedNameSpecifier( + Ctx, Scope.getAsNamespaceAndPrefix().Namespace->getNamespace(), + WithGlobalNsPrefix); + case NestedNameSpecifier::Kind::Type: { + const Type *Type = Scope.getAsType(); + // Find decl context. + const TypeDecl *TD; + if (const TagType *TagDeclType = Type->getAs()) + TD = TagDeclType->getOriginalDecl(); + else if (const auto *D = dyn_cast(Type)) + TD = D->getDecl(); + else return Scope; - } + return TypeName::createNestedNameSpecifier(Ctx, TD, /*FullyQualify=*/true, + WithGlobalNsPrefix); + } } llvm_unreachable("bad NNS kind"); } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Decl *Decl, - bool FullyQualified, bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Decl *Decl, + bool FullyQualified, + bool WithGlobalNsPrefix) { assert(Decl); const DeclContext *DC = Decl->getDeclContext()->getRedeclContext(); const auto *Outer = dyn_cast(DC); const auto *OuterNS = dyn_cast(DC); - if (Outer && !(OuterNS && OuterNS->isAnonymousNamespace())) { + if (OuterNS && OuterNS->isAnonymousNamespace()) + OuterNS = dyn_cast(OuterNS->getParent()); + if (Outer) { if (const auto *CxxDecl = dyn_cast(DC)) { if (ClassTemplateDecl *ClassTempl = CxxDecl->getDescribedClassTemplate()) { @@ -288,76 +286,80 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( Ctx, TD, FullyQualified, WithGlobalNsPrefix); } else if (isa(Outer)) { // Context is the TU. Nothing needs to be done. - return nullptr; + return std::nullopt; } else { // Decl's context was neither the TU, a namespace, nor a // TagDecl, which means it is a type local to a scope, and not // accessible at the end of the TU. - return nullptr; + return std::nullopt; } } else if (WithGlobalNsPrefix && DC->isTranslationUnit()) { - return NestedNameSpecifier::GlobalSpecifier(Ctx); + return NestedNameSpecifier::getGlobal(); } - return nullptr; + return std::nullopt; } /// Create a nested name specifier for the declaring context of /// the type. -static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( - const ASTContext &Ctx, const Type *TypePtr, - bool FullyQualified, bool WithGlobalNsPrefix) { - if (!TypePtr) return nullptr; +static NestedNameSpecifier +createNestedNameSpecifierForScopeOf(const ASTContext &Ctx, const Type *TypePtr, + bool FullyQualified, + bool WithGlobalNsPrefix) { + if (!TypePtr) + return std::nullopt; Decl *Decl = nullptr; // There are probably other cases ... if (const auto *TDT = dyn_cast(TypePtr)) { Decl = TDT->getDecl(); } else if (const auto *TagDeclType = dyn_cast(TypePtr)) { - Decl = TagDeclType->getDecl(); + Decl = TagDeclType->getOriginalDecl(); } else if (const auto *TST = dyn_cast(TypePtr)) { Decl = TST->getTemplateName().getAsTemplateDecl(); } else { Decl = TypePtr->getAsCXXRecordDecl(); } - if (!Decl) return nullptr; + if (!Decl) + return std::nullopt; return createNestedNameSpecifierForScopeOf( Ctx, Decl, FullyQualified, WithGlobalNsPrefix); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const NamespaceDecl *Namespace, - bool WithGlobalNsPrefix) { +static NestedNameSpecifier +createNestedNameSpecifier(const ASTContext &Ctx, const NamespaceDecl *Namespace, + bool WithGlobalNsPrefix) { while (Namespace && Namespace->isInline()) { // Ignore inline namespace; Namespace = dyn_cast(Namespace->getDeclContext()); } - if (!Namespace) return nullptr; + if (!Namespace) + return std::nullopt; - bool FullyQualified = true; // doesn't matter, DeclContexts are namespaces - return NestedNameSpecifier::Create( - Ctx, - createOuterNNS(Ctx, Namespace, FullyQualified, WithGlobalNsPrefix), - Namespace); + bool FullyQualify = true; // doesn't matter, DeclContexts are namespaces + return NestedNameSpecifier( + Ctx, Namespace, + createOuterNNS(Ctx, Namespace, FullyQualify, WithGlobalNsPrefix)); } -NestedNameSpecifier *createNestedNameSpecifier(const ASTContext &Ctx, - const TypeDecl *TD, - bool FullyQualify, - bool WithGlobalNsPrefix) { - const Type *TypePtr = TD->getTypeForDecl(); - if (isa(TypePtr) || - isa(TypePtr)) { +NestedNameSpecifier createNestedNameSpecifier(const ASTContext &Ctx, + const TypeDecl *TD, + bool FullyQualify, + bool WithGlobalNsPrefix) { + const Type *TypePtr = Ctx.getTypeDeclType(TD).getTypePtr(); + if (auto *RD = dyn_cast(TypePtr)) { // We are asked to fully qualify and we have a Record Type (which // may point to a template specialization) or Template // Specialization Type. We need to fully qualify their arguments. - - TypePtr = getFullyQualifiedTemplateType(Ctx, TypePtr, WithGlobalNsPrefix); + TypePtr = getFullyQualifiedTemplateType( + Ctx, RD, ElaboratedTypeKeyword::None, + createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), + WithGlobalNsPrefix); + } else if (auto *TST = dyn_cast(TypePtr)) { + TypePtr = getFullyQualifiedTemplateType(Ctx, TST, WithGlobalNsPrefix); } - - return NestedNameSpecifier::Create( - Ctx, createOuterNNS(Ctx, TD, FullyQualify, WithGlobalNsPrefix), TypePtr); + return NestedNameSpecifier(TypePtr); } /// Return the fully qualified type, including fully-qualified @@ -381,7 +383,7 @@ QualType getFullyQualifiedType(QualType QT, const ASTContext &Ctx, Qualifiers Quals = QT.getQualifiers(); // Fully qualify the pointee and class types. QT = getFullyQualifiedType(QT->getPointeeType(), Ctx, WithGlobalNsPrefix); - NestedNameSpecifier *Qualifier = getFullyQualifiedNestedNameSpecifier( + NestedNameSpecifier Qualifier = getFullyQualifiedNestedNameSpecifier( Ctx, MPT->getQualifier(), WithGlobalNsPrefix); QT = Ctx.getMemberPointerType(QT, Qualifier, MPT->getMostRecentCXXRecordDecl()); diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index a2c77883df419..afccba8778fd2 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -454,10 +454,7 @@ void StmtPrinter::VisitMSDependentExistsStmt(MSDependentExistsStmt *Node) { else OS << "__if_not_exists ("; - if (NestedNameSpecifier *Qualifier - = Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); - + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getNameInfo() << ") "; PrintRawCompoundStmt(Node->getSubStmt()); @@ -1309,8 +1306,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { TPOD->printAsExpr(OS, Policy); return; } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; @@ -1359,8 +1355,7 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { void StmtPrinter::VisitDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *Node) { - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getNameInfo(); @@ -1777,8 +1772,7 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { if (FD->isAnonymousStructOrUnion()) return; - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2176,9 +2170,7 @@ void StmtPrinter::VisitMSPropertyRefExpr(MSPropertyRefExpr *Node) { OS << "->"; else OS << "."; - if (NestedNameSpecifier *Qualifier = - Node->getQualifierLoc().getNestedNameSpecifier()) - Qualifier->print(OS, Policy); + Node->getQualifierLoc().getNestedNameSpecifier().print(OS, Policy); OS << Node->getPropertyDecl()->getDeclName(); } @@ -2570,8 +2562,7 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr( PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2584,8 +2575,7 @@ void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { PrintExpr(Node->getBase()); OS << (Node->isArrow() ? "->" : "."); } - if (NestedNameSpecifier *Qualifier = Node->getQualifier()) - Qualifier->print(OS, Policy); + Node->getQualifier().print(OS, Policy); if (Node->hasTemplateKeyword()) OS << "template "; OS << Node->getMemberNameInfo(); @@ -2676,8 +2666,7 @@ void StmtPrinter::VisitCXXParenListInitExpr(CXXParenListInitExpr *Node) { void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) { NestedNameSpecifierLoc NNS = E->getNestedNameSpecifierLoc(); - if (NNS) - NNS.getNestedNameSpecifier()->print(OS, Policy); + NNS.getNestedNameSpecifier().print(OS, Policy); if (E->getTemplateKWLoc().isValid()) OS << "template "; OS << E->getFoundDecl()->getName(); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c61450e19f1b6..59a18395d109c 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -65,7 +65,7 @@ namespace { /// Visit a nested-name-specifier that occurs within an expression /// or statement. - virtual void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) = 0; + virtual void VisitNestedNameSpecifier(NestedNameSpecifier NNS) = 0; /// Visit a template name that occurs within an expression or /// statement. @@ -167,10 +167,10 @@ namespace { ID.AddPointer(II); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { if (Canonical) - NNS = Context.getCanonicalNestedNameSpecifier(NNS); - ID.AddPointer(NNS); + NNS = NNS.getCanonical(); + NNS.Profile(ID); } void VisitTemplateName(TemplateName Name) override { @@ -226,11 +226,10 @@ namespace { void VisitTemplateName(TemplateName Name) override { Hash.AddTemplateName(Name); } - void VisitNestedNameSpecifier(NestedNameSpecifier *NNS) override { - ID.AddBoolean(NNS); - if (NNS) { + void VisitNestedNameSpecifier(NestedNameSpecifier NNS) override { + ID.AddBoolean(bool(NNS)); + if (NNS) Hash.AddNestedNameSpecifier(NNS); - } } }; } diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 2fae4ab2b0ea3..700675840fd96 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -585,6 +585,29 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out, // TemplateArgumentLoc Implementation //===----------------------------------------------------------------------===// +TemplateArgumentLoc::TemplateArgumentLoc(ASTContext &Ctx, + const TemplateArgument &Argument, + SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) + : Argument(Argument), + LocInfo(Ctx, TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc) { + assert(Argument.getKind() == TemplateArgument::Template || + Argument.getKind() == TemplateArgument::TemplateExpansion); + assert(QualifierLoc.getNestedNameSpecifier() == + Argument.getAsTemplateOrTemplatePattern().getQualifier()); +} + +NestedNameSpecifierLoc TemplateArgumentLoc::getTemplateQualifierLoc() const { + if (Argument.getKind() != TemplateArgument::Template && + Argument.getKind() != TemplateArgument::TemplateExpansion) + return NestedNameSpecifierLoc(); + return NestedNameSpecifierLoc( + Argument.getAsTemplateOrTemplatePattern().getQualifier(), + LocInfo.getTemplate()->QualifierLocData); +} + SourceRange TemplateArgumentLoc::getSourceRange() const { switch (Argument.getKind()) { case TemplateArgument::Expression: @@ -691,10 +714,11 @@ const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB, } clang::TemplateArgumentLocInfo::TemplateArgumentLocInfo( - ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateNameLoc, SourceLocation EllipsisLoc) { + ASTContext &Ctx, SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateNameLoc, + SourceLocation EllipsisLoc) { TemplateTemplateArgLocInfo *Template = new (Ctx) TemplateTemplateArgLocInfo; - Template->Qualifier = QualifierLoc.getNestedNameSpecifier(); + Template->TemplateKwLoc = TemplateKWLoc; Template->QualifierLocData = QualifierLoc.getOpaqueData(); Template->TemplateNameLoc = TemplateNameLoc; Template->EllipsisLoc = EllipsisLoc; diff --git a/clang/lib/AST/TemplateName.cpp b/clang/lib/AST/TemplateName.cpp index 5b7abc4d038a9..c171516c38c10 100644 --- a/clang/lib/AST/TemplateName.cpp +++ b/clang/lib/AST/TemplateName.cpp @@ -289,10 +289,30 @@ QualifiedTemplateName *TemplateName::getAsQualifiedTemplateName() const { return dyn_cast_if_present(Storage); } +QualifiedTemplateName * +TemplateName::getAsAdjustedQualifiedTemplateName() const { + for (std::optional Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N; + return nullptr; +} + DependentTemplateName *TemplateName::getAsDependentTemplateName() const { return Storage.dyn_cast(); } +NestedNameSpecifier TemplateName::getQualifier() const { + for (std::optional Cur = *this; Cur; + Cur = Cur->desugar(/*IgnoreDeduced=*/true)) { + if (DependentTemplateName *N = Cur->getAsDependentTemplateName()) + return N->getQualifier(); + if (QualifiedTemplateName *N = Cur->getAsQualifiedTemplateName()) + return N->getQualifier(); + } + return std::nullopt; +} + UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { if (Decl *D = Storage.dyn_cast()) if (UsingShadowDecl *USD = dyn_cast(D)) @@ -303,24 +323,21 @@ UsingShadowDecl *TemplateName::getAsUsingShadowDecl() const { } DependentTemplateStorage::DependentTemplateStorage( - NestedNameSpecifier *Qualifier, IdentifierOrOverloadedOperator Name, + NestedNameSpecifier Qualifier, IdentifierOrOverloadedOperator Name, bool HasTemplateKeyword) : Qualifier(Qualifier, HasTemplateKeyword), Name(Name) { - assert((!Qualifier || Qualifier->isDependent()) && + assert((!Qualifier || Qualifier.isDependent()) && "Qualifier must be dependent"); } TemplateNameDependence DependentTemplateStorage::getDependence() const { - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } void DependentTemplateStorage::print(raw_ostream &OS, const PrintingPolicy &Policy) const { - if (NestedNameSpecifier *NNS = getQualifier()) - NNS->print(OS, Policy); + getQualifier().print(OS, Policy); if (hasTemplateKeyword()) OS << "template "; @@ -363,16 +380,13 @@ TemplateNameDependence TemplateName::getDependence() const { case NameKind::QualifiedTemplate: { QualifiedTemplateName *S = getAsQualifiedTemplateName(); TemplateNameDependence D = S->getUnderlyingTemplate().getDependence(); - if (NestedNameSpecifier *NNS = S->getQualifier()) - D |= toTemplateNameDependence(NNS->getDependence()); + D |= toTemplateNameDependence(S->getQualifier().getDependence()); return D; } case NameKind::DependentTemplate: { DependentTemplateName *S = getAsDependentTemplateName(); - auto D = TemplateNameDependence::DependentInstantiation; - if (NestedNameSpecifier *Qualifier = S->getQualifier()) - D |= toTemplateNameDependence(Qualifier->getDependence()); - return D; + return toTemplateNameDependence(S->getQualifier().getDependence()) | + TemplateNameDependence::DependentInstantiation; } case NameKind::SubstTemplateTemplateParm: { auto *S = getAsSubstTemplateTemplateParm(); @@ -434,18 +448,20 @@ void TemplateName::print(raw_ostream &OS, const PrintingPolicy &Policy, Template = cast(Template->getCanonicalDecl()); if (handleAnonymousTTP(Template, OS)) return; - if (Qual == Qualified::None) + if (Qual == Qualified::None || Policy.SuppressScope) { OS << *Template; - else - Template->printQualifiedName(OS, Policy); + } else { + PrintingPolicy NestedNamePolicy = Policy; + NestedNamePolicy.SuppressUnwrittenScope = true; + Template->printQualifiedName(OS, NestedNamePolicy); + } } else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { if (Policy.PrintAsCanonical) { QTN->getUnderlyingTemplate().print(OS, Policy, Qual); return; } - if (NestedNameSpecifier *NNS = QTN->getQualifier(); - Qual != Qualified::None && NNS) - NNS->print(OS, Policy); + if (Qual != Qualified::None) + QTN->getQualifier().print(OS, Policy); if (QTN->hasTemplateKeyword()) OS << "template "; diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 8aa01bfaf9668..38924aff54634 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -1034,35 +1034,34 @@ void clang::TextNodeDumper::dumpTemplateSpecializationKind( } } -void clang::TextNodeDumper::dumpNestedNameSpecifier(const NestedNameSpecifier *NNS) { +void clang::TextNodeDumper::dumpNestedNameSpecifier(NestedNameSpecifier NNS) { if (!NNS) return; AddChild([=] { OS << "NestedNameSpecifier"; - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - OS << " Identifier"; - OS << " '" << NNS->getAsIdentifier()->getName() << "'"; - break; - case NestedNameSpecifier::Namespace: + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); OS << " "; // "Namespace" is printed as the decl kind. - dumpBareDeclRef(NNS->getAsNamespace()); + dumpBareDeclRef(Namespace); + dumpNestedNameSpecifier(Prefix); break; - case NestedNameSpecifier::TypeSpec: + } + case NestedNameSpecifier::Kind::Type: OS << " TypeSpec"; - dumpType(QualType(NNS->getAsType(), 0)); + dumpType(QualType(NNS.getAsType(), 0)); break; - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: OS << " Global"; break; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: OS << " Super"; break; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } - - dumpNestedNameSpecifier(NNS->getPrefix()); }); } @@ -2801,8 +2800,7 @@ void TextNodeDumper::VisitTemplateTemplateParmDecl( void TextNodeDumper::VisitUsingDecl(const UsingDecl *D) { OS << ' '; - if (D->getQualifier()) - D->getQualifier()->print(OS, D->getASTContext().getPrintingPolicy()); + D->getQualifier().print(OS, D->getASTContext().getPrintingPolicy()); OS << D->getDeclName(); dumpNestedNameSpecifier(D->getQualifier()); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index d756d22645156..2726d820cae20 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1959,6 +1959,35 @@ Type::getAsNonAliasTemplateSpecializationType() const { return TST; } +NestedNameSpecifier Type::getPrefix() const { + switch (getTypeClass()) { + case Type::DependentName: + return cast(this)->getQualifier(); + case Type::TemplateSpecialization: { + QualifiedTemplateName *S = cast(this) + ->getTemplateName() + .getAsAdjustedQualifiedTemplateName(); + return S ? S->getQualifier() : std::nullopt; + } + case Type::DependentTemplateSpecialization: + return cast(this) + ->getDependentTemplateName() + .getQualifier(); + case Type::Enum: + case Type::Record: + case Type::InjectedClassName: + return cast(this)->getQualifier(); + case Type::Typedef: + return cast(this)->getQualifier(); + case Type::UnresolvedUsing: + return cast(this)->getQualifier(); + case Type::Using: + return cast(this)->getQualifier(); + default: + return std::nullopt; + } +} + bool Type::hasAttr(attr::Kind AK) const { const Type *Cur = this; while (const auto *AT = Cur->getAs()) { @@ -5435,16 +5464,16 @@ QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { bool MemberPointerType::isSugared() const { CXXRecordDecl *D1 = getMostRecentCXXRecordDecl(), - *D2 = getQualifier()->getAsRecordDecl(); + *D2 = getQualifier().getAsRecordDecl(); assert(!D1 == !D2); return D1 != D2 && D1->getCanonicalDecl() != D2->getCanonicalDecl(); } void MemberPointerType::Profile(llvm::FoldingSetNodeID &ID, QualType Pointee, - const NestedNameSpecifier *Qualifier, + const NestedNameSpecifier Qualifier, const CXXRecordDecl *Cls) { ID.AddPointer(Pointee.getAsOpaquePtr()); - ID.AddPointer(Qualifier); + Qualifier.Profile(ID); if (Cls) ID.AddPointer(Cls->getCanonicalDecl()); } diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index c909697b5b037..fbe8772924465 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -471,6 +471,134 @@ TypeLoc TypeLoc::findExplicitQualifierLoc() const { return {}; } +NestedNameSpecifierLoc TypeLoc::getPrefix() const { + switch (getTypeLocClass()) { + case TypeLoc::DependentName: + return castAs().getQualifierLoc(); + case TypeLoc::TemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::DependentTemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::DeducedTemplateSpecialization: + return castAs().getQualifierLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs().getQualifierLoc(); + case TypeLoc::Typedef: + return castAs().getQualifierLoc(); + case TypeLoc::UnresolvedUsing: + return castAs().getQualifierLoc(); + case TypeLoc::Using: + return castAs().getQualifierLoc(); + default: + return NestedNameSpecifierLoc(); + } +} + +SourceLocation TypeLoc::getNonPrefixBeginLoc() const { + switch (getTypeLocClass()) { + case TypeLoc::TemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentTemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DeducedTemplateSpecialization: { + auto TL = castAs(); + SourceLocation Loc = TL.getTemplateKeywordLoc(); + if (!Loc.isValid()) + Loc = TL.getTemplateNameLoc(); + return Loc; + } + case TypeLoc::DependentName: + return castAs().getNameLoc(); + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + return castAs().getNameLoc(); + case TypeLoc::Typedef: + return castAs().getNameLoc(); + case TypeLoc::UnresolvedUsing: + return castAs().getNameLoc(); + case TypeLoc::Using: + return castAs().getNameLoc(); + default: + return getBeginLoc(); + } +} + +SourceLocation TypeLoc::getNonElaboratedBeginLoc() const { + // For elaborated types (e.g. `struct a::A`) we want the portion after the + // `struct` but including the namespace qualifier, `a::`. + switch (getTypeLocClass()) { + case TypeLoc::Qualified: + return castAs() + .getUnqualifiedLoc() + .getNonElaboratedBeginLoc(); + case TypeLoc::TemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentTemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DeducedTemplateSpecialization: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getTemplateNameLoc(); + } + case TypeLoc::DependentName: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Enum: + case TypeLoc::Record: + case TypeLoc::InjectedClassName: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Typedef: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::UnresolvedUsing: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + case TypeLoc::Using: { + auto T = castAs(); + if (NestedNameSpecifierLoc QualifierLoc = T.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return T.getNameLoc(); + } + default: + return getBeginLoc(); + } +} + void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); @@ -544,9 +672,9 @@ static void initializeElaboratedKeyword(TL T, SourceLocation Loc) { : SourceLocation()); } -static NestedNameSpecifierLoc -initializeQualifier(ASTContext &Context, NestedNameSpecifier *Qualifier, - SourceLocation Loc) { +static NestedNameSpecifierLoc initializeQualifier(ASTContext &Context, + NestedNameSpecifier Qualifier, + SourceLocation Loc) { if (!Qualifier) return NestedNameSpecifierLoc(); NestedNameSpecifierLocBuilder Builder; diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index b0fa7f4c95719..d43d1aec71b29 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -122,15 +122,15 @@ class MatchChildASTVisitor else if (const Stmt *S = DynNode.get()) traverse(*S); else if (const NestedNameSpecifier *NNS = - DynNode.get()) + DynNode.get()) traverse(*NNS); else if (const NestedNameSpecifierLoc *NNSLoc = DynNode.get()) traverse(*NNSLoc); else if (const QualType *Q = DynNode.get()) - traverse(*Q); + traverse(*Q, /*TraverseQualifier=*/true); else if (const TypeLoc *T = DynNode.get()) - traverse(*T); + traverse(*T, /*TraverseQualifier=*/true); else if (const auto *C = DynNode.get()) traverse(*C); else if (const TemplateArgumentLoc *TALoc = @@ -217,17 +217,17 @@ class MatchChildASTVisitor if (!match(TypeLocNode.getType())) return false; // The TypeLoc is matched inside traverse. - return traverse(TypeLocNode); + return traverse(TypeLocNode, TraverseQualifier); } - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS) { ScopedIncrement ScopedDepth(&CurrentDepth); - return (NNS == nullptr) || traverse(*NNS); + return !NNS || traverse(NNS); } bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { if (!NNS) return true; ScopedIncrement ScopedDepth(&CurrentDepth); - if (!match(*NNS.getNestedNameSpecifier())) + if (!match(NNS.getNestedNameSpecifier())) return false; return traverse(NNS); } @@ -340,15 +340,14 @@ class MatchChildASTVisitor bool baseTraverse(const Stmt &StmtNode) { return VisitorBase::TraverseStmt(const_cast(&StmtNode)); } - bool baseTraverse(QualType TypeNode) { - return VisitorBase::TraverseType(TypeNode); + bool baseTraverse(QualType TypeNode, bool TraverseQualifier) { + return VisitorBase::TraverseType(TypeNode, TraverseQualifier); } - bool baseTraverse(TypeLoc TypeLocNode) { - return VisitorBase::TraverseTypeLoc(TypeLocNode); + bool baseTraverse(TypeLoc TypeLocNode, bool TraverseQualifier) { + return VisitorBase::TraverseTypeLoc(TypeLocNode, TraverseQualifier); } - bool baseTraverse(const NestedNameSpecifier &NNS) { - return VisitorBase::TraverseNestedNameSpecifier( - const_cast(&NNS)); + bool baseTraverse(NestedNameSpecifier NNS) { + return VisitorBase::TraverseNestedNameSpecifier(NNS); } bool baseTraverse(NestedNameSpecifierLoc NNS) { return VisitorBase::TraverseNestedNameSpecifierLoc(NNS); @@ -501,9 +500,9 @@ class MatchASTVisitor : public RecursiveASTVisitor, bool TraverseDecl(Decl *DeclNode); bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr); - bool TraverseType(QualType TypeNode); - bool TraverseTypeLoc(TypeLoc TypeNode); - bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + bool TraverseType(QualType TypeNode, bool TraverseQualifier = true); + bool TraverseTypeLoc(TypeLoc TypeNode, bool TraverseQualifier = true); + bool TraverseNestedNameSpecifier(NestedNameSpecifier NNS); bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit); bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL); @@ -1530,11 +1529,12 @@ bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode, // each TypeLoc. match(TypeLocNode); match(TypeLocNode.getType()); - return RecursiveASTVisitor::TraverseTypeLoc(TypeLocNode); + return RecursiveASTVisitor::TraverseTypeLoc( + TypeLocNode, TraverseQualifier); } -bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { - match(*NNS); +bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier NNS) { + match(NNS); return RecursiveASTVisitor::TraverseNestedNameSpecifier(NNS); } @@ -1548,7 +1548,7 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc( // We only match the nested name specifier here (as opposed to traversing it) // because the traversal is already done in the parallel "Loc"-hierarchy. if (NNS.hasQualifier()) - match(*NNS.getNestedNameSpecifier()); + match(NNS.getNestedNameSpecifier()); return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNS); } diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 5560985af4de6..f9aff893eb0f0 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -278,14 +278,13 @@ static CGCallee BuildAppleKextVirtualCall(CodeGenFunction &CGF, /// BuildAppleKextVirtualCall - This routine is to support gcc's kext ABI making /// indirect call to virtual functions. It makes the call through indexing /// into the vtable. -CGCallee -CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, - NestedNameSpecifier *Qual, - llvm::Type *Ty) { - assert((Qual->getKind() == NestedNameSpecifier::TypeSpec) && +CGCallee CodeGenFunction::BuildAppleKextVirtualCall(const CXXMethodDecl *MD, + NestedNameSpecifier Qual, + llvm::Type *Ty) { + assert(Qual.getKind() == NestedNameSpecifier::Kind::Type && "BuildAppleKextVirtualCall - bad Qual kind"); - const Type *QTy = Qual->getAsType(); + const Type *QTy = Qual.getAsType(); QualType T = QualType(QTy, 0); const RecordType *RT = T->getAs(); assert(RT && "BuildAppleKextVirtualCall - Qual type must be record"); diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 70b12231d65a3..a92b89def6433 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -206,7 +206,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } bool HasQualifier = ME->hasQualifier(); - NestedNameSpecifier *Qualifier = HasQualifier ? ME->getQualifier() : nullptr; + NestedNameSpecifier Qualifier = ME->getQualifier(); bool IsArrow = ME->isArrow(); const Expr *Base = ME->getBase(); @@ -217,7 +217,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue, - bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow, + bool HasQualifier, NestedNameSpecifier Qualifier, bool IsArrow, const Expr *Base, llvm::CallBase **CallOrInvoke) { assert(isa(CE) || isa(CE)); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 6822113e11b69..c33c215c03e01 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4560,7 +4560,7 @@ class CodeGenFunction : public CodeGenTypeCache { ArrayRef args); CGCallee BuildAppleKextVirtualCall(const CXXMethodDecl *MD, - NestedNameSpecifier *Qual, llvm::Type *Ty); + NestedNameSpecifier Qual, llvm::Type *Ty); CGCallee BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, @@ -4665,7 +4665,7 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::CallBase **CallOrInvoke = nullptr); RValue EmitCXXMemberOrOperatorMemberCallExpr( const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue, - bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow, + bool HasQualifier, NestedNameSpecifier Qualifier, bool IsArrow, const Expr *Base, llvm::CallBase **CallOrInvoke); // Compute the object pointer. Address EmitCXXMemberDataPointerAddress( diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 63118d6bd5f12..541af6d587174 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -205,45 +205,39 @@ DeclarationFragments::getStructureTypeFragment(const RecordDecl *Record) { // Build declaration fragments for NNS recursively so that we have the USR for // every part in a qualified name, and also leaves the actual underlying type // cleaner for its own fragment. -DeclarationFragments -DeclarationFragmentsBuilder::getFragmentsForNNS(const NestedNameSpecifier *NNS, - ASTContext &Context, - DeclarationFragments &After) { +DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNNS( + NestedNameSpecifier NNS, ASTContext &Context, DeclarationFragments &After) { DeclarationFragments Fragments; - if (NNS->getPrefix()) - Fragments.append(getFragmentsForNNS(NNS->getPrefix(), Context, After)); - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - Fragments.append(NNS->getAsIdentifier()->getName(), - DeclarationFragments::FragmentKind::Identifier); - break; + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + return Fragments; - case NestedNameSpecifier::Namespace: { - const NamespaceBaseDecl *NS = NNS->getAsNamespace(); - if (const auto *Namespace = dyn_cast(NS); - Namespace && Namespace->isAnonymousNamespace()) + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); + Fragments.append(getFragmentsForNNS(Prefix, Context, After)); + if (const auto *NS = dyn_cast(Namespace); + NS && NS->isAnonymousNamespace()) return Fragments; SmallString<128> USR; - index::generateUSRForDecl(NS, USR); - Fragments.append(NS->getName(), - DeclarationFragments::FragmentKind::Identifier, USR, NS); + index::generateUSRForDecl(Namespace, USR); + Fragments.append(Namespace->getName(), + DeclarationFragments::FragmentKind::Identifier, USR, + Namespace); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // The global specifier `::` at the beginning. No stored value. break; - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::MicrosoftSuper: // Microsoft's `__super` specifier. Fragments.append("__super", DeclarationFragments::FragmentKind::Keyword); break; - case NestedNameSpecifier::TypeSpec: { - const Type *T = NNS->getAsType(); + case NestedNameSpecifier::Kind::Type: { // FIXME: Handle C++ template specialization type - Fragments.append(getFragmentsForType(T, Context, After)); + Fragments.append(getFragmentsForType(NNS.getAsType(), Context, After)); break; } } diff --git a/clang/lib/Index/IndexTypeSourceInfo.cpp b/clang/lib/Index/IndexTypeSourceInfo.cpp index 2bc6f26d34368..9a699c3c896de 100644 --- a/clang/lib/Index/IndexTypeSourceInfo.cpp +++ b/clang/lib/Index/IndexTypeSourceInfo.cpp @@ -244,32 +244,28 @@ void IndexingContext::indexTypeLoc(TypeLoc TL, TypeIndexer(*this, Parent, DC, isBase, isIBType).TraverseTypeLoc(TL); } -void IndexingContext::indexNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, - const NamedDecl *Parent, - const DeclContext *DC) { - if (!NNS) - return; - - if (NestedNameSpecifierLoc Prefix = NNS.getPrefix()) - indexNestedNameSpecifierLoc(Prefix, Parent, DC); - +void IndexingContext::indexNestedNameSpecifierLoc( + NestedNameSpecifierLoc QualifierLoc, const NamedDecl *Parent, + const DeclContext *DC) { if (!DC) DC = Parent->getLexicalDeclContext(); - SourceLocation Loc = NNS.getLocalBeginLoc(); - - switch (NNS.getNestedNameSpecifier()->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + switch (NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier(); + Qualifier.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: break; - case NestedNameSpecifier::Namespace: - handleReference(NNS.getNestedNameSpecifier()->getAsNamespace(), - Loc, Parent, DC, SymbolRoleSet()); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = QualifierLoc.castAsNamespaceAndPrefix(); + indexNestedNameSpecifierLoc(Prefix, Parent, DC); + handleReference(Namespace, QualifierLoc.getLocalBeginLoc(), Parent, DC, + SymbolRoleSet()); break; + } - case NestedNameSpecifier::TypeSpec: - indexTypeLoc(NNS.getTypeLoc(), Parent, DC); + case NestedNameSpecifier::Kind::Type: + indexTypeLoc(QualifierLoc.castAsTypeLoc(), Parent, DC); break; } } diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index 5b1d1cb698231..9e69ca567e80c 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -653,14 +653,14 @@ bool USRGenerator::GenLoc(const Decl *D, bool IncludeOffset) { } static void printQualifier(llvm::raw_ostream &Out, const LangOptions &LangOpts, - NestedNameSpecifier *NNS) { + NestedNameSpecifier NNS) { // FIXME: Encode the qualifier, don't just print it. PrintingPolicy PO(LangOpts); PO.SuppressTagKeyword = true; PO.SuppressUnwrittenScope = true; PO.ConstantArraySizeAsWritten = false; PO.AnonymousTagLocations = false; - NNS->print(Out, PO); + NNS.print(Out, PO); } void USRGenerator::VisitType(QualType T) { diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 31392d1dd8d4b..b096d5ee296de 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -591,7 +591,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, NextToken().isRegularKeywordAttribute() || NextToken().is(tok::kw___attribute)) && D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && - D.SS.getScopeRep()->getKind() != NestedNameSpecifier::Namespace) { + D.SS.getScopeRep().getKind() != NestedNameSpecifier::Kind::Namespace) { SourceLocation IdLoc = ConsumeToken(); ParsedType Type = Actions.getInheritingConstructorName(D.SS, IdLoc, *LastII); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index b58100c635677..6cbc48102bf73 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1328,7 +1328,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), Tok.getAnnotationRange(), SS); - if (SS.getScopeRep() && SS.getScopeRep()->isDependent()) { + if (SS.getScopeRep().isDependent()) { RevertingTentativeParsingAction PA(*this); ConsumeAnnotationToken(); ConsumeToken(); diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index d1400cbfc884d..94b1099c4bb90 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -227,14 +227,11 @@ static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { // Skip function calls which are qualified with a templated class. if (const DeclRefExpr *DRE = - dyn_cast(CE->getCallee()->IgnoreParenImpCasts())) { - if (NestedNameSpecifier *NNS = DRE->getQualifier()) { - if (NNS->getKind() == NestedNameSpecifier::TypeSpec && - isa(NNS->getAsType())) { + dyn_cast(CE->getCallee()->IgnoreParenImpCasts())) + if (NestedNameSpecifier NNS = DRE->getQualifier(); + NNS.getKind() == NestedNameSpecifier::Kind::Type) + if (isa_and_nonnull(NNS.getAsType())) continue; - } - } - } const CXXMemberCallExpr *MCE = dyn_cast(CE); if (!MCE || isa(MCE->getImplicitObjectArgument()) || diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 3ea5aa55c1e94..8756ce5f0d850 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -59,19 +59,6 @@ void CXXScopeSpec::Make(ASTContext &Context, TypeLoc TL, "NestedNameSpecifierLoc range computation incorrect"); } -void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier, - SourceLocation IdentifierLoc, - SourceLocation ColonColonLoc) { - Builder.Extend(Context, Identifier, IdentifierLoc, ColonColonLoc); - - if (Range.getBegin().isInvalid()) - Range.setBegin(IdentifierLoc); - Range.setEnd(ColonColonLoc); - - assert(Range == Builder.getSourceRange() && - "NestedNameSpecifierLoc range computation incorrect"); -} - void CXXScopeSpec::Extend(ASTContext &Context, NamespaceBaseDecl *Namespace, SourceLocation NamespaceLoc, SourceLocation ColonColonLoc) { @@ -95,10 +82,10 @@ void CXXScopeSpec::MakeGlobal(ASTContext &Context, "NestedNameSpecifierLoc range computation incorrect"); } -void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD, - SourceLocation SuperLoc, - SourceLocation ColonColonLoc) { - Builder.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); +void CXXScopeSpec::MakeMicrosoftSuper(ASTContext &Context, CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Builder.MakeMicrosoftSuper(Context, RD, SuperLoc, ColonColonLoc); Range.setBegin(SuperLoc); Range.setEnd(ColonColonLoc); @@ -108,7 +95,7 @@ void CXXScopeSpec::MakeSuper(ASTContext &Context, CXXRecordDecl *RD, } void CXXScopeSpec::MakeTrivial(ASTContext &Context, - NestedNameSpecifier *Qualifier, SourceRange R) { + NestedNameSpecifier Qualifier, SourceRange R) { Builder.MakeTrivial(Context, Qualifier, R); Range = R; } diff --git a/clang/lib/Sema/HeuristicResolver.cpp b/clang/lib/Sema/HeuristicResolver.cpp index 5bd5d15c6709c..9c56dd356421e 100644 --- a/clang/lib/Sema/HeuristicResolver.cpp +++ b/clang/lib/Sema/HeuristicResolver.cpp @@ -44,7 +44,7 @@ class HeuristicResolverImpl { resolveDependentNameType(const DependentNameType *DNT); std::vector resolveTemplateSpecializationType( const DependentTemplateSpecializationType *DTST); - QualType resolveNestedNameSpecifierToType(const NestedNameSpecifier *NNS); + QualType resolveNestedNameSpecifierToType(NestedNameSpecifier NNS); QualType getPointeeType(QualType T); std::vector lookupDependentName(CXXRecordDecl *RD, DeclarationName Name, @@ -285,7 +285,7 @@ std::vector HeuristicResolverImpl::resolveMemberExpr( // an instance method, it's represented as a CXXDependentScopeMemberExpr // with `this` as the base expression as `X` as the qualifier // (which could be valid if `X` names a base class after instantiation). - if (NestedNameSpecifier *NNS = ME->getQualifier()) { + if (NestedNameSpecifier NNS = ME->getQualifier()) { if (QualType QualifierType = resolveNestedNameSpecifierToType(NNS); !QualifierType.isNull()) { auto Decls = @@ -341,7 +341,10 @@ HeuristicResolverImpl::resolveCalleeOfCallExpr(const CallExpr *CE) { std::vector HeuristicResolverImpl::resolveUsingValueDecl( const UnresolvedUsingValueDecl *UUVD) { - return resolveDependentMember(QualType(UUVD->getQualifier()->getAsType(), 0), + NestedNameSpecifier Qualifier = UUVD->getQualifier(); + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) + return {}; + return resolveDependentMember(QualType(Qualifier.getAsType(), 0), UUVD->getNameInfo().getName(), ValueFilter); } @@ -392,23 +395,23 @@ QualType HeuristicResolverImpl::resolveExprToType(const Expr *E) { } QualType HeuristicResolverImpl::resolveNestedNameSpecifierToType( - const NestedNameSpecifier *NNS) { - if (!NNS) - return QualType(); - + NestedNameSpecifier NNS) { // The purpose of this function is to handle the dependent (Kind == // Identifier) case, but we need to recurse on the prefix because // that may be dependent as well, so for convenience handle // the TypeSpec cases too. - switch (NNS->getKind()) { - case NestedNameSpecifier::TypeSpec: - return QualType(NNS->getAsType(), 0); - case NestedNameSpecifier::Identifier: { - return resolveDeclsToType( - resolveDependentMember( - resolveNestedNameSpecifierToType(NNS->getPrefix()), - NNS->getAsIdentifier(), TypeFilter), - Ctx); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Type: { + const auto *T = NNS.getAsType(); + // FIXME: Should this handle the DependentTemplateSpecializationType as + // well? + if (const auto *DTN = dyn_cast(T)) + return resolveDeclsToType( + resolveDependentMember( + resolveNestedNameSpecifierToType(DTN->getQualifier()), + DTN->getIdentifier(), TypeFilter), + Ctx); + return QualType(T, 0); } default: break; @@ -583,7 +586,7 @@ HeuristicResolver::resolveTemplateSpecializationType( return HeuristicResolverImpl(Ctx).resolveTemplateSpecializationType(DTST); } QualType HeuristicResolver::resolveNestedNameSpecifierToType( - const NestedNameSpecifier *NNS) const { + NestedNameSpecifier NNS) const { return HeuristicResolverImpl(Ctx).resolveNestedNameSpecifierToType(NNS); } std::vector HeuristicResolver::lookupDependentName( diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index a82129821b884..45de8ff3ba264 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -51,18 +51,17 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (!SS.isSet() || SS.isInvalid()) return nullptr; - NestedNameSpecifier *NNS = SS.getScopeRep(); - if (NNS->isDependent()) { + NestedNameSpecifier NNS = SS.getScopeRep(); + if (NNS.isDependent()) { // If this nested-name-specifier refers to the current // instantiation, return its DeclContext. if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) return Record; if (EnteringContext) { - const Type *NNSType = NNS->getAsType(); - if (!NNSType) { + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) return nullptr; - } + const Type *NNSType = NNS.getAsType(); // Look through type alias templates, per C++0x [temp.dep.type]p1. NNSType = Context.getCanonicalType(NNSType); @@ -129,24 +128,25 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, return nullptr; } - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - llvm_unreachable("Dependent nested-name-specifier has no DeclContext"); - - case NestedNameSpecifier::Namespace: - return NNS->getAsNamespace()->getNamespace(); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: + return const_cast( + NNS.getAsNamespaceAndPrefix().Namespace->getNamespace()); - case NestedNameSpecifier::TypeSpec: { - const TagType *Tag = NNS->getAsType()->getAs(); - assert(Tag && "Non-tag type in nested-name-specifier"); - return Tag->getDecl(); + case NestedNameSpecifier::Kind::Type: { + auto *TD = NNS.getAsType()->getAsTagDecl(); + assert(TD && "Non-tag type in nested-name-specifier"); + return TD; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: return Context.getTranslationUnitDecl(); - case NestedNameSpecifier::Super: - return NNS->getAsRecordDecl(); + case NestedNameSpecifier::Kind::MicrosoftSuper: + return NNS.getAsMicrosoftSuper(); + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); @@ -156,17 +156,17 @@ bool Sema::isDependentScopeSpecifier(const CXXScopeSpec &SS) { if (!SS.isSet() || SS.isInvalid()) return false; - return SS.getScopeRep()->isDependent(); + return SS.getScopeRep().isDependent(); } -CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) { +CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier NNS) { assert(getLangOpts().CPlusPlus && "Only callable in C++"); - assert(NNS->isDependent() && "Only dependent nested-name-specifier allowed"); + assert(NNS.isDependent() && "Only dependent nested-name-specifier allowed"); - if (!NNS->getAsType()) + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) return nullptr; - QualType T = QualType(NNS->getAsType(), 0); + QualType T = QualType(NNS.getAsType(), 0); return ::getCurrentInstantiationOf(T, CurContext); } @@ -301,7 +301,7 @@ bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc, return true; } - SS.MakeSuper(Context, RD, SuperLoc, ColonColonLoc); + SS.MakeMicrosoftSuper(Context, RD, SuperLoc, ColonColonLoc); return false; } @@ -338,32 +338,42 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD, if (IsExtension) *IsExtension = true; } + if (auto *TD = dyn_cast(SD)) { + if (TD->isDependentType()) + return true; + } else if (Context.getCanonicalTypeDeclType(cast(SD)) + ->isDependentType()) { + return true; + } return false; } -NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { - if (!S || !NNS) +NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier NNS) { + if (!S) return nullptr; - while (NNS->getPrefix()) - NNS = NNS->getPrefix(); - - if (NNS->getKind() != NestedNameSpecifier::Identifier) - return nullptr; + while (NNS.getKind() == NestedNameSpecifier::Kind::Type) { + const Type *T = NNS.getAsType(); + if ((NNS = T->getPrefix())) + continue; - LookupResult Found(*this, NNS->getAsIdentifier(), SourceLocation(), - LookupNestedNameSpecifierName); - LookupName(Found, S); - assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); + const auto *DNT = dyn_cast(T); + if (!DNT) + break; - if (!Found.isSingleResult()) - return nullptr; + LookupResult Found(*this, DNT->getIdentifier(), SourceLocation(), + LookupNestedNameSpecifierName); + LookupName(Found, S); + assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet"); - NamedDecl *Result = Found.getFoundDecl(); - if (isAcceptableNestedNameSpecifier(Result)) - return Result; + if (!Found.isSingleResult()) + return nullptr; + NamedDecl *Result = Found.getFoundDecl(); + if (isAcceptableNestedNameSpecifier(Result)) + return Result; + } return nullptr; } @@ -899,7 +909,7 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, DependentTemplateSpecializationTypeLoc SpecTL = Builder.push(T); SpecTL.setElaboratedKeywordLoc(SourceLocation()); - SpecTL.setQualifierLoc(NestedNameSpecifierLoc()); + SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); SpecTL.setTemplateKeywordLoc(TemplateKWLoc); SpecTL.setTemplateNameLoc(TemplateNameLoc); SpecTL.setLAngleLoc(LAngleLoc); @@ -962,7 +972,7 @@ namespace { /// A structure that stores a nested-name-specifier annotation, /// including both the nested-name-specifier struct NestedNameSpecifierAnnotation { - NestedNameSpecifier *NNS; + NestedNameSpecifier NNS = std::nullopt; }; } @@ -1001,8 +1011,6 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { if (isa(CurContext) || isa(CurContext)) return false; - NestedNameSpecifier *Qualifier = SS.getScopeRep(); - // There are only two places a well-formed program may qualify a // declarator: first, when defining a namespace or class member // out-of-line, and second, when naming an explicitly-qualified @@ -1017,18 +1025,20 @@ bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { // granting friendship. // i.e. we don't push a scope unless it's a class member. - switch (Qualifier->getKind()) { - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Namespace: + switch (SS.getScopeRep().getKind()) { + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::Namespace: // These are always namespace scopes. We never want to enter a // namespace scope from anything but a file context. return CurContext->getRedeclContext()->isFileContext(); - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Type: + case NestedNameSpecifier::Kind::MicrosoftSuper: // These are never namespace scopes. return true; + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 0c86a1f97046a..99492cea4e6c2 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -732,7 +732,7 @@ ResultBuilder::ShadowMapEntry::end() const { /// /// \returns a nested name specifier that refers into the target context, or /// NULL if no qualification is needed. -static NestedNameSpecifier * +static NestedNameSpecifier getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, const DeclContext *TargetContext) { SmallVector TargetParents; @@ -747,7 +747,7 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, TargetParents.push_back(CommonAncestor); } - NestedNameSpecifier *Result = nullptr; + NestedNameSpecifier Result = std::nullopt; while (!TargetParents.empty()) { const DeclContext *Parent = TargetParents.pop_back_val(); @@ -755,10 +755,12 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, if (!Namespace->getIdentifier()) continue; - Result = NestedNameSpecifier::Create(Context, Result, Namespace); - } else if (const auto *TD = dyn_cast(Parent)) - Result = NestedNameSpecifier::Create( - Context, Result, Context.getTypeDeclType(TD).getTypePtr()); + Result = NestedNameSpecifier(Context, Namespace, Result); + } else if (const auto *TD = dyn_cast(Parent)) { + QualType TT = Context.getTagType(ElaboratedTypeKeyword::None, Result, TD, + /*OwnsTag=*/false); + Result = NestedNameSpecifier(TT.getTypePtr()); + } } return Result; } @@ -937,11 +939,12 @@ SimplifiedTypeClass clang::getSimplifiedTypeClass(CanQualType T) { /// Get the type that a given expression will have if this declaration /// is used as an expression in its "typical" code-completion form. -QualType clang::getDeclUsageType(ASTContext &C, const NamedDecl *ND) { +QualType clang::getDeclUsageType(ASTContext &C, NestedNameSpecifier Qualifier, + const NamedDecl *ND) { ND = ND->getUnderlyingDecl(); if (const auto *Type = dyn_cast(ND)) - return C.getTypeDeclType(Type); + return C.getTypeDeclType(ElaboratedTypeKeyword::None, Qualifier, Type); if (const auto *Iface = dyn_cast(ND)) return C.getObjCInterfaceType(Iface); @@ -1217,11 +1220,13 @@ void ResultBuilder::MaybeAddResult(Result R, DeclContext *CurContext) { const DeclContext *Ctx = R.Declaration->getDeclContext(); if (const NamespaceDecl *Namespace = dyn_cast(Ctx)) R.Qualifier = - NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace); + NestedNameSpecifier(SemaRef.Context, Namespace, std::nullopt); else if (const TagDecl *Tag = dyn_cast(Ctx)) - R.Qualifier = NestedNameSpecifier::Create( - SemaRef.Context, nullptr, - SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + R.Qualifier = NestedNameSpecifier( + SemaRef.Context + .getTagType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, Tag, /*OwnsTag=*/false) + .getTypePtr()); else R.QualifierIsInformative = false; } @@ -1406,11 +1411,13 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, const DeclContext *Ctx = R.Declaration->getDeclContext(); if (const auto *Namespace = dyn_cast(Ctx)) R.Qualifier = - NestedNameSpecifier::Create(SemaRef.Context, nullptr, Namespace); + NestedNameSpecifier(SemaRef.Context, Namespace, std::nullopt); else if (const auto *Tag = dyn_cast(Ctx)) - R.Qualifier = NestedNameSpecifier::Create( - SemaRef.Context, nullptr, - SemaRef.Context.getTypeDeclType(Tag).getTypePtr()); + R.Qualifier = NestedNameSpecifier( + SemaRef.Context + .getTagType(ElaboratedTypeKeyword::None, + /*Qualifier=*/std::nullopt, Tag, /*OwnsTag=*/false) + .getTypePtr()); else R.QualifierIsInformative = false; } @@ -3385,7 +3392,7 @@ static void AddTemplateParameterChunks( /// Add a qualifier to the given code-completion string, if the /// provided nested-name-specifier is non-NULL. static void AddQualifierToCompletionString(CodeCompletionBuilder &Result, - NestedNameSpecifier *Qualifier, + NestedNameSpecifier Qualifier, bool QualifierIsInformative, ASTContext &Context, const PrintingPolicy &Policy) { @@ -4500,12 +4507,12 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, // If we need a nested-name-specifier, add one now. if (!InContext) { - NestedNameSpecifier *NNS = getRequiredQualification( + NestedNameSpecifier NNS = getRequiredQualification( S.Context, CurContext, Overridden->getDeclContext()); if (NNS) { std::string Str; llvm::raw_string_ostream OS(Str); - NNS->print(OS, Policy); + NNS.print(OS, Policy); Builder.AddTextChunk(Results.getAllocator().CopyString(Str)); } } else if (!InContext->Equals(Overridden->getDeclContext())) @@ -4914,14 +4921,14 @@ namespace { /// Information that allows to avoid completing redundant enumerators. struct CoveredEnumerators { llvm::SmallPtrSet Seen; - NestedNameSpecifier *SuggestedQualifier = nullptr; + NestedNameSpecifier SuggestedQualifier = std::nullopt; }; } // namespace static void AddEnumerators(ResultBuilder &Results, ASTContext &Context, EnumDecl *Enum, DeclContext *CurContext, const CoveredEnumerators &Enumerators) { - NestedNameSpecifier *Qualifier = Enumerators.SuggestedQualifier; + NestedNameSpecifier Qualifier = Enumerators.SuggestedQualifier; if (Context.getLangOpts().CPlusPlus && !Qualifier && Enumerators.Seen.empty()) { // If there are no prior enumerators in C++, check whether we have to // qualify the names of the enumerators that we suggest, because they @@ -5607,15 +5614,18 @@ class ConceptInfo { // In T::foo, `foo` is a static member function/variable. bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) override { - if (E->getQualifier() && isApprox(E->getQualifier()->getAsType(), T)) + NestedNameSpecifier Qualifier = E->getQualifier(); + if (Qualifier.getKind() == NestedNameSpecifier::Kind::Type && + isApprox(Qualifier.getAsType(), T)) addValue(E, E->getDeclName(), Member::Colons); return true; } // In T::typename foo, `foo` is a type. bool VisitDependentNameType(DependentNameType *DNT) override { - const auto *Q = DNT->getQualifier(); - if (Q && isApprox(Q->getAsType(), T)) + NestedNameSpecifier Q = DNT->getQualifier(); + if (Q.getKind() == NestedNameSpecifier::Kind::Type && + isApprox(Q.getAsType(), T)) addType(DNT->getIdentifier()); return true; } @@ -5624,10 +5634,15 @@ class ConceptInfo { // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-( bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) override { if (NNSL) { - NestedNameSpecifier *NNS = NNSL.getNestedNameSpecifier(); - const auto *Q = NNS->getPrefix(); - if (Q && isApprox(Q->getAsType(), T)) - addType(NNS->getAsIdentifier()); + NestedNameSpecifier NNS = NNSL.getNestedNameSpecifier(); + if (NNS.getKind() == NestedNameSpecifier::Kind::Type) { + const Type *NNST = NNS.getAsType(); + if (NestedNameSpecifier Q = NNST->getPrefix(); + Q.getKind() == NestedNameSpecifier::Kind::Type && + isApprox(Q.getAsType(), T)) + if (const auto *DNT = dyn_cast_or_null(NNST)) + addType(DNT->getIdentifier()); + } } // FIXME: also handle T::foo::bar return DynamicRecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL); @@ -6882,8 +6897,8 @@ void SemaCodeCompletion::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // Try to instantiate any non-dependent declaration contexts before // we look in them. Bail out if we fail. - NestedNameSpecifier *NNS = SS.getScopeRep(); - if (NNS != nullptr && SS.isValid() && !NNS->isDependent()) { + NestedNameSpecifier NNS = SS.getScopeRep(); + if (NNS && !NNS.isDependent()) { if (Ctx == nullptr || SemaRef.RequireCompleteDeclContext(SS, Ctx)) return; } @@ -6897,14 +6912,13 @@ void SemaCodeCompletion::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. // FIXME: results is always empty, this appears to be dead. - if (!Results.empty() && NNS && NNS->isDependent()) + if (!Results.empty() && NNS.isDependent()) Results.AddResult("template"); // If the scope is a concept-constrained type parameter, infer nested // members based on the constraints. - if (NNS) { - if (const auto *TTPT = - dyn_cast_or_null(NNS->getAsType())) { + if (NNS.getKind() == NestedNameSpecifier::Kind::Type) { + if (const auto *TTPT = dyn_cast(NNS.getAsType())) { for (const auto &R : ConceptInfo(*TTPT, S).members()) { if (R.Operator != ConceptInfo::Member::Colons) continue; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3043f8f8d004c..2ae9bc11a9bdd 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -307,9 +307,10 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, if (AllowImplicitTypename == ImplicitTypenameContext::No) return nullptr; SourceLocation QualifiedLoc = SS->getRange().getBegin(); - auto DB = - DiagCompat(QualifiedLoc, diag_compat::implicit_typename) - << NestedNameSpecifier::Create(Context, SS->getScopeRep(), &II); + // FIXME: Defer the diagnostic after we build the type and use it. + auto DB = DiagCompat(QualifiedLoc, diag_compat::implicit_typename) + << Context.getDependentNameType(ElaboratedTypeKeyword::None, + SS->getScopeRep(), &II); if (!getLangOpts().CPlusPlus20) DB << FixItHint::CreateInsertion(QualifiedLoc, "typename "); } @@ -389,7 +390,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool MemberOfUnknownSpecialization; UnqualifiedId TemplateName; TemplateName.setIdentifier(NewII, NameLoc); - NestedNameSpecifier *NNS = Correction.getCorrectionSpecifier(); + NestedNameSpecifier NNS = Correction.getCorrectionSpecifier(); CXXScopeSpec NewSS, *NewSSPtr = SS; if (SS && NNS) { NewSS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); @@ -568,8 +569,9 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } else if (AllowDeducedTemplate) { if (auto *TD = getAsTypeTemplateDecl(IIDecl)) { assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); + // FIXME: Support UsingType here. TemplateName Template = Context.getQualifiedTemplateName( - SS ? SS->getScopeRep() : nullptr, /*TemplateKeyword=*/false, + SS ? SS->getScopeRep() : std::nullopt, /*TemplateKeyword=*/false, FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD)); QualType T = Context.getDeducedTemplateSpecializationType( ElaboratedTypeKeyword::None, Template, QualType(), false); @@ -582,31 +584,23 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, } } - if (T.isNull()) { - // If it's not plausibly a type, suppress diagnostics. - Result.suppressDiagnostics(); - return nullptr; - } - - if (FoundUsingShadow) - T = Context.getUsingType(FoundUsingShadow, T); - - return buildNamedType(*this, SS, T, NameLoc, WantNontrivialTypeSourceInfo); + // As it's not plausibly a type, suppress diagnostics. + Result.suppressDiagnostics(); + return nullptr; } // Builds a fake NNS for the given decl context. -static NestedNameSpecifier * +static NestedNameSpecifier synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { for (;; DC = DC->getLookupParent()) { DC = DC->getPrimaryContext(); auto *ND = dyn_cast(DC); if (ND && !ND->isInline() && !ND->isAnonymousNamespace()) - return NestedNameSpecifier::Create(Context, nullptr, ND); + return NestedNameSpecifier(Context, ND, std::nullopt); if (auto *RD = dyn_cast(DC)) - return NestedNameSpecifier::Create(Context, nullptr, - RD->getTypeForDecl()); + return NestedNameSpecifier(Context.getCanonicalTagType(RD)->getTypePtr()); if (isa(DC)) - return NestedNameSpecifier::GlobalSpecifier(Context); + return NestedNameSpecifier::getGlobal(); } llvm_unreachable("something isn't in TU scope?"); } @@ -631,7 +625,7 @@ ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II, bool IsTemplateTypeArg) { assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode"); - NestedNameSpecifier *NNS = nullptr; + NestedNameSpecifier NNS = std::nullopt; if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) { // If we weren't able to parse a default template argument, delay lookup // until instantiation time by making a non-dependent DependentTypeName. We @@ -646,7 +640,7 @@ ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II, findRecordWithDependentBasesOfEnclosingMethod(CurContext)) { // Build a DependentNameType that will perform lookup into RD at // instantiation time. - NNS = NestedNameSpecifier::Create(Context, nullptr, RD->getTypeForDecl()); + NNS = NestedNameSpecifier(Context.getCanonicalTagType(RD)->getTypePtr()); // Diagnose that this identifier was undeclared, and retry the lookup during // template instantiation. @@ -699,19 +693,22 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { } bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { - if (CurContext->isRecord()) { - if (SS->getScopeRep()->getKind() == NestedNameSpecifier::Super) - return true; + if (!CurContext->isRecord()) + return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); - const Type *Ty = SS->getScopeRep()->getAsType(); - - CXXRecordDecl *RD = cast(CurContext); - for (const auto &Base : RD->bases()) - if (Ty && Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType())) + switch (SS->getScopeRep().getKind()) { + case NestedNameSpecifier::Kind::MicrosoftSuper: + return true; + case NestedNameSpecifier::Kind::Type: { + QualType T(SS->getScopeRep().getAsType(), 0); + for (const auto &Base : cast(CurContext)->bases()) + if (Context.hasSameUnqualifiedType(T, Base.getType())) return true; + [[fallthrough]]; + } + default: return S->isFunctionPrototypeScope(); } - return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, @@ -815,12 +812,13 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) DiagID = diag::ext_typename_missing; + SuggestedType = + ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); + Diag(SS->getRange().getBegin(), DiagID) - << NestedNameSpecifier::Create(Context, SS->getScopeRep(), II) + << GetTypeFromParser(SuggestedType) << SourceRange(SS->getRange().getBegin(), IILoc) << FixItHint::CreateInsertion(SS->getRange().getBegin(), "typename "); - SuggestedType = ActOnTypenameType(S, SourceLocation(), - *SS, *II, IILoc).get(); } else { assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 5ed59afd77e59..0477d37cac4c5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12456,9 +12456,7 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, S = S->getDeclParent(); UsingDirectiveDecl *UDir = nullptr; - NestedNameSpecifier *Qualifier = nullptr; - if (SS.isSet()) - Qualifier = SS.getScopeRep(); + NestedNameSpecifier Qualifier = SS.getScopeRep(); // Lookup namespace name. LookupResult R(*this, NamespcName, IdentLoc, LookupNamespaceName); @@ -12470,14 +12468,16 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc, R.clear(); // Allow "using namespace std;" or "using namespace ::std;" even if // "std" hasn't been defined yet, for GCC compatibility. - if ((!Qualifier || Qualifier->getKind() == NestedNameSpecifier::Global) && + if ((!Qualifier || + Qualifier.getKind() == NestedNameSpecifier::Kind::Global) && NamespcName->isStr("std")) { Diag(IdentLoc, diag::ext_using_undefined_std); R.addDecl(getOrCreateStdNamespace()); R.resolveKind(); } // Otherwise, attempt typo correction. - else TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName); + else + TryNamespaceTypoCorrection(*this, R, S, SS, IdentLoc, NamespcName); } if (!R.empty()) { @@ -12955,7 +12955,7 @@ namespace { class UsingValidatorCCC final : public CorrectionCandidateCallback { public: UsingValidatorCCC(bool HasTypenameKeyword, bool IsInstantiation, - NestedNameSpecifier *NNS, CXXRecordDecl *RequireMemberOf) + NestedNameSpecifier NNS, CXXRecordDecl *RequireMemberOf) : HasTypenameKeyword(HasTypenameKeyword), IsInstantiation(IsInstantiation), OldNNS(NNS), RequireMemberOf(RequireMemberOf) {} @@ -12982,24 +12982,23 @@ class UsingValidatorCCC final : public CorrectionCandidateCallback { ASTContext &Ctx = ND->getASTContext(); if (!Ctx.getLangOpts().CPlusPlus11) return false; - QualType FoundType = Ctx.getRecordType(FoundRecord); + CanQualType FoundType = Ctx.getCanonicalTagType(FoundRecord); // Check that the injected-class-name is named as a member of its own // type; we don't want to suggest 'using Derived::Base;', since that // means something else. - NestedNameSpecifier *Specifier = - Candidate.WillReplaceSpecifier() - ? Candidate.getCorrectionSpecifier() - : OldNNS; - if (!Specifier->getAsType() || - !Ctx.hasSameType(QualType(Specifier->getAsType(), 0), FoundType)) + NestedNameSpecifier Specifier = Candidate.WillReplaceSpecifier() + ? Candidate.getCorrectionSpecifier() + : OldNNS; + if (Specifier.getKind() != NestedNameSpecifier::Kind::Type || + !Ctx.hasSameType(QualType(Specifier.getAsType(), 0), FoundType)) return false; // Check that this inheriting constructor declaration actually names a // direct base class of the current class. bool AnyDependentBases = false; if (!findDirectBaseWithType(RequireMemberOf, - Ctx.getRecordType(FoundRecord), + Ctx.getCanonicalTagType(FoundRecord), AnyDependentBases) && !AnyDependentBases) return false; @@ -13029,7 +13028,7 @@ class UsingValidatorCCC final : public CorrectionCandidateCallback { private: bool HasTypenameKeyword; bool IsInstantiation; - NestedNameSpecifier *OldNNS; + NestedNameSpecifier OldNNS; CXXRecordDecl *RequireMemberOf; }; } // end anonymous namespace @@ -13411,7 +13410,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Prev) { - NestedNameSpecifier *Qual = SS.getScopeRep(); + NestedNameSpecifier Qual = SS.getScopeRep(); // C++03 [namespace.udecl]p8: // C++0x [namespace.udecl]p10: @@ -13443,13 +13442,12 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, return false; } - const NestedNameSpecifier *CNNS = - Context.getCanonicalNestedNameSpecifier(Qual); + NestedNameSpecifier CNNS = Qual.getCanonical(); for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; bool DTypename; - NestedNameSpecifier *DQual; + NestedNameSpecifier DQual = std::nullopt; if (UsingDecl *UD = dyn_cast(D)) { DTypename = UD->hasTypename(); DQual = UD->getQualifier(); @@ -13470,7 +13468,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // using decls differ if they name different scopes (but note that // template instantiation can cause this check to trigger when it // didn't before instantiation). - if (CNNS != Context.getCanonicalNestedNameSpecifier(DQual)) + if (CNNS != DQual.getCanonical()) continue; Diag(NameLoc, diag::err_using_decl_redeclaration) << SS.getRange(); @@ -14903,10 +14901,9 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // reference to operator=; this is required to suppress the virtual // call mechanism. CXXScopeSpec SS; + // FIXME: Don't canonicalize this. const Type *CanonicalT = S.Context.getCanonicalType(T.getTypePtr()); - SS.MakeTrivial(S.Context, - NestedNameSpecifier::Create(S.Context, nullptr, CanonicalT), - Loc); + SS.MakeTrivial(S.Context, NestedNameSpecifier(CanonicalT), Loc); // Create the reference to operator=. ExprResult OpEqualRef diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3de6936eef9bb..813cf42862353 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2704,8 +2704,7 @@ recoverFromMSUnqualifiedLookup(Sema &S, ASTContext &Context, // Synthesize a fake NNS that points to the derived class. This will // perform name lookup during template instantiation. CXXScopeSpec SS; - auto *NNS = - NestedNameSpecifier::Create(Context, nullptr, RD->getTypeForDecl()); + NestedNameSpecifier NNS(Context.getCanonicalTagType(RD)->getTypePtr()); SS.MakeTrivial(Context, NNS, SourceRange(Loc, Loc)); return DependentScopeDeclRefExpr::Create( Context, SS.getWithLocInContext(Context), TemplateKWLoc, NameInfo, @@ -2995,11 +2994,10 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr( return BuildDeclarationNameExpr(SS, R, /*ADL=*/false); } -ExprResult -Sema::PerformObjectMemberConversion(Expr *From, - NestedNameSpecifier *Qualifier, - NamedDecl *FoundDecl, - NamedDecl *Member) { +ExprResult Sema::PerformObjectMemberConversion(Expr *From, + NestedNameSpecifier Qualifier, + NamedDecl *FoundDecl, + NamedDecl *Member) { const auto *RD = dyn_cast(Member->getDeclContext()); if (!RD) return From; @@ -3088,8 +3086,8 @@ Sema::PerformObjectMemberConversion(Expr *From, // x = 17; // error: ambiguous base subobjects // Derived1::x = 17; // okay, pick the Base subobject of Derived1 // } - if (Qualifier && Qualifier->getAsType()) { - QualType QType = QualType(Qualifier->getAsType(), 0); + if (Qualifier.getKind() == NestedNameSpecifier::Kind::Type) { + QualType QType = QualType(Qualifier.getAsType(), 0); assert(QType->isRecordType() && "lookup done with non-record type"); QualType QRecordType = QualType(QType->castAs(), 0); @@ -21230,7 +21228,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { NamedDecl *Temp = *ULE->decls_begin(); const bool IsTypeAliasTemplateDecl = isa(Temp); - NestedNameSpecifier *NNS = ULE->getQualifierLoc().getNestedNameSpecifier(); + NestedNameSpecifier NNS = ULE->getQualifierLoc().getNestedNameSpecifier(); // FIXME: AssumedTemplate is not very appropriate for error recovery here, // as it models only the unqualified-id case, where this case can clearly be // qualified. Thus we can't just qualify an assumed template. diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index de064834314fa..c3e57c1f7eff9 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -57,11 +57,11 @@ using namespace sema; ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, const IdentifierInfo &Name) { - NestedNameSpecifier *NNS = SS.getScopeRep(); - if ([[maybe_unused]] const IdentifierInfo *II = NNS->getAsIdentifier()) - assert(II == &Name && "not a constructor name"); + NestedNameSpecifier NNS = SS.getScopeRep(); + QualType Type(NNS.getAsType(), 0); + if ([[maybe_unused]] const auto *DNT = dyn_cast(Type)) + assert(DNT->getIdentifier() == &Name && "not a constructor name"); - QualType Type(NNS->translateToType(Context), 0); // This reference to the type is located entirely at the location of the // final identifier in the qualified-id. return CreateParsedType(Type, @@ -310,15 +310,23 @@ ParsedType Sema::getDestructorName(const IdentifierInfo &II, // If both lookups succeed and find a dependent result, which result should // we retain? (Same question for p->~type-name().) - if (NestedNameSpecifier *Prefix = - SS.isSet() ? SS.getScopeRep()->getPrefix() : nullptr) { + auto Prefix = [&]() -> NestedNameSpecifierLoc { + NestedNameSpecifierLoc NNS = SS.getWithLocInContext(Context); + if (!NNS) + return NestedNameSpecifierLoc(); + if (auto TL = NNS.getAsTypeLoc()) + return TL.getPrefix(); + return NNS.getAsNamespaceAndPrefix().Prefix; + }(); + + if (Prefix) { // This is // // nested-name-specifier type-name :: ~ type-name // // Look for the second type-name in the nested-name-specifier. CXXScopeSpec PrefixSS; - PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); + PrefixSS.Adopt(Prefix); if (ParsedType T = LookupInNestedNameSpec(PrefixSS)) return T; } else { @@ -502,12 +510,8 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, << II << static_cast(Status) << Hint; } - if (!SS.isValid()) - return false; - - switch (SS.getScopeRep()->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::TypeSpec: + switch (SS.getScopeRep().getKind()) { + case NestedNameSpecifier::Kind::Type: // Per C++11 [over.literal]p2, literal operators can only be declared at // namespace scope. Therefore, this unqualified-id cannot name anything. // Reject it early, because we have no AST representation for this in the @@ -516,9 +520,10 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, << SS.getScopeRep(); return true; - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: - case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + case NestedNameSpecifier::Kind::Namespace: return false; } diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 89f5ccadbc416..ba0f783411427 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -2702,12 +2702,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS) { - auto *NNS = SS.getScopeRep(); - if (NNS && NNS->getKind() == NestedNameSpecifier::Super) - return LookupInSuper(R, NNS->getAsRecordDecl()); - else - - return LookupQualifiedName(R, LookupCtx); + NestedNameSpecifier Qualifier = SS.getScopeRep(); + if (Qualifier.getKind() == NestedNameSpecifier::Kind::MicrosoftSuper) + return LookupInSuper(R, Qualifier.getAsMicrosoftSuper()); + return LookupQualifiedName(R, LookupCtx); } bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, @@ -2744,9 +2742,9 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, // FIXME: '__super' lookup semantics could be implemented by a // LookupResult::isSuperLookup flag which skips the initial search of // the lookup context in LookupQualified. - if (NestedNameSpecifier *NNS = SS->getScopeRep(); - NNS->getKind() == NestedNameSpecifier::Super) - return LookupInSuper(R, NNS->getAsRecordDecl()); + if (NestedNameSpecifier Qualifier = SS->getScopeRep(); + Qualifier.getKind() == NestedNameSpecifier::Kind::MicrosoftSuper) + return LookupInSuper(R, Qualifier.getAsMicrosoftSuper()); } IsDependent = !DC && isDependentScopeSpecifier(*SS); } else { @@ -4553,40 +4551,101 @@ static void checkCorrectionVisibility(Sema &SemaRef, TypoCorrection &TC) { // the given NestedNameSpecifier (i.e. given a NestedNameSpecifier "foo::bar::", // fill the vector with the IdentifierInfo pointers for "foo" and "bar"). static void getNestedNameSpecifierIdentifiers( - NestedNameSpecifier *NNS, - SmallVectorImpl &Identifiers) { - if (NestedNameSpecifier *Prefix = NNS->getPrefix()) - getNestedNameSpecifierIdentifiers(Prefix, Identifiers); - else + NestedNameSpecifier NNS, + SmallVectorImpl &Identifiers) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: Identifiers.clear(); + return; - const IdentifierInfo *II = nullptr; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - II = NNS->getAsIdentifier(); - break; - - case NestedNameSpecifier::Namespace: { - const NamespaceBaseDecl *Namespace = NNS->getAsNamespace(); + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = NNS.getAsNamespaceAndPrefix(); + getNestedNameSpecifierIdentifiers(Prefix, Identifiers); if (const auto *NS = dyn_cast(Namespace); NS && NS->isAnonymousNamespace()) return; - II = Namespace->getIdentifier(); - break; + Identifiers.push_back(Namespace->getIdentifier()); + return; } - case NestedNameSpecifier::TypeSpec: - II = QualType(NNS->getAsType(), 0).getBaseTypeIdentifier(); + case NestedNameSpecifier::Kind::Type: { + for (const Type *T = NNS.getAsType(); /**/; /**/) { + switch (T->getTypeClass()) { + case Type::DependentName: { + auto *DT = cast(T); + getNestedNameSpecifierIdentifiers(DT->getQualifier(), Identifiers); + Identifiers.push_back(DT->getIdentifier()); + return; + } + case Type::TemplateSpecialization: { + TemplateName Name = + cast(T)->getTemplateName(); + if (const QualifiedTemplateName *QTN = + Name.getAsAdjustedQualifiedTemplateName()) { + getNestedNameSpecifierIdentifiers(QTN->getQualifier(), Identifiers); + Name = QTN->getUnderlyingTemplate(); + } + if (const auto *TD = Name.getAsTemplateDecl(/*IgnoreDeduced=*/true)) + Identifiers.push_back(TD->getIdentifier()); + return; + } + case Type::DependentTemplateSpecialization: { + const DependentTemplateStorage &S = + cast(T) + ->getDependentTemplateName(); + getNestedNameSpecifierIdentifiers(S.getQualifier(), Identifiers); + // FIXME: Should this dig into the Name as well? + // Identifiers.push_back(S.getName().getIdentifier()); + return; + } + case Type::SubstTemplateTypeParm: + T = cast(T) + ->getReplacementType() + .getTypePtr(); + continue; + case Type::TemplateTypeParm: + Identifiers.push_back(cast(T)->getIdentifier()); + return; + case Type::Decltype: + return; + case Type::Enum: + case Type::Record: + case Type::InjectedClassName: { + auto *TT = cast(T); + getNestedNameSpecifierIdentifiers(TT->getQualifier(), Identifiers); + Identifiers.push_back(TT->getOriginalDecl()->getIdentifier()); + return; + } + case Type::Typedef: { + auto *TT = cast(T); + getNestedNameSpecifierIdentifiers(TT->getQualifier(), Identifiers); + Identifiers.push_back(TT->getDecl()->getIdentifier()); + return; + } + case Type::Using: { + auto *TT = cast(T); + getNestedNameSpecifierIdentifiers(TT->getQualifier(), Identifiers); + Identifiers.push_back(TT->getDecl()->getIdentifier()); + return; + } + case Type::UnresolvedUsing: { + auto *TT = cast(T); + getNestedNameSpecifierIdentifiers(TT->getQualifier(), Identifiers); + Identifiers.push_back(TT->getDecl()->getIdentifier()); + return; + } + default: + Identifiers.push_back(QualType(T, 0).getBaseTypeIdentifier()); + return; + } + } break; + } - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return; } - - if (II) - Identifiers.push_back(II); } void TypoCorrectionConsumer::FoundDecl(NamedDecl *ND, NamedDecl *Hiding, @@ -4619,11 +4678,11 @@ void TypoCorrectionConsumer::FoundName(StringRef Name) { void TypoCorrectionConsumer::addKeywordResult(StringRef Keyword) { // Compute the edit distance between the typo and this keyword, // and add the keyword to the list of results. - addName(Keyword, nullptr, nullptr, true); + addName(Keyword, /*ND=*/nullptr, /*NNS=*/std::nullopt, /*isKeyword=*/true); } void TypoCorrectionConsumer::addName(StringRef Name, NamedDecl *ND, - NestedNameSpecifier *NNS, bool isKeyword) { + NestedNameSpecifier NNS, bool isKeyword) { // Use a simple length-based heuristic to determine the minimum possible // edit distance. If the minimum isn't good enough, bail out early. StringRef TypoStr = Typo->getName(); @@ -4715,10 +4774,10 @@ void TypoCorrectionConsumer::addNamespaces( Namespaces.addNameSpecifier(KNPair.first); bool SSIsTemplate = false; - if (NestedNameSpecifier *NNS = - (SS && SS->isValid()) ? SS->getScopeRep() : nullptr) { - if (const Type *T = NNS->getAsType()) - SSIsTemplate = T->getTypeClass() == Type::TemplateSpecialization; + if (NestedNameSpecifier NNS = (SS ? SS->getScopeRep() : std::nullopt)) { + if (NNS.getKind() == NestedNameSpecifier::Kind::Type) + SSIsTemplate = + NNS.getAsType()->getTypeClass() == Type::TemplateSpecialization; } // Do not transform this into an iterator-based loop. The loop body can // trigger the creation of further types (through lazy deserialization) and @@ -4820,17 +4879,15 @@ void TypoCorrectionConsumer::performQualifiedLookups() { for (const TypoCorrection &QR : QualifiedResults) { for (const auto &NSI : Namespaces) { DeclContext *Ctx = NSI.DeclCtx; - const Type *NSType = NSI.NameSpecifier->getAsType(); + CXXRecordDecl *NamingClass = NSI.NameSpecifier.getAsRecordDecl(); // If the current NestedNameSpecifier refers to a class and the // current correction candidate is the name of that class, then skip // it as it is unlikely a qualified version of the class' constructor // is an appropriate correction. - if (CXXRecordDecl *NSDecl = NSType ? NSType->getAsCXXRecordDecl() : - nullptr) { - if (NSDecl->getIdentifier() == QR.getCorrectionAsIdentifierInfo()) - continue; - } + if (NamingClass && + NamingClass->getIdentifier() == QR.getCorrectionAsIdentifierInfo()) + continue; TypoCorrection TC(QR); TC.ClearCorrectionDecls(); @@ -4895,10 +4952,10 @@ void TypoCorrectionConsumer::performQualifiedLookups() { TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( ASTContext &Context, DeclContext *CurContext, CXXScopeSpec *CurScopeSpec) : Context(Context), CurContextChain(buildContextChain(CurContext)) { - if (NestedNameSpecifier *NNS = - CurScopeSpec ? CurScopeSpec->getScopeRep() : nullptr) { + if (NestedNameSpecifier NNS = + CurScopeSpec ? CurScopeSpec->getScopeRep() : std::nullopt) { llvm::raw_string_ostream SpecifierOStream(CurNameSpecifier); - NNS->print(SpecifierOStream, Context.getPrintingPolicy()); + NNS.print(SpecifierOStream, Context.getPrintingPolicy()); getNestedNameSpecifierIdentifiers(NNS, CurNameSpecifierIdentifiers); } @@ -4912,7 +4969,7 @@ TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( // Add the global context as a NestedNameSpecifier SpecifierInfo SI = {cast(Context.getTranslationUnitDecl()), - NestedNameSpecifier::GlobalSpecifier(Context), 1}; + NestedNameSpecifier::getGlobal(), 1}; DistanceMap[1].push_back(SI); } @@ -4932,14 +4989,16 @@ auto TypoCorrectionConsumer::NamespaceSpecifierSet::buildContextChain( unsigned TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( - DeclContextList &DeclChain, NestedNameSpecifier *&NNS) { + DeclContextList &DeclChain, NestedNameSpecifier &NNS) { unsigned NumSpecifiers = 0; for (DeclContext *C : llvm::reverse(DeclChain)) { if (auto *ND = dyn_cast_or_null(C)) { - NNS = NestedNameSpecifier::Create(Context, NNS, ND); + NNS = NestedNameSpecifier(Context, ND, NNS); ++NumSpecifiers; } else if (auto *RD = dyn_cast_or_null(C)) { - NNS = NestedNameSpecifier::Create(Context, NNS, RD->getTypeForDecl()); + QualType T = Context.getTagType(ElaboratedTypeKeyword::None, NNS, RD, + /*OwnsTag=*/false); + NNS = NestedNameSpecifier(T.getTypePtr()); ++NumSpecifiers; } } @@ -4948,7 +5007,7 @@ TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( DeclContext *Ctx) { - NestedNameSpecifier *NNS = nullptr; + NestedNameSpecifier NNS = std::nullopt; unsigned NumSpecifiers = 0; DeclContextList NamespaceDeclChain(buildContextChain(Ctx)); DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); @@ -4966,7 +5025,7 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( // Add an explicit leading '::' specifier if needed. if (NamespaceDeclChain.empty()) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. - NNS = NestedNameSpecifier::GlobalSpecifier(Context); + NNS = NestedNameSpecifier::getGlobal(); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } else if (NamedDecl *ND = @@ -4978,12 +5037,12 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( llvm::raw_string_ostream SpecifierOStream(NewNameSpecifier); SmallVector NewNameSpecifierIdentifiers; getNestedNameSpecifierIdentifiers(NNS, NewNameSpecifierIdentifiers); - NNS->print(SpecifierOStream, Context.getPrintingPolicy()); + NNS.print(SpecifierOStream, Context.getPrintingPolicy()); SameNameSpecifier = NewNameSpecifier == CurNameSpecifier; } if (SameNameSpecifier || llvm::is_contained(CurContextIdentifiers, Name)) { // Rebuild the NestedNameSpecifier as a globally-qualified specifier. - NNS = NestedNameSpecifier::GlobalSpecifier(Context); + NNS = NestedNameSpecifier::getGlobal(); NumSpecifiers = buildNestedNameSpecifier(FullNamespaceDeclChain, NNS); } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1f87f4db5cb53..c02e205dc9cde 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3639,12 +3639,12 @@ Sema::MemberPointerConversionResult Sema::CheckMemberPointerConversion( CXXRecordDecl *FromClass = FromPtrType->getMostRecentCXXRecordDecl(), *ToClass = ToPtrType->getMostRecentCXXRecordDecl(); - auto DiagCls = [](PartialDiagnostic &PD, NestedNameSpecifier *Qual, - const CXXRecordDecl *Cls) { - if (declaresSameEntity(Qual->getAsRecordDecl(), Cls)) + auto DiagCls = [&](PartialDiagnostic &PD, NestedNameSpecifier Qual, + const CXXRecordDecl *Cls) { + if (declaresSameEntity(Qual.getAsRecordDecl(), Cls)) PD << Qual; else - PD << QualType(Cls->getTypeForDecl(), 0); + PD << Context.getCanonicalTagType(Cls); }; auto DiagFromTo = [&](PartialDiagnostic &PD) -> PartialDiagnostic & { DiagCls(PD, FromPtrType->getQualifier(), FromClass); @@ -3689,8 +3689,8 @@ Sema::MemberPointerConversionResult Sema::CheckMemberPointerConversion( ? diag::err_upcast_to_inaccessible_base : diag::err_downcast_from_inaccessible_base, [&](PartialDiagnostic &PD) { - NestedNameSpecifier *BaseQual = FromPtrType->getQualifier(), - *DerivedQual = ToPtrType->getQualifier(); + NestedNameSpecifier BaseQual = FromPtrType->getQualifier(), + DerivedQual = ToPtrType->getQualifier(); if (Direction == MemberPointerConversionDirection::Upcast) std::swap(BaseQual, DerivedQual); DiagCls(PD, DerivedQual, Derived); @@ -6062,7 +6062,7 @@ static ImplicitConversionSequence TryObjectArgumentInitialization( /// the implicit object parameter for the given Method with the given /// expression. ExprResult Sema::PerformImplicitObjectArgumentInitialization( - Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, + Expr *From, NestedNameSpecifier Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = Method->getFunctionObjectParameterType(); @@ -16081,7 +16081,7 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, CXXMethodDecl *Method = nullptr; bool HadMultipleCandidates = false; DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_public); - NestedNameSpecifier *Qualifier = nullptr; + NestedNameSpecifier Qualifier = std::nullopt; if (isa(NakedMemExpr)) { MemExpr = cast(NakedMemExpr); Method = cast(MemExpr->getMemberDecl()); @@ -16951,7 +16951,7 @@ ExprResult Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, assert(isa(SubExpr.get()) && "fixed to something other than a decl ref"); - NestedNameSpecifier *Qualifier = + NestedNameSpecifier Qualifier = cast(SubExpr.get())->getQualifier(); assert(Qualifier && "fixed to a member ref with no nested name qualifier"); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f6cf569c226ce..8ce14f4d282f8 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -291,7 +291,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, FoundUsingShadow ? TemplateName(FoundUsingShadow) : TemplateName(TD); assert(!FoundUsingShadow || FoundUsingShadow->getTargetDecl() == TD); if (!SS.isInvalid()) { - NestedNameSpecifier *Qualifier = SS.getScopeRep(); + NestedNameSpecifier Qualifier = SS.getScopeRep(); Template = Context.getQualifiedTemplateName(Qualifier, hasTemplateKeyword, Template); } @@ -363,9 +363,8 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, // The code is missing a 'template' keyword prior to the dependent template // name. - NestedNameSpecifier *Qualifier = (NestedNameSpecifier *)SS->getScopeRep(); SuggestedTemplate = TemplateTy::make(Context.getDependentTemplateName( - {Qualifier, &II, /*HasTemplateKeyword=*/false})); + {SS->getScopeRep(), &II, /*HasTemplateKeyword=*/false})); Diag(IILoc, diag::err_template_kw_missing) << SuggestedTemplate.get() << FixItHint::CreateInsertion(IILoc, "template "); @@ -2105,11 +2104,11 @@ DeclResult Sema::CheckClassTemplate( bool ShouldAddRedecl = !(TUK == TagUseKind::Friend && CurContext->isDependentContext()); - CXXRecordDecl *NewClass = - CXXRecordDecl::Create(Context, Kind, SemanticContext, KWLoc, NameLoc, Name, - PrevClassTemplate && ShouldAddRedecl ? - PrevClassTemplate->getTemplatedDecl() : nullptr, - /*DelayTypeCreation=*/true); + CXXRecordDecl *NewClass = CXXRecordDecl::Create( + Context, Kind, SemanticContext, KWLoc, NameLoc, Name, + PrevClassTemplate && ShouldAddRedecl + ? PrevClassTemplate->getTemplatedDecl() + : nullptr); SetNestedNameSpecifier(*this, NewClass, SS); if (NumOuterTemplateParamLists > 0) NewClass->setTemplateParameterListsInfo( @@ -2697,14 +2696,14 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, QualType T, const CXXScopeSpec &SS) { NestedNameSpecifierLoc NNSLoc(SS.getScopeRep(), SS.location_data()); - while (NestedNameSpecifier *NNS = NNSLoc.getNestedNameSpecifier()) { - if (const Type *CurType = NNS->getAsType()) { - if (Context.hasSameUnqualifiedType(T, QualType(CurType, 0))) - return NNSLoc.getTypeLoc().getSourceRange(); - } else + for (;;) { + NestedNameSpecifier NNS = NNSLoc.getNestedNameSpecifier(); + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) break; - - NNSLoc = NNSLoc.getPrefix(); + if (Context.hasSameUnqualifiedType(T, QualType(NNS.getAsType(), 0))) + return NNSLoc.castAsTypeLoc().getSourceRange(); + // FIXME: This will always be empty. + NNSLoc = NNSLoc.getAsNamespaceAndPrefix().Prefix; } return SourceRange(); @@ -2723,12 +2722,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // by the nested-name-specifier and walking out until we run out of types. SmallVector NestedTypes; QualType T; - if (SS.getScopeRep()) { - if (CXXRecordDecl *Record - = dyn_cast_or_null(computeDeclContext(SS, true))) - T = Context.getTypeDeclType(Record); + if (NestedNameSpecifier Qualifier = SS.getScopeRep(); + Qualifier.getKind() == NestedNameSpecifier::Kind::Type) { + if (CXXRecordDecl *Record = + dyn_cast_or_null(computeDeclContext(SS, true))) + T = Context.getCanonicalTagType(Record); else - T = QualType(SS.getScopeRep()->getAsType(), 0); + T = QualType(Qualifier.getAsType(), 0); } // If we found an explicit specialization that prevents us from needing @@ -2776,9 +2776,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // Look one step prior in a dependent template specialization type. if (const DependentTemplateSpecializationType *DependentTST = T->getAs()) { - if (NestedNameSpecifier *NNS = - DependentTST->getDependentTemplateName().getQualifier()) - T = QualType(NNS->getAsType(), 0); + if (NestedNameSpecifier NNS = + DependentTST->getDependentTemplateName().getQualifier(); + NNS.getKind() == NestedNameSpecifier::Kind::Type) + T = QualType(NNS.getAsType(), 0); else T = QualType(); continue; @@ -2786,8 +2787,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // Look one step prior in a dependent name type. if (const DependentNameType *DependentName = T->getAs()){ - if (NestedNameSpecifier *NNS = DependentName->getQualifier()) - T = QualType(NNS->getAsType(), 0); + if (NestedNameSpecifier NNS = DependentName->getQualifier(); + NNS.getKind() == NestedNameSpecifier::Kind::Type) + T = QualType(NNS.getAsType(), 0); else T = QualType(); continue; @@ -3874,8 +3876,9 @@ TypeResult Sema::ActOnTemplateIdType( // elaborated-type-specifier (7.1.5.3). if (!LookupCtx && isDependentScopeSpecifier(SS)) { // C++2a relaxes some of those restrictions in [temp.res]p5. - NestedNameSpecifier *NNS = - NestedNameSpecifier::Create(Context, SS.getScopeRep(), TemplateII); + QualType DNT = Context.getDependentNameType(ElaboratedTypeKeyword::None, + SS.getScopeRep(), TemplateII); + NestedNameSpecifier NNS(DNT.getTypePtr()); if (AllowImplicitTypename == ImplicitTypenameContext::Yes) { auto DB = DiagCompat(SS.getBeginLoc(), diag_compat::implicit_typename) << NNS; @@ -4939,7 +4942,7 @@ TemplateNameKind Sema::ActOnTemplateName(Scope *S, return TNK_Non_template; } - NestedNameSpecifier *Qualifier = SS.getScopeRep(); + NestedNameSpecifier Qualifier = SS.getScopeRep(); switch (Name.getKind()) { case UnqualifiedIdKind::IK_Identifier: @@ -5227,8 +5230,9 @@ static bool SubstDefaultTemplateArgument( /// /// \returns the substituted template argument, or NULL if an error occurred. static TemplateName SubstDefaultTemplateArgument( - Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateLoc, - SourceLocation RAngleLoc, TemplateTemplateParmDecl *Param, + Sema &SemaRef, TemplateDecl *Template, SourceLocation TemplateKWLoc, + SourceLocation TemplateLoc, SourceLocation RAngleLoc, + TemplateTemplateParmDecl *Param, ArrayRef SugaredConverted, ArrayRef CanonicalConverted, NestedNameSpecifierLoc &QualifierLoc) { @@ -5245,25 +5249,17 @@ static TemplateName SubstDefaultTemplateArgument( TemplateArgLists.addOuterTemplateArguments(std::nullopt); Sema::ContextRAII SavedContext(SemaRef, Template->getDeclContext()); - // Substitute into the nested-name-specifier first, - QualifierLoc = Param->getDefaultArgument().getTemplateQualifierLoc(); - if (QualifierLoc) { - QualifierLoc = - SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgLists); - if (!QualifierLoc) - return TemplateName(); - } - return SemaRef.SubstTemplateName( - QualifierLoc, - Param->getDefaultArgument().getArgument().getAsTemplate(), - Param->getDefaultArgument().getTemplateNameLoc(), - TemplateArgLists); + const TemplateArgumentLoc &A = Param->getDefaultArgument(); + QualifierLoc = A.getTemplateQualifierLoc(); + return SemaRef.SubstTemplateName(TemplateKWLoc, QualifierLoc, + A.getArgument().getAsTemplate(), + A.getTemplateNameLoc(), TemplateArgLists); } TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( - TemplateDecl *Template, SourceLocation TemplateLoc, - SourceLocation RAngleLoc, Decl *Param, + TemplateDecl *Template, SourceLocation TemplateKWLoc, + SourceLocation TemplateNameLoc, SourceLocation RAngleLoc, Decl *Param, ArrayRef SugaredConverted, ArrayRef CanonicalConverted, bool &HasDefaultArg) { HasDefaultArg = false; @@ -5301,17 +5297,16 @@ TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( return TemplateArgumentLoc(); HasDefaultArg = true; + const TemplateArgumentLoc &A = TempTempParm->getDefaultArgument(); NestedNameSpecifierLoc QualifierLoc; TemplateName TName = SubstDefaultTemplateArgument( - *this, Template, TemplateLoc, RAngleLoc, TempTempParm, SugaredConverted, - CanonicalConverted, QualifierLoc); + *this, Template, TemplateKWLoc, TemplateNameLoc, RAngleLoc, TempTempParm, + SugaredConverted, CanonicalConverted, QualifierLoc); if (TName.isNull()) return TemplateArgumentLoc(); - return TemplateArgumentLoc( - Context, TemplateArgument(TName), - TempTempParm->getDefaultArgument().getTemplateQualifierLoc(), - TempTempParm->getDefaultArgument().getTemplateNameLoc()); + return TemplateArgumentLoc(Context, TemplateArgument(TName), TemplateKWLoc, + QualifierLoc, A.getTemplateNameLoc()); } /// Convert a template-argument that we parsed as a type into a template, if @@ -5319,33 +5314,24 @@ TemplateArgumentLoc Sema::SubstDefaultTemplateArgumentIfAvailable( /// template template arguments and as template type arguments. static TemplateArgumentLoc convertTypeTemplateArgumentToTemplate(ASTContext &Context, TypeLoc TLoc) { - // Extract and step over any surrounding nested-name-specifier. - NestedNameSpecifierLoc QualLoc; - if (auto ETLoc = TLoc.getAs()) { - if (ETLoc.getTypePtr()->getKeyword() != ElaboratedTypeKeyword::None) - return TemplateArgumentLoc(); + auto TagLoc = TLoc.getAs(); + if (!TagLoc) + return TemplateArgumentLoc(); - QualLoc = ETLoc.getQualifierLoc(); - TLoc = ETLoc.getNamedTypeLoc(); - } // If this type was written as an injected-class-name, it can be used as a // template template argument. - if (auto InjLoc = TLoc.getAs()) - return TemplateArgumentLoc(Context, InjLoc.getTypePtr()->getTemplateName(), - QualLoc, InjLoc.getNameLoc()); - // If this type was written as an injected-class-name, it may have been // converted to a RecordType during instantiation. If the RecordType is // *not* wrapped in a TemplateSpecializationType and denotes a class // template specialization, it must have come from an injected-class-name. - if (auto RecLoc = TLoc.getAs()) - if (auto *CTSD = - dyn_cast(RecLoc.getDecl())) - return TemplateArgumentLoc(Context, - TemplateName(CTSD->getSpecializedTemplate()), - QualLoc, RecLoc.getNameLoc()); - return TemplateArgumentLoc(); + TemplateName Name = TagLoc.getTypePtr()->getTemplateName(Context); + if (Name.isNull()) + return TemplateArgumentLoc(); + + return TemplateArgumentLoc(Context, Name, + /*TemplateKWLoc=*/SourceLocation(), + TagLoc.getQualifierLoc(), TagLoc.getNameLoc()); } bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc, @@ -6023,7 +6009,7 @@ namespace { #include "clang/AST/TypeNodes.inc" bool VisitTagDecl(const TagDecl *Tag); - bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + bool VisitNestedNameSpecifier(NestedNameSpecifier NNS); }; } // end anonymous namespace @@ -6202,10 +6188,7 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentNameType( bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType( const DependentTemplateSpecializationType* T) { - if (auto *Q = T->getDependentTemplateName().getQualifier()) - return VisitNestedNameSpecifier(Q); - - return false; + return VisitNestedNameSpecifier(T->getDependentTemplateName().getQualifier()); } bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType( @@ -6271,20 +6254,15 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { } bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( - NestedNameSpecifier *NNS) { - assert(NNS); - if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix())) - return true; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Super: + NestedNameSpecifier NNS) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Namespace: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: return false; - - case NestedNameSpecifier::TypeSpec: - return Visit(QualType(NNS->getAsType(), 0)); + case NestedNameSpecifier::Kind::Type: + return Visit(QualType(NNS.getAsType(), 0)); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } @@ -7708,10 +7686,9 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument( assert(VD->getDeclContext()->isRecord() && (isa(VD) || isa(VD) || isa(VD))); - QualType ClassType - = Context.getTypeDeclType(cast(VD->getDeclContext())); - NestedNameSpecifier *Qualifier = - NestedNameSpecifier::Create(Context, nullptr, ClassType.getTypePtr()); + CanQualType ClassType = + Context.getCanonicalTagType(cast(VD->getDeclContext())); + NestedNameSpecifier Qualifier(ClassType.getTypePtr()); SS.MakeTrivial(Context, Qualifier, Loc); } @@ -8716,13 +8693,12 @@ DeclResult Sema::ActOnClassTemplateSpecialization( } // Create a new class template partial specialization declaration node. - ClassTemplatePartialSpecializationDecl *PrevPartial - = cast_or_null(PrevDecl); + ClassTemplatePartialSpecializationDecl *PrevPartial = + cast_or_null(PrevDecl); ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create( Context, Kind, DC, KWLoc, TemplateNameLoc, TemplateParams, - ClassTemplate, CTAI.CanonicalConverted, WrittenTy->getType(), - PrevPartial); + ClassTemplate, CTAI.CanonicalConverted, CanonType, PrevPartial); Partial->setTemplateArgsAsWritten(TemplateArgs); SetNestedNameSpecifier(*this, Partial, SS); if (TemplateParameterLists.size() > 1 && SS.isSet()) { @@ -9876,12 +9852,14 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. - for (NestedNameSpecifier *NNS = SS.getScopeRep(); NNS; - NNS = NNS->getPrefix()) - if (const Type *T = NNS->getAsType()) - if (isa(T)) - return true; - + for (NestedNameSpecifier NNS = SS.getScopeRep(); + NNS.getKind() == NestedNameSpecifier::Kind::Type; + /**/) { + const Type *T = NNS.getAsType(); + if (isa(T)) + return true; + NNS = T->getPrefix(); + } return false; } @@ -10783,7 +10761,7 @@ TypeResult Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // This has to hold, because SS is expected to be defined. assert(Name && "Expected a name in a dependent tag"); - NestedNameSpecifier *NNS = SS.getScopeRep(); + NestedNameSpecifier NNS = SS.getScopeRep(); if (!NNS) return true; @@ -10921,11 +10899,12 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return false; // ... within an explicitly-written template specialization... - if (!NNS || !NNS.getNestedNameSpecifier()->getAsType()) + if (NNS.getNestedNameSpecifier().getKind() != NestedNameSpecifier::Kind::Type) return false; - TypeLoc EnableIfTy = NNS.getTypeLoc(); - TemplateSpecializationTypeLoc EnableIfTSTLoc = - EnableIfTy.getAs(); + + // FIXME: Look through sugar. + auto EnableIfTSTLoc = + NNS.castAsTypeLoc().getAs(); if (!EnableIfTSTLoc || EnableIfTSTLoc.getNumArgs() == 0) return false; const TemplateSpecializationType *EnableIfTST = EnableIfTSTLoc.getTypePtr(); @@ -11022,7 +11001,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, if (!Ctx) { // If the nested-name-specifier is dependent and couldn't be // resolved to a type, build a typename type. - assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + assert(QualifierLoc.getNestedNameSpecifier().isDependent()); return Context.getDependentNameType(Keyword, QualifierLoc.getNestedNameSpecifier(), &II); diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1c6d30902bff3..85b1f409cf955 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -2103,26 +2103,19 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Result != TemplateDeductionResult::Success) return Result; - QualType TP; - if (MPP->isSugared()) { - TP = S.Context.getTypeDeclType(MPP->getMostRecentCXXRecordDecl()); - } else { - NestedNameSpecifier *QP = MPP->getQualifier(); - if (QP->getKind() == NestedNameSpecifier::Identifier) - // Skip translation if it's a non-deduced context anyway. - return TemplateDeductionResult::Success; - TP = QualType(QP->translateToType(S.Context), 0); - } + QualType TP = + MPP->isSugared() + ? S.Context.getCanonicalTagType(MPP->getMostRecentCXXRecordDecl()) + : QualType(MPP->getQualifier().getAsType(), 0); assert(!TP.isNull() && "member pointer with non-type class"); - QualType TA; - if (MPA->isSugared()) { - TA = S.Context.getTypeDeclType(MPA->getMostRecentCXXRecordDecl()); - } else { - NestedNameSpecifier *QA = MPA->getQualifier(); - TA = QualType(QA->translateToType(S.Context), 0).getUnqualifiedType(); - } + QualType TA = + MPA->isSugared() + ? S.Context.getCanonicalTagType(MPA->getMostRecentCXXRecordDecl()) + : QualType(MPA->getQualifier().getAsType(), 0) + .getUnqualifiedType(); assert(!TA.isNull() && "member pointer with non-type class"); + return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, TP, TA, Info, Deduced, SubTDF, degradeCallPartialOrderingKind(POK), @@ -6668,19 +6661,13 @@ MarkUsedTemplateParameters(ASTContext &Ctx, /// Mark the template parameters that are used by the given /// nested name specifier. -static void -MarkUsedTemplateParameters(ASTContext &Ctx, - NestedNameSpecifier *NNS, - bool OnlyDeduced, - unsigned Depth, - llvm::SmallBitVector &Used) { - if (!NNS) +static void MarkUsedTemplateParameters(ASTContext &Ctx, NestedNameSpecifier NNS, + bool OnlyDeduced, unsigned Depth, + llvm::SmallBitVector &Used) { + if (NNS.getKind() != NestedNameSpecifier::Kind::Type) return; - - MarkUsedTemplateParameters(Ctx, NNS->getPrefix(), OnlyDeduced, Depth, - Used); - MarkUsedTemplateParameters(Ctx, QualType(NNS->getAsType(), 0), - OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, QualType(NNS.getAsType(), 0), OnlyDeduced, + Depth, Used); } /// Mark the template parameters that are used by the given diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 037001a0b2bbc..c8ac720dbe632 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -180,10 +180,17 @@ class ExtractTypeForDeductionGuide MaterializedTypedefs.push_back(Decl); } - QualType TDTy = Context.getTypedefType(Decl); - TypedefTypeLoc TypedefTL = TLB.push(TDTy); - TypedefTL.setNameLoc(TL.getNameLoc()); + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + } + QualType TDTy = Context.getTypedefType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), Decl); + TLB.push(TDTy).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); return TDTy; } }; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 5c14d890f94d5..1e01723fbc93f 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -353,45 +353,50 @@ Response HandleFunctionTemplateDecl(Sema &SemaRef, SemaRef.Context), /*Final=*/false); - NestedNameSpecifier *NNS = FTD->getTemplatedDecl()->getQualifier(); - - while (const Type *Ty = NNS ? NNS->getAsType() : nullptr) { - if (NNS->isInstantiationDependent()) { - if (const auto *TSTy = Ty->getAs()) { - ArrayRef Arguments = TSTy->template_arguments(); - // Prefer template arguments from the injected-class-type if possible. - // For example, - // ```cpp - // template struct S { - // template void foo(); - // }; - // template template - // ^^^^^^^^^^^^^ InjectedTemplateArgs - // They're of kind TemplateArgument::Pack, not of - // TemplateArgument::Type. - // void S::foo() {} - // ^^^^^^^ - // TSTy->template_arguments() (which are of PackExpansionType) - // ``` - // This meets the contract in - // TreeTransform::TryExpandParameterPacks that the template arguments - // for unexpanded parameters should be of a Pack kind. - if (TSTy->isCurrentInstantiation()) { - auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); - if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) - Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context); - else if (auto *Specialization = - dyn_cast(RD)) - Arguments = - Specialization->getTemplateInstantiationArgs().asArray(); - } - Result.addOuterTemplateArguments( - TSTy->getTemplateName().getAsTemplateDecl(), Arguments, - /*Final=*/false); - } - } + NestedNameSpecifier NNS = FTD->getTemplatedDecl()->getQualifier(); + + for (const Type *Ty = NNS.getKind() == NestedNameSpecifier::Kind::Type + ? NNS.getAsType() + : nullptr, + *NextTy = nullptr; + Ty && Ty->isInstantiationDependentType(); + Ty = std::exchange(NextTy, nullptr)) { + if (NestedNameSpecifier P = Ty->getPrefix(); + P.getKind() == NestedNameSpecifier::Kind::Type) + NextTy = P.getAsType(); + const auto *TSTy = dyn_cast(Ty); + if (!TSTy) + continue; - NNS = NNS->getPrefix(); + ArrayRef Arguments = TSTy->template_arguments(); + // Prefer template arguments from the injected-class-type if possible. + // For example, + // ```cpp + // template struct S { + // template void foo(); + // }; + // template template + // ^^^^^^^^^^^^^ InjectedTemplateArgs + // They're of kind TemplateArgument::Pack, not of + // TemplateArgument::Type. + // void S::foo() {} + // ^^^^^^^ + // TSTy->template_arguments() (which are of PackExpansionType) + // ``` + // This meets the contract in + // TreeTransform::TryExpandParameterPacks that the template arguments + // for unexpanded parameters should be of a Pack kind. + if (TSTy->isCurrentInstantiation()) { + auto *RD = TSTy->getCanonicalTypeInternal()->getAsCXXRecordDecl(); + if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) + Arguments = CTD->getInjectedTemplateArgs(SemaRef.Context); + else if (auto *Specialization = + dyn_cast(RD)) + Arguments = Specialization->getTemplateInstantiationArgs().asArray(); + } + Result.addOuterTemplateArguments( + TSTy->getTemplateName().getAsTemplateDecl(), Arguments, + /*Final=*/false); } } @@ -1595,15 +1600,9 @@ namespace { VarDecl *RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, TypeSourceInfo *TSInfo, QualType T); - /// Check for tag mismatches when instantiating an - /// elaborated type. - QualType RebuildElaboratedType(SourceLocation KeywordLoc, - ElaboratedTypeKeyword Keyword, - NestedNameSpecifierLoc QualifierLoc, - QualType T); - TemplateName - TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, + TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc, + SourceLocation TemplateKWLoc, TemplateName Name, SourceLocation NameLoc, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = nullptr, @@ -2080,9 +2079,9 @@ VarDecl *TemplateInstantiator::RebuildObjCExceptionDecl(VarDecl *ExceptionDecl, } TemplateName TemplateInstantiator::TransformTemplateName( - CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc, - QualType ObjectType, NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { + NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, QualType ObjectType, + NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (TemplateTemplateParmDecl *TTP = dyn_cast_or_null(Name.getAsTemplateDecl())) { if (TTP->getDepth() < TemplateArgs.getNumLevels()) { @@ -2129,6 +2128,12 @@ TemplateName TemplateInstantiator::TransformTemplateName( TemplateName Template = Arg.getAsTemplate(); assert(!Template.isNull() && "Null template template argument"); + if (NestedNameSpecifier Qualifier = Template.getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(SemaRef.Context, Qualifier, NameLoc); + QualifierLoc = Builder.getWithLocInContext(SemaRef.Context); + } + return getSema().Context.getSubstTemplateTemplateParm( Template, AssociatedDecl, TTP->getIndex(), PackIndex, Final); } @@ -4519,14 +4524,14 @@ Sema::SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, } TemplateName -Sema::SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, - TemplateName Name, SourceLocation Loc, +Sema::SubstTemplateName(SourceLocation TemplateKWLoc, + NestedNameSpecifierLoc &QualifierLoc, TemplateName Name, + SourceLocation NameLoc, const MultiLevelTemplateArgumentList &TemplateArgs) { - TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, + TemplateInstantiator Instantiator(*this, TemplateArgs, NameLoc, DeclarationName()); - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - return Instantiator.TransformTemplateName(SS, Name, Loc); + return Instantiator.TransformTemplateName(QualifierLoc, TemplateKWLoc, Name, + NameLoc); } static const Decl *getCanonicalParmVarDecl(const Decl *D) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 5e49645ec2379..755cbb6e4547d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3783,19 +3783,18 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( D->getPosition(), D->isParameterPack(), D->getIdentifier(), D->wasDeclaredWithTypename(), InstParams); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { - NestedNameSpecifierLoc QualifierLoc = - D->getDefaultArgument().getTemplateQualifierLoc(); - QualifierLoc = - SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, TemplateArgs); + const TemplateArgumentLoc &A = D->getDefaultArgument(); + NestedNameSpecifierLoc QualifierLoc = A.getTemplateQualifierLoc(); + // FIXME: Pass in the template keyword location. TemplateName TName = SemaRef.SubstTemplateName( - QualifierLoc, D->getDefaultArgument().getArgument().getAsTemplate(), - D->getDefaultArgument().getTemplateNameLoc(), TemplateArgs); + A.getTemplateKWLoc(), QualifierLoc, A.getArgument().getAsTemplate(), + A.getTemplateNameLoc(), TemplateArgs); if (!TName.isNull()) Param->setDefaultArgument( SemaRef.Context, TemplateArgumentLoc(SemaRef.Context, TemplateArgument(TName), - D->getDefaultArgument().getTemplateQualifierLoc(), - D->getDefaultArgument().getTemplateNameLoc())); + A.getTemplateKWLoc(), QualifierLoc, + A.getTemplateNameLoc())); } Param->setAccess(AS_public); Param->setImplicit(D->isImplicit()); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 2bb95a738e0ab..05ab55c6d304c 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -3654,11 +3654,22 @@ static void warnAboutRedundantParens(Sema &S, Declarator &D, QualType T) { // here: even (e.g.) "int ::x" is visually ambiguous even though it's // formally unambiguous. if (StartsWithDeclaratorId && D.getCXXScopeSpec().isValid()) { - for (NestedNameSpecifier *NNS = D.getCXXScopeSpec().getScopeRep(); NNS; - NNS = NNS->getPrefix()) { - if (NNS->getKind() == NestedNameSpecifier::Global) + NestedNameSpecifier NNS = D.getCXXScopeSpec().getScopeRep(); + for (;;) { + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Global: return; + case NestedNameSpecifier::Kind::Type: + NNS = NNS.getAsType()->getPrefix(); + continue; + case NestedNameSpecifier::Kind::Namespace: + NNS = NNS.getAsNamespaceAndPrefix().Prefix; + continue; + default: + goto out; + } } + out:; } S.Diag(Paren.Loc, diag::warn_redundant_parens_around_declarator) @@ -5321,7 +5332,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, state.getDeclarator() .getCXXScopeSpec() .getScopeRep() - ->getKind() == NestedNameSpecifier::TypeSpec) || + .getKind() == NestedNameSpecifier::Kind::Type) || state.getDeclarator().getContext() == DeclaratorContext::Member || state.getDeclarator().getContext() == diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp index eddad958a7ceb..9b9dd172003a0 100644 --- a/clang/lib/Sema/SemaTypeTraits.cpp +++ b/clang/lib/Sema/SemaTypeTraits.cpp @@ -2016,11 +2016,10 @@ static ExtractedTypeTraitInfo ExtractTypeTraitFromExpression(const Expr *E) { // std::is_xxx<>::value if (const auto *VD = dyn_cast(Ref->getDecl()); Ref->hasQualifier() && VD && VD->getIdentifier()->isStr("value")) { - const Type *T = Ref->getQualifier()->getAsType(); - if (!T) + NestedNameSpecifier Qualifier = Ref->getQualifier(); + if (Qualifier.getKind() != NestedNameSpecifier::Kind::Type) return std::nullopt; - const TemplateSpecializationType *Ts = - T->getAs(); + const auto *Ts = Qualifier.getAsType()->getAs(); if (!Ts) return std::nullopt; const TemplateDecl *D = Ts->getTemplateName().getAsTemplateDecl(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 6777aa6538113..d39cd7590b726 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -591,12 +591,12 @@ class TreeTransform { /// By default, transforms the template name by transforming the declarations /// and nested-name-specifiers that occur within the template name. /// Subclasses may override this function to provide alternate behavior. - TemplateName - TransformTemplateName(CXXScopeSpec &SS, TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType = QualType(), - NamedDecl *FirstQualifierInScope = nullptr, - bool AllowInjectedClassName = false); + TemplateName TransformTemplateName(NestedNameSpecifierLoc &QualifierLoc, + SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, + QualType ObjectType = QualType(), + NamedDecl *FirstQualifierInScope = nullptr, + bool AllowInjectedClassName = false); /// Transform the given template argument. /// @@ -1149,7 +1149,7 @@ class TreeTransform { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - if (QualifierLoc.getNestedNameSpecifier()->isDependent()) { + if (QualifierLoc.getNestedNameSpecifier().isDependent()) { // If the name is still dependent, just build a new dependent name type. if (!SemaRef.computeDeclContext(SS)) return SemaRef.Context.getDependentNameType(Keyword, @@ -4583,7 +4583,7 @@ NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( auto insertNNS = [&Qualifiers](NestedNameSpecifierLoc NNS) { for (NestedNameSpecifierLoc Qualifier = NNS; Qualifier; - Qualifier = Qualifier.getPrefix()) + Qualifier = Qualifier.getAsNamespaceAndPrefix().Prefix) Qualifiers.push_back(Qualifier); }; insertNNS(NNS); @@ -4591,76 +4591,87 @@ NestedNameSpecifierLoc TreeTransform::TransformNestedNameSpecifierLoc( CXXScopeSpec SS; while (!Qualifiers.empty()) { NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); - NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); - - switch (QNNS->getKind()) { - case NestedNameSpecifier::Identifier: { - Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(), - Q.getLocalBeginLoc(), Q.getLocalEndLoc(), - ObjectType); - if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false, - SS, FirstQualifierInScope, false)) - return NestedNameSpecifierLoc(); - break; - } + NestedNameSpecifier QNNS = Q.getNestedNameSpecifier(); - case NestedNameSpecifier::Namespace: { + switch (QNNS.getKind()) { + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); + + case NestedNameSpecifier::Kind::Namespace: { auto *NS = cast(getDerived().TransformDecl( - Q.getLocalBeginLoc(), QNNS->getAsNamespace())); + Q.getLocalBeginLoc(), const_cast( + QNNS.getAsNamespaceAndPrefix().Namespace))); SS.Extend(SemaRef.Context, NS, Q.getLocalBeginLoc(), Q.getLocalEndLoc()); break; } - case NestedNameSpecifier::Global: + case NestedNameSpecifier::Kind::Global: // There is no meaningful transformation that one could perform on the // global scope. SS.MakeGlobal(SemaRef.Context, Q.getBeginLoc()); break; - case NestedNameSpecifier::Super: { - CXXRecordDecl *RD = - cast_or_null(getDerived().TransformDecl( - SourceLocation(), QNNS->getAsRecordDecl())); - SS.MakeSuper(SemaRef.Context, RD, Q.getBeginLoc(), Q.getEndLoc()); + case NestedNameSpecifier::Kind::MicrosoftSuper: { + CXXRecordDecl *RD = cast_or_null( + getDerived().TransformDecl(SourceLocation(), QNNS.getAsRecordDecl())); + SS.MakeMicrosoftSuper(SemaRef.Context, RD, Q.getBeginLoc(), + Q.getEndLoc()); break; } - case NestedNameSpecifier::TypeSpec: { - TypeLoc TL = TransformTypeInObjectScope(Q.getTypeLoc(), ObjectType, - FirstQualifierInScope, SS); - - if (!TL) - return NestedNameSpecifierLoc(); + case NestedNameSpecifier::Kind::Type: { + assert(SS.isEmpty()); + TypeLoc TL = Q.castAsTypeLoc(); + + if (auto DNT = TL.getAs()) { + NestedNameSpecifierLoc QualifierLoc = DNT.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return NestedNameSpecifierLoc(); + ObjectType = QualType(); + FirstQualifierInScope = nullptr; + } + SS.Adopt(QualifierLoc); + Sema::NestedNameSpecInfo IdInfo( + const_cast(DNT.getTypePtr()->getIdentifier()), + DNT.getNameLoc(), Q.getLocalEndLoc(), ObjectType); + if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, + false, SS, + FirstQualifierInScope, false)) + return NestedNameSpecifierLoc(); + return SS.getWithLocInContext(SemaRef.Context); + } QualType T = TL.getType(); + TypeLocBuilder TLB; + if (!getDerived().AlreadyTransformed(T)) { + T = TransformTypeInObjectScope(TLB, TL, ObjectType, + FirstQualifierInScope); + if (T.isNull()) + return NestedNameSpecifierLoc(); + TL = TLB.getTypeLocInContext(SemaRef.Context, T); + } + if (T->isDependentType() || T->isRecordType() || (SemaRef.getLangOpts().CPlusPlus11 && T->isEnumeralType())) { if (T->isEnumeralType()) SemaRef.Diag(TL.getBeginLoc(), diag::warn_cxx98_compat_enum_nested_name_spec); - - if (const auto ETL = TL.getAs()) { - SS.Adopt(ETL.getQualifierLoc()); - TL = ETL.getNamedTypeLoc(); - } - - SS.Extend(SemaRef.Context, TL, Q.getLocalEndLoc()); + SS.Make(SemaRef.Context, TL, Q.getLocalEndLoc()); break; } // If the nested-name-specifier is an invalid type def, don't emit an // error because a previous error should have already been emitted. TypedefTypeLoc TTL = TL.getAsAdjusted(); - if (!TTL || !TTL.getTypedefNameDecl()->isInvalidDecl()) { + if (!TTL || !TTL.getDecl()->isInvalidDecl()) { SemaRef.Diag(TL.getBeginLoc(), diag::err_nested_name_spec_non_tag) << T << SS.getRange(); } return NestedNameSpecifierLoc(); } } - - // The qualifier-in-scope and object type only apply to the leftmost entity. - FirstQualifierInScope = nullptr; - ObjectType = QualType(); } // Don't rebuild the nested-name-specifier if we don't have to. @@ -4746,30 +4757,32 @@ template TemplateName TreeTransform::RebuildTemplateName( CXXScopeSpec &SS, SourceLocation TemplateKWLoc, IdentifierOrOverloadedOperator IO, SourceLocation NameLoc, - QualType ObjectType, NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { - if (const IdentifierInfo *II = IO.getIdentifier()) { + QualType ObjectType, bool AllowInjectedClassName) { + if (const IdentifierInfo *II = IO.getIdentifier()) return getDerived().RebuildTemplateName(SS, TemplateKWLoc, *II, NameLoc, - ObjectType, FirstQualifierInScope, - AllowInjectedClassName); - } + ObjectType, AllowInjectedClassName); return getDerived().RebuildTemplateName(SS, TemplateKWLoc, IO.getOperator(), NameLoc, ObjectType, AllowInjectedClassName); } -template -TemplateName -TreeTransform::TransformTemplateName(CXXScopeSpec &SS, - TemplateName Name, - SourceLocation NameLoc, - QualType ObjectType, - NamedDecl *FirstQualifierInScope, - bool AllowInjectedClassName) { +template +TemplateName TreeTransform::TransformTemplateName( + NestedNameSpecifierLoc &QualifierLoc, SourceLocation TemplateKWLoc, + TemplateName Name, SourceLocation NameLoc, QualType ObjectType, + NamedDecl *FirstQualifierInScope, bool AllowInjectedClassName) { if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { + // FIXME: Preserve UsingTemplateName. TemplateDecl *Template = QTN->getUnderlyingTemplate().getAsTemplateDecl(); assert(Template && "qualified template name must refer to a template"); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return TemplateName(); + } + TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); @@ -4777,41 +4790,67 @@ TreeTransform::TransformTemplateName(CXXScopeSpec &SS, return TemplateName(); if (!getDerived().AlwaysRebuild() && - SS.getScopeRep() == QTN->getQualifier() && + QualifierLoc.getNestedNameSpecifier() == QTN->getQualifier() && TransTemplate == Template) return Name; - + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); return getDerived().RebuildTemplateName(SS, QTN->hasTemplateKeyword(), TransTemplate); } if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { - if (SS.getScopeRep()) { - // These apply to the scope specifier, not the template. + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, FirstQualifierInScope); + if (!QualifierLoc) + return TemplateName(); + // The qualifier-in-scope and object type only apply to the leftmost + // entity. ObjectType = QualType(); - FirstQualifierInScope = nullptr; } if (!getDerived().AlwaysRebuild() && - SS.getScopeRep() == DTN->getQualifier() && + QualifierLoc.getNestedNameSpecifier() == DTN->getQualifier() && ObjectType.isNull()) return Name; - // FIXME: Preserve the location of the "template" keyword. - SourceLocation TemplateKWLoc = NameLoc; - return getDerived().RebuildTemplateName( - SS, TemplateKWLoc, DTN->getName(), NameLoc, ObjectType, + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + return getDerived().RebuildTemplateName(SS, TemplateKWLoc, DTN->getName(), + NameLoc, ObjectType, + AllowInjectedClassName); + } + + if (SubstTemplateTemplateParmStorage *S = + Name.getAsSubstTemplateTemplateParm()) { + TemplateName NewName = getDerived().TransformTemplateName( + QualifierLoc, TemplateKWLoc, S->getReplacement(), NameLoc, ObjectType, FirstQualifierInScope, AllowInjectedClassName); + if (NewName.isNull()) + return TemplateName(); + Decl *AssociatedDecl = + getDerived().TransformDecl(NameLoc, S->getAssociatedDecl()); + if (!getDerived().AlwaysRebuild() && NewName == S->getReplacement() && + AssociatedDecl == S->getAssociatedDecl()) + return Name; + return SemaRef.Context.getSubstTemplateTemplateParm( + NewName, AssociatedDecl, S->getIndex(), S->getPackIndex(), + S->getFinal()); } - // FIXME: Try to preserve more of the TemplateName. + assert(!Name.getAsDeducedTemplateName() && + "DeducedTemplateName should not escape partial ordering"); + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + assert(!QualifierLoc && "missed a Qualified Template"); TemplateDecl *TransTemplate = cast_or_null(getDerived().TransformDecl(NameLoc, Template)); if (!TransTemplate) return TemplateName(); + CXXScopeSpec SS; return getDerived().RebuildTemplateName(SS, /*TemplateKeyword=*/false, TransTemplate); } @@ -4903,21 +4942,16 @@ bool TreeTransform::TransformTemplateArgument( case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); - if (QualifierLoc) { - QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); - if (!QualifierLoc) - return true; - } - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); TemplateName Template = getDerived().TransformTemplateName( - SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); + QualifierLoc, Input.getTemplateKWLoc(), Arg.getAsTemplate(), + Input.getTemplateNameLoc()); if (Template.isNull()) return true; Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), - QualifierLoc, Input.getTemplateNameLoc()); + Input.getTemplateKWLoc(), QualifierLoc, + Input.getTemplateNameLoc()); return false; } @@ -6620,23 +6654,38 @@ QualType TreeTransform::TransformFunctionNoProtoType( template QualType TreeTransform::TransformUnresolvedUsingType( TypeLocBuilder &TLB, UnresolvedUsingTypeLoc TL) { + const UnresolvedUsingType *T = TL.getTypePtr(); - Decl *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); + bool Changed = false; + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } + + auto *D = getDerived().TransformDecl(TL.getNameLoc(), T->getDecl()); if (!D) return QualType(); + Changed |= D != T->getDecl(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || D != T->getDecl()) { - Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildUnresolvedUsingType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), TL.getNameLoc(), + D); if (Result.isNull()) return QualType(); } - // We might get an arbitrary type spec type back. We should at - // least always get a type spec type, though. - TypeSpecTypeLoc NewTL = TLB.pushTypeSpec(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + if (isa(Result)) + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); + else + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); return Result; } @@ -6644,25 +6693,37 @@ template QualType TreeTransform::TransformUsingType(TypeLocBuilder &TLB, UsingTypeLoc TL) { const UsingType *T = TL.getTypePtr(); + bool Changed = false; + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } - auto *Found = cast_or_null(getDerived().TransformDecl( - TL.getLocalSourceRange().getBegin(), T->getFoundDecl())); - if (!Found) + auto *D = cast_or_null( + getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); + if (!D) return QualType(); + Changed |= D != T->getDecl(); - QualType Underlying = getDerived().TransformType(T->desugar()); - if (Underlying.isNull()) + QualType UnderlyingType = getDerived().TransformType(T->desugar()); + if (UnderlyingType.isNull()) return QualType(); + Changed |= UnderlyingType != T->desugar(); QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || Found != T->getFoundDecl() || - Underlying != T->getUnderlyingType()) { - Result = getDerived().RebuildUsingType(Found, Underlying); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildUsingType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), D, + UnderlyingType); if (Result.isNull()) return QualType(); } - - TLB.pushTypeSpec(Result).setNameLoc(TL.getNameLoc()); + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), QualifierLoc, + TL.getNameLoc()); return Result; } @@ -6670,23 +6731,34 @@ template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { const TypedefType *T = TL.getTypePtr(); - TypedefNameDecl *Typedef - = cast_or_null(getDerived().TransformDecl(TL.getNameLoc(), - T->getDecl())); + bool Changed = false; + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (NestedNameSpecifierLoc OldQualifierLoc = QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(QualifierLoc); + if (!QualifierLoc) + return QualType(); + Changed |= QualifierLoc != OldQualifierLoc; + } + + auto *Typedef = cast_or_null( + getDerived().TransformDecl(TL.getNameLoc(), T->getDecl())); if (!Typedef) return QualType(); + Changed |= Typedef != T->getDecl(); + + // FIXME: Transform the UnderlyingType if different from decl. QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || - Typedef != T->getDecl()) { - Result = getDerived().RebuildTypedefType(Typedef); + if (getDerived().AlwaysRebuild() || Changed) { + Result = getDerived().RebuildTypedefType( + T->getKeyword(), QualifierLoc.getNestedNameSpecifier(), Typedef); if (Result.isNull()) return QualType(); } - TypedefTypeLoc NewTL = TLB.push(Result); - NewTL.setNameLoc(TL.getNameLoc()); - + TLB.push(Result).set(TL.getElaboratedKeywordLoc(), + QualifierLoc, TL.getNameLoc()); return Result; } @@ -6922,9 +6994,10 @@ QualType TreeTransform::TransformDeducedTemplateSpecializationType( TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { const DeducedTemplateSpecializationType *T = TL.getTypePtr(); - CXXScopeSpec SS; + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); TemplateName TemplateName = getDerived().TransformTemplateName( - SS, T->getTemplateName(), TL.getTemplateNameLoc()); + QualifierLoc, /*TemplateKELoc=*/SourceLocation(), T->getTemplateName(), + TL.getTemplateNameLoc()); if (TemplateName.isNull()) return QualType(); @@ -7301,9 +7374,16 @@ QualType TreeTransform::TransformAutoType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTemplateSpecializationType( - TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - TemplateName Template) { + TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { + const TemplateSpecializationType *T = TL.getTypePtr(); + + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + TemplateName Template = getDerived().TransformTemplateName( + QualifierLoc, TL.getTemplateKeywordLoc(), T->getTemplateName(), + TL.getTemplateNameLoc()); + if (Template.isNull()) + return QualType(); + TemplateArgumentListInfo NewTemplateArgs; NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); @@ -7538,15 +7618,22 @@ QualType TreeTransform::TransformDependentNameType( return TransformDependentNameType(TLB, TL, false); } -template +template QualType TreeTransform::TransformDependentNameType( - TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext) { + TypeLocBuilder &TLB, DependentNameTypeLoc TL, bool DeducedTSTContext, + QualType ObjectType, NamedDecl *UnqualLookup) { const DependentNameType *T = TL.getTypePtr(); - NestedNameSpecifierLoc QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - if (!QualifierLoc) - return QualType(); + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, UnqualLookup); + if (!QualifierLoc) + return QualType(); + } else { + assert((ObjectType.isNull() && !UnqualLookup) && + "must be transformed by TransformNestedNameSpecifierLoc"); + } QualType Result = getDerived().RebuildDependentNameType(T->getKeyword(), @@ -7580,33 +7667,34 @@ QualType TreeTransform::TransformDependentNameType( return Result; } -template -QualType TreeTransform:: - TransformDependentTemplateSpecializationType(TypeLocBuilder &TLB, - DependentTemplateSpecializationTypeLoc TL) { - NestedNameSpecifierLoc QualifierLoc; - if (TL.getQualifierLoc()) { - QualifierLoc - = getDerived().TransformNestedNameSpecifierLoc(TL.getQualifierLoc()); - if (!QualifierLoc) - return QualType(); - } - - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); - return getDerived().TransformDependentTemplateSpecializationType(TLB, TL, SS); +template +QualType TreeTransform::TransformDependentTemplateSpecializationType( + TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL) { + return getDerived().TransformDependentTemplateSpecializationType( + TLB, TL, QualType(), nullptr, false); } template QualType TreeTransform::TransformDependentTemplateSpecializationType( TypeLocBuilder &TLB, DependentTemplateSpecializationTypeLoc TL, - CXXScopeSpec &SS) { + QualType ObjectType, NamedDecl *UnqualLookup, bool AllowInjectedClassName) { const DependentTemplateSpecializationType *T = TL.getTypePtr(); - TemplateArgumentListInfo NewTemplateArgs; - NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); - NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + NestedNameSpecifierLoc QualifierLoc = TL.getQualifierLoc(); + if (QualifierLoc) { + QualifierLoc = getDerived().TransformNestedNameSpecifierLoc( + QualifierLoc, ObjectType, UnqualLookup); + if (!QualifierLoc) + return QualType(); + // These only apply to the leftmost prefix. + ObjectType = QualType(); + UnqualLookup = nullptr; + } + CXXScopeSpec SS; + SS.Adopt(QualifierLoc); + TemplateArgumentListInfo NewTemplateArgs(TL.getLAngleLoc(), + TL.getRAngleLoc()); auto ArgsRange = llvm::make_range>({TL, 0}, {TL, TL.getNumArgs()}); @@ -7623,43 +7711,27 @@ QualType TreeTransform::TransformDependentTemplateSpecializationType( QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || SS.getScopeRep() != DTN.getQualifier() || - TemplateArgumentsChanged) { + TemplateArgumentsChanged || !ObjectType.isNull()) { TemplateName Name = getDerived().RebuildTemplateName( SS, TL.getTemplateKeywordLoc(), DTN.getName(), TL.getTemplateNameLoc(), - /*ObjectType=*/QualType(), /*FirstQualifierInScope=*/nullptr, - /*AllowInjectedClassName=*/false); + ObjectType, AllowInjectedClassName); if (Name.isNull()) return QualType(); Result = getDerived().RebuildDependentTemplateSpecializationType( - T->getKeyword(), SS.getScopeRep(), TL.getTemplateKeywordLoc(), Name, + T->getKeyword(), TL.getTemplateKeywordLoc(), Name, TL.getTemplateNameLoc(), NewTemplateArgs, /*AllowInjectedClassName=*/false); if (Result.isNull()) return QualType(); } - NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(SemaRef.Context); - if (const ElaboratedType *ElabT = dyn_cast(Result)) { - QualType NamedT = ElabT->getNamedType(); - - // Copy information relevant to the template specialization. - TemplateSpecializationTypeLoc NamedTL - = TLB.push(NamedT); - NamedTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); - NamedTL.setTemplateNameLoc(TL.getTemplateNameLoc()); - NamedTL.setLAngleLoc(TL.getLAngleLoc()); - NamedTL.setRAngleLoc(TL.getRAngleLoc()); - for (unsigned I = 0, E = NewTemplateArgs.size(); I != E; ++I) - NamedTL.setArgLocInfo(I, NewTemplateArgs[I].getLocInfo()); - - // Copy information relevant to the elaborated type. - ElaboratedTypeLoc NewTL = TLB.push(Result); - NewTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); - NewTL.setQualifierLoc(QualifierLoc); + QualifierLoc = SS.getWithLocInContext(SemaRef.Context); + if (isa(Result)) { + TLB.push(Result).set( + TL.getElaboratedKeywordLoc(), QualifierLoc, TL.getTemplateKeywordLoc(), + TL.getTemplateNameLoc(), NewTemplateArgs); } else { - assert(isa(Result)); - DependentTemplateSpecializationTypeLoc SpecTL - = TLB.push(Result); + auto SpecTL = TLB.push(Result); SpecTL.setElaboratedKeywordLoc(TL.getElaboratedKeywordLoc()); SpecTL.setQualifierLoc(QualifierLoc); SpecTL.setTemplateKeywordLoc(TL.getTemplateKeywordLoc()); diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index ce2edcc25a099..18f1a45c7bde7 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -7978,18 +7978,15 @@ ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) { return readExpr(); case TemplateArgument::Type: return readTypeSourceInfo(); - case TemplateArgument::Template: { - NestedNameSpecifierLoc QualifierLoc = - readNestedNameSpecifierLoc(); - SourceLocation TemplateNameLoc = readSourceLocation(); - return TemplateArgumentLocInfo(getASTContext(), QualifierLoc, - TemplateNameLoc, SourceLocation()); - } + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { + SourceLocation TemplateKWLoc = readSourceLocation(); NestedNameSpecifierLoc QualifierLoc = readNestedNameSpecifierLoc(); SourceLocation TemplateNameLoc = readSourceLocation(); - SourceLocation EllipsisLoc = readSourceLocation(); - return TemplateArgumentLocInfo(getASTContext(), QualifierLoc, + SourceLocation EllipsisLoc = Kind == TemplateArgument::TemplateExpansion + ? readSourceLocation() + : SourceLocation(); + return TemplateArgumentLocInfo(getASTContext(), TemplateKWLoc, QualifierLoc, TemplateNameLoc, EllipsisLoc); } case TemplateArgument::Null: @@ -10113,41 +10110,37 @@ ASTRecordReader::readNestedNameSpecifierLoc() { for (unsigned I = 0; I != N; ++I) { auto Kind = readNestedNameSpecifierKind(); switch (Kind) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = readIdentifier(); - SourceRange Range = readSourceRange(); - Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); - break; - } - - case NestedNameSpecifier::Namespace: { + case NestedNameSpecifier::Kind::Namespace: { auto *NS = readDeclAs(); SourceRange Range = readSourceRange(); Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); break; } - case NestedNameSpecifier::TypeSpec: { + case NestedNameSpecifier::Kind::Type: { TypeSourceInfo *T = readTypeSourceInfo(); if (!T) return NestedNameSpecifierLoc(); SourceLocation ColonColonLoc = readSourceLocation(); - Builder.Extend(Context, T->getTypeLoc(), ColonColonLoc); + Builder.Make(Context, T->getTypeLoc(), ColonColonLoc); break; } - case NestedNameSpecifier::Global: { + case NestedNameSpecifier::Kind::Global: { SourceLocation ColonColonLoc = readSourceLocation(); Builder.MakeGlobal(Context, ColonColonLoc); break; } - case NestedNameSpecifier::Super: { + case NestedNameSpecifier::Kind::MicrosoftSuper: { CXXRecordDecl *RD = readDeclAs(); SourceRange Range = readSourceRange(); - Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd()); + Builder.MakeMicrosoftSuper(Context, RD, Range.getBegin(), Range.getEnd()); break; } + + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 462e38c5c77f1..0b63c2e0c2a77 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7075,49 +7075,50 @@ void ASTRecordWriter::AddQualifierInfo(const QualifierInfo &Info) { AddTemplateParameterList(Info.TemplParamLists[i]); } -void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { +void ASTRecordWriter::AddNestedNameSpecifierLoc( + NestedNameSpecifierLoc QualifierLoc) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. SmallVector NestedNames; // Push each of the nested-name-specifiers's onto a stack for // serialization in reverse order. - while (NNS) { - NestedNames.push_back(NNS); - NNS = NNS.getPrefix(); + while (QualifierLoc) { + NestedNames.push_back(QualifierLoc); + QualifierLoc = QualifierLoc.getAsNamespaceAndPrefix().Prefix; } Record->push_back(NestedNames.size()); while(!NestedNames.empty()) { - NNS = NestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind Kind - = NNS.getNestedNameSpecifier()->getKind(); - Record->push_back(Kind); + QualifierLoc = NestedNames.pop_back_val(); + NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier(); + NestedNameSpecifier::Kind Kind = Qualifier.getKind(); + Record->push_back(llvm::to_underlying(Kind)); switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierRef(NNS.getNestedNameSpecifier()->getAsIdentifier()); - AddSourceRange(NNS.getLocalSourceRange()); + case NestedNameSpecifier::Kind::Namespace: + AddDeclRef(Qualifier.getAsNamespaceAndPrefix().Namespace); + AddSourceRange(QualifierLoc.getLocalSourceRange()); break; - case NestedNameSpecifier::Namespace: - AddDeclRef(NNS.getNestedNameSpecifier()->getAsNamespace()); - AddSourceRange(NNS.getLocalSourceRange()); + case NestedNameSpecifier::Kind::Type: { + TypeLoc TL = QualifierLoc.castAsTypeLoc(); + AddTypeRef(TL.getType()); + AddTypeLoc(TL); + AddSourceLocation(QualifierLoc.getLocalSourceRange().getEnd()); break; + } - case NestedNameSpecifier::TypeSpec: - AddTypeRef(NNS.getTypeLoc().getType()); - AddTypeLoc(NNS.getTypeLoc()); - AddSourceLocation(NNS.getLocalSourceRange().getEnd()); + case NestedNameSpecifier::Kind::Global: + AddSourceLocation(QualifierLoc.getLocalSourceRange().getEnd()); break; - case NestedNameSpecifier::Global: - AddSourceLocation(NNS.getLocalSourceRange().getEnd()); + case NestedNameSpecifier::Kind::MicrosoftSuper: + AddDeclRef(Qualifier.getAsMicrosoftSuper()); + AddSourceRange(QualifierLoc.getLocalSourceRange()); break; - case NestedNameSpecifier::Super: - AddDeclRef(NNS.getNestedNameSpecifier()->getAsRecordDecl()); - AddSourceRange(NNS.getLocalSourceRange()); - break; + case NestedNameSpecifier::Kind::Null: + llvm_unreachable("unexpected null nested name specifier"); } } } diff --git a/clang/lib/Tooling/Refactoring/Lookup.cpp b/clang/lib/Tooling/Refactoring/Lookup.cpp index 8372371aff368..dedde860516ab 100644 --- a/clang/lib/Tooling/Refactoring/Lookup.cpp +++ b/clang/lib/Tooling/Refactoring/Lookup.cpp @@ -108,16 +108,6 @@ static StringRef getBestNamespaceSubstr(const DeclContext *DeclA, } } -/// Check if the name specifier begins with a written "::". -static bool isFullyQualified(const NestedNameSpecifier *NNS) { - while (NNS) { - if (NNS->getKind() == NestedNameSpecifier::Global) - return true; - NNS = NNS->getPrefix(); - } - return false; -} - // Adds more scope specifier to the spelled name until the spelling is not // ambiguous. A spelling is ambiguous if the resolution of the symbol is // ambiguous. For example, if QName is "::y::bar", the spelling is "y::bar", and @@ -182,7 +172,7 @@ static std::string disambiguateSpellingInScope(StringRef Spelling, return Disambiguated; } -std::string tooling::replaceNestedName(const NestedNameSpecifier *Use, +std::string tooling::replaceNestedName(NestedNameSpecifier Use, SourceLocation UseLoc, const DeclContext *UseContext, const NamedDecl *FromDecl, diff --git a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp index 7d153ec958bef..d9444110d421c 100644 --- a/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp +++ b/clang/lib/Tooling/Refactoring/Rename/USRLocFinder.cpp @@ -107,45 +107,83 @@ class USRLocFindingASTVisitor }; SourceLocation StartLocationForType(TypeLoc TL) { + if (auto QTL = TL.getAs()) + TL = QTL.getUnqualifiedLoc(); + // For elaborated types (e.g. `struct a::A`) we want the portion after the - // `struct` but including the namespace qualifier, `a::`. - if (auto ElaboratedTypeLoc = TL.getAs()) { - NestedNameSpecifierLoc NestedNameSpecifier = - ElaboratedTypeLoc.getQualifierLoc(); - if (NestedNameSpecifier.getNestedNameSpecifier()) - return NestedNameSpecifier.getBeginLoc(); - TL = TL.getNextTypeLoc(); + // `struct`, including the namespace qualifier, `a::`. + switch (TL.getTypeLocClass()) { + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + case TypeLoc::Enum: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getNameLoc(); + } + case TypeLoc::Typedef: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getNameLoc(); + } + case TypeLoc::UnresolvedUsing: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getNameLoc(); + } + case TypeLoc::Using: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getNameLoc(); + } + case TypeLoc::TemplateSpecialization: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getTemplateNameLoc(); + } + case TypeLoc::DeducedTemplateSpecialization: { + auto DTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = DTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return DTL.getTemplateNameLoc(); + } + case TypeLoc::DependentName: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getNameLoc(); + } + case TypeLoc::DependentTemplateSpecialization: { + auto TTL = TL.castAs(); + if (NestedNameSpecifierLoc QualifierLoc = TTL.getQualifierLoc()) + return QualifierLoc.getBeginLoc(); + return TTL.getTemplateNameLoc(); + } + default: + llvm_unreachable("unhandled TypeLoc class"); } - return TL.getBeginLoc(); } SourceLocation EndLocationForType(TypeLoc TL) { - // Dig past any namespace or keyword qualifications. - while (TL.getTypeLocClass() == TypeLoc::Elaborated || - TL.getTypeLocClass() == TypeLoc::Qualified) - TL = TL.getNextTypeLoc(); + if (auto QTL = TL.getAs()) + TL = QTL.getUnqualifiedLoc(); // The location for template specializations (e.g. Foo) includes the // templated types in its location range. We want to restrict this to just // before the `<` character. - if (TL.getTypeLocClass() == TypeLoc::TemplateSpecialization) { - return TL.castAs() - .getLAngleLoc() - .getLocWithOffset(-1); - } + if (auto TTL = TL.getAs()) + return TTL.getLAngleLoc().getLocWithOffset(-1); return TL.getEndLoc(); } -NestedNameSpecifier *GetNestedNameForType(TypeLoc TL) { - // Dig past any keyword qualifications. - while (TL.getTypeLocClass() == TypeLoc::Qualified) - TL = TL.getNextTypeLoc(); - - // For elaborated types (e.g. `struct a::A`) we want the portion after the - // `struct` but including the namespace qualifier, `a::`. - if (auto ElaboratedTypeLoc = TL.getAs()) - return ElaboratedTypeLoc.getQualifierLoc().getNestedNameSpecifier(); - return nullptr; +NestedNameSpecifier GetNestedNameForType(TypeLoc TL) { + if (auto QTL = TL.getAs()) + TL = QTL.getUnqualifiedLoc(); + return TL.getPrefix().getNestedNameSpecifier(); } // Find all locations identified by the given USRs for rename. @@ -168,14 +206,14 @@ class RenameLocFinder : public RecursiveASTVisitor { const NamedDecl *FromDecl; // The declaration in which the nested name is contained (can be nullptr). const Decl *Context; - // The nested name being replaced (can be nullptr). - const NestedNameSpecifier *Specifier; + // The nested name being replaced. + NestedNameSpecifier Specifier; // Determine whether the prefix qualifiers of the NewName should be ignored. // Normally, we set it to true for the symbol declaration and definition to // avoid adding prefix qualifiers. // For example, if it is true and NewName is "a::b::foo", then the symbol // occurrence which the RenameInfo points to will be renamed to "foo". - bool IgnorePrefixQualifers; + bool IgnorePrefixQualifiers; }; bool VisitNamedDecl(const NamedDecl *Decl) { @@ -350,18 +388,18 @@ class RenameLocFinder : public RecursiveASTVisitor { } bool VisitNestedNameSpecifierLocations(NestedNameSpecifierLoc NestedLoc) { - if (!NestedLoc.getNestedNameSpecifier()->getAsType()) + TypeLoc TL = NestedLoc.getAsTypeLoc(); + if (!TL) return true; - if (const auto *TargetDecl = - getSupportedDeclFromTypeLoc(NestedLoc.getTypeLoc())) { + if (const auto *TargetDecl = getSupportedDeclFromTypeLoc(TL)) { if (isInUSRSet(TargetDecl)) { RenameInfo Info = {NestedLoc.getBeginLoc(), - EndLocationForType(NestedLoc.getTypeLoc()), + EndLocationForType(TL), TargetDecl, getClosestAncestorDecl(NestedLoc), - NestedLoc.getNestedNameSpecifier()->getPrefix(), - /*IgnorePrefixQualifers=*/false}; + /*Specifier=*/std::nullopt, + /*IgnorePrefixQualifiers=*/false}; RenameInfos.push_back(Info); } } diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index 2e43714b16c1c..546161cee33f4 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -918,97 +918,91 @@ class BuildTreeVisitor : public RecursiveASTVisitor { return true; } - // FIXME: Fix `NestedNameSpecifierLoc::getLocalSourceRange` for the - // `DependentTemplateSpecializationType` case. - /// Given a nested-name-specifier return the range for the last name - /// specifier. - /// - /// e.g. `std::T::template X::` => `template X::` - SourceRange getLocalSourceRange(const NestedNameSpecifierLoc &NNSLoc) { - auto SR = NNSLoc.getLocalSourceRange(); - - // The method `NestedNameSpecifierLoc::getLocalSourceRange` *should* - // return the desired `SourceRange`, but there is a corner case. For a - // `DependentTemplateSpecializationType` this method returns its - // qualifiers as well, in other words in the example above this method - // returns `T::template X::` instead of only `template X::` - if (auto TL = NNSLoc.getTypeLoc()) { - if (auto DependentTL = - TL.getAs()) { - // The 'template' keyword is always present in dependent template - // specializations. Except in the case of incorrect code - // TODO: Treat the case of incorrect code. - SR.setBegin(DependentTL.getTemplateKeywordLoc()); - } - } - - return SR; - } - - syntax::NodeKind getNameSpecifierKind(const NestedNameSpecifier &NNS) { - switch (NNS.getKind()) { - case NestedNameSpecifier::Global: - return syntax::NodeKind::GlobalNameSpecifier; - case NestedNameSpecifier::Namespace: - case NestedNameSpecifier::Identifier: - return syntax::NodeKind::IdentifierNameSpecifier; - case NestedNameSpecifier::TypeSpec: { - const auto *NNSType = NNS.getAsType(); - assert(NNSType); - if (isa(NNSType)) - return syntax::NodeKind::DecltypeNameSpecifier; - if (isa( - NNSType)) - return syntax::NodeKind::SimpleTemplateNameSpecifier; - return syntax::NodeKind::IdentifierNameSpecifier; - } - default: - // FIXME: Support Microsoft's __super - llvm::report_fatal_error("We don't yet support the __super specifier", - true); - } + syntax::NameSpecifier *buildIdentifier(SourceRange SR, + bool DropBack = false) { + auto NameSpecifierTokens = Builder.getRange(SR).drop_back(DropBack); + assert(NameSpecifierTokens.size() == 1); + Builder.markChildToken(NameSpecifierTokens.begin(), + syntax::NodeRole::Unknown); + auto *NS = new (allocator()) syntax::IdentifierNameSpecifier; + Builder.foldNode(NameSpecifierTokens, NS, nullptr); + return NS; + } + + syntax::NameSpecifier *buildSimpleTemplateName(SourceRange SR) { + auto NameSpecifierTokens = Builder.getRange(SR); + // TODO: Build `SimpleTemplateNameSpecifier` children and implement + // accessors to them. + // Be aware, we cannot do that simply by calling `TraverseTypeLoc`, + // some `TypeLoc`s have inside them the previous name specifier and + // we want to treat them independently. + auto *NS = new (allocator()) syntax::SimpleTemplateNameSpecifier; + Builder.foldNode(NameSpecifierTokens, NS, nullptr); + return NS; } syntax::NameSpecifier * buildNameSpecifier(const NestedNameSpecifierLoc &NNSLoc) { assert(NNSLoc.hasQualifier()); - auto NameSpecifierTokens = - Builder.getRange(getLocalSourceRange(NNSLoc)).drop_back(); - switch (getNameSpecifierKind(*NNSLoc.getNestedNameSpecifier())) { - case syntax::NodeKind::GlobalNameSpecifier: + switch (NNSLoc.getNestedNameSpecifier().getKind()) { + case NestedNameSpecifier::Kind::Global: return new (allocator()) syntax::GlobalNameSpecifier; - case syntax::NodeKind::IdentifierNameSpecifier: { - assert(NameSpecifierTokens.size() == 1); - Builder.markChildToken(NameSpecifierTokens.begin(), - syntax::NodeRole::Unknown); - auto *NS = new (allocator()) syntax::IdentifierNameSpecifier; - Builder.foldNode(NameSpecifierTokens, NS, nullptr); - return NS; - } - case syntax::NodeKind::SimpleTemplateNameSpecifier: { - // TODO: Build `SimpleTemplateNameSpecifier` children and implement - // accessors to them. - // Be aware, we cannot do that simply by calling `TraverseTypeLoc`, - // some `TypeLoc`s have inside them the previous name specifier and - // we want to treat them independently. - auto *NS = new (allocator()) syntax::SimpleTemplateNameSpecifier; - Builder.foldNode(NameSpecifierTokens, NS, nullptr); - return NS; - } - case syntax::NodeKind::DecltypeNameSpecifier: { - const auto TL = NNSLoc.getTypeLoc().castAs(); - if (!RecursiveASTVisitor::TraverseDecltypeTypeLoc(TL)) - return nullptr; - auto *NS = new (allocator()) syntax::DecltypeNameSpecifier; - // TODO: Implement accessor to `DecltypeNameSpecifier` inner - // `DecltypeTypeLoc`. - // For that add mapping from `TypeLoc` to `syntax::Node*` then: - // Builder.markChild(TypeLoc, syntax::NodeRole); - Builder.foldNode(NameSpecifierTokens, NS, nullptr); - return NS; + + case NestedNameSpecifier::Kind::Namespace: + return buildIdentifier(NNSLoc.getLocalSourceRange(), /*DropBack=*/true); + + case NestedNameSpecifier::Kind::Type: { + TypeLoc TL = NNSLoc.castAsTypeLoc(); + switch (TL.getTypeLocClass()) { + case TypeLoc::Record: + case TypeLoc::InjectedClassName: + case TypeLoc::Enum: + return buildIdentifier(TL.castAs().getNameLoc()); + case TypeLoc::Typedef: + return buildIdentifier(TL.castAs().getNameLoc()); + case TypeLoc::UnresolvedUsing: + return buildIdentifier( + TL.castAs().getNameLoc()); + case TypeLoc::Using: + return buildIdentifier(TL.castAs().getNameLoc()); + case TypeLoc::DependentName: + return buildIdentifier(TL.castAs().getNameLoc()); + case TypeLoc::TemplateSpecialization: { + auto TST = TL.castAs(); + SourceLocation BeginLoc = TST.getTemplateKeywordLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = TST.getTemplateNameLoc(); + return buildSimpleTemplateName({BeginLoc, TST.getEndLoc()}); + } + case TypeLoc::DependentTemplateSpecialization: { + auto DT = TL.castAs(); + SourceLocation BeginLoc = DT.getTemplateKeywordLoc(); + if (BeginLoc.isInvalid()) + BeginLoc = DT.getTemplateNameLoc(); + return buildSimpleTemplateName({BeginLoc, DT.getEndLoc()}); + } + case TypeLoc::Decltype: { + const auto DTL = TL.castAs(); + if (!RecursiveASTVisitor::TraverseDecltypeTypeLoc( + DTL, /*TraverseQualifier=*/true)) + return nullptr; + auto *NS = new (allocator()) syntax::DecltypeNameSpecifier; + // TODO: Implement accessor to `DecltypeNameSpecifier` inner + // `DecltypeTypeLoc`. + // For that add mapping from `TypeLoc` to `syntax::Node*` then: + // Builder.markChild(TypeLoc, syntax::NodeRole); + Builder.foldNode(Builder.getRange(DTL.getLocalSourceRange()), NS, + nullptr); + return NS; + } + default: + return buildIdentifier(TL.getLocalSourceRange()); + } } default: - llvm_unreachable("getChildKind() does not return this value"); + // FIXME: Support Microsoft's __super + llvm::report_fatal_error("We don't yet support the __super specifier", + true); } } @@ -1019,12 +1013,16 @@ class BuildTreeVisitor : public RecursiveASTVisitor { bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) { if (!QualifierLoc) return true; - for (auto It = QualifierLoc; It; It = It.getPrefix()) { + for (auto It = QualifierLoc; It; /**/) { auto *NS = buildNameSpecifier(It); if (!NS) return false; Builder.markChild(NS, syntax::NodeRole::ListElement); Builder.markChildToken(It.getEndLoc(), syntax::NodeRole::ListDelimiter); + if (TypeLoc TL = It.getAsTypeLoc()) + It = TL.getPrefix(); + else + It = It.getAsNamespaceAndPrefix().Prefix; } Builder.foldNode(Builder.getRange(QualifierLoc.getSourceRange()), new (allocator()) syntax::NestedNameSpecifier, diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index d4f0794a8e0af..239c9c536f243 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1420,79 +1420,25 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { llvm_unreachable("Invalid DeclarationName::Kind!"); } -bool CursorVisitor::VisitNestedNameSpecifier(NestedNameSpecifier *NNS, - SourceRange Range) { - // FIXME: This whole routine is a hack to work around the lack of proper - // source information in nested-name-specifiers (PR5791). Since we do have - // a beginning source location, we can visit the first component of the - // nested-name-specifier, if it's a single-token component. - if (!NNS) - return false; - - // Get the first component in the nested-name-specifier. - while (NestedNameSpecifier *Prefix = NNS->getPrefix()) - NNS = Prefix; - - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - return Visit( - MakeCursorNamespaceRef(NNS->getAsNamespace(), Range.getBegin(), TU)); - - case NestedNameSpecifier::TypeSpec: { - // If the type has a form where we know that the beginning of the source - // range matches up with a reference cursor. Visit the appropriate reference - // cursor. - const Type *T = NNS->getAsType(); - if (const TypedefType *Typedef = dyn_cast(T)) - return Visit(MakeCursorTypeRef(Typedef->getDecl(), Range.getBegin(), TU)); - if (const TagType *Tag = dyn_cast(T)) - return Visit(MakeCursorTypeRef(Tag->getDecl(), Range.getBegin(), TU)); - if (const TemplateSpecializationType *TST = - dyn_cast(T)) - return VisitTemplateName(TST->getTemplateName(), Range.getBegin()); - break; - } - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Super: - break; - } - - return false; -} - bool CursorVisitor::VisitNestedNameSpecifierLoc( NestedNameSpecifierLoc Qualifier) { - SmallVector Qualifiers; - for (; Qualifier; Qualifier = Qualifier.getPrefix()) - Qualifiers.push_back(Qualifier); - - while (!Qualifiers.empty()) { - NestedNameSpecifierLoc Q = Qualifiers.pop_back_val(); - NestedNameSpecifier *NNS = Q.getNestedNameSpecifier(); - switch (NNS->getKind()) { - case NestedNameSpecifier::Namespace: - if (Visit(MakeCursorNamespaceRef(NNS->getAsNamespace(), - Q.getLocalBeginLoc(), TU))) - return true; - - break; - - case NestedNameSpecifier::TypeSpec: - if (Visit(Q.getTypeLoc())) - return true; - - break; - - case NestedNameSpecifier::Global: - case NestedNameSpecifier::Identifier: - case NestedNameSpecifier::Super: - break; - } + NestedNameSpecifier NNS = Qualifier.getNestedNameSpecifier(); + switch (NNS.getKind()) { + case NestedNameSpecifier::Kind::Namespace: { + auto [Namespace, Prefix] = Qualifier.castAsNamespaceAndPrefix(); + if (VisitNestedNameSpecifierLoc(Prefix)) + return true; + return Visit( + MakeCursorNamespaceRef(Namespace, Qualifier.getLocalBeginLoc(), TU)); } - - return false; + case NestedNameSpecifier::Kind::Type: + return Visit(Qualifier.castAsTypeLoc()); + case NestedNameSpecifier::Kind::Null: + case NestedNameSpecifier::Kind::Global: + case NestedNameSpecifier::Kind::MicrosoftSuper: + return false; + } + llvm_unreachable("unexpected nested name specifier kind"); } bool CursorVisitor::VisitTemplateParameters( @@ -1515,16 +1461,23 @@ bool CursorVisitor::VisitTemplateParameters( return false; } -bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { +bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation NameLoc, + NestedNameSpecifierLoc NNS) { switch (Name.getKind()) { + case TemplateName::QualifiedTemplate: { + const QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName(); + assert(QTN->getQualifier() == NNS.getNestedNameSpecifier()); + if (VisitNestedNameSpecifierLoc(NNS)) + return true; + return VisitTemplateName(QTN->getUnderlyingTemplate(), NameLoc, /*NNS=*/{}); + } case TemplateName::Template: case TemplateName::UsingTemplate: - case TemplateName::QualifiedTemplate: // FIXME: Visit nested-name-specifier. - return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), Loc, TU)); + return Visit(MakeCursorTemplateRef(Name.getAsTemplateDecl(), NameLoc, TU)); case TemplateName::OverloadedTemplate: // Visit the overloaded template set. - if (Visit(MakeCursorOverloadedDeclRef(Name, Loc, TU))) + if (Visit(MakeCursorOverloadedDeclRef(Name, NameLoc, TU))) return true; return false; @@ -1533,17 +1486,19 @@ bool CursorVisitor::VisitTemplateName(TemplateName Name, SourceLocation Loc) { // FIXME: Visit DeclarationName? return false; - case TemplateName::DependentTemplate: - // FIXME: Visit nested-name-specifier. - return false; + case TemplateName::DependentTemplate: { + assert(Name.getAsDependentTemplateName()->getQualifier() == + NNS.getNestedNameSpecifier()); + return VisitNestedNameSpecifierLoc(NNS); + } case TemplateName::SubstTemplateTemplateParm: return Visit(MakeCursorTemplateRef( - Name.getAsSubstTemplateTemplateParm()->getParameter(), Loc, TU)); + Name.getAsSubstTemplateTemplateParm()->getParameter(), NameLoc, TU)); case TemplateName::SubstTemplateTemplateParmPack: return Visit(MakeCursorTemplateRef( - Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), Loc, + Name.getAsSubstTemplateTemplateParmPack()->getParameterPack(), NameLoc, TU)); case TemplateName::DeducedTemplate: @@ -1587,11 +1542,9 @@ bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (VisitNestedNameSpecifierLoc(TAL.getTemplateQualifierLoc())) - return true; - return VisitTemplateName(TAL.getArgument().getAsTemplateOrTemplatePattern(), - TAL.getTemplateNameLoc()); + TAL.getTemplateNameLoc(), + TAL.getTemplateQualifierLoc()); } llvm_unreachable("Invalid TemplateArgument::Kind!"); @@ -1669,7 +1622,10 @@ bool CursorVisitor::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { } bool CursorVisitor::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - return Visit(MakeCursorTypeRef(TL.getTypedefNameDecl(), TL.getNameLoc(), TU)); + if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) + return true; + + return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } bool CursorVisitor::VisitPredefinedSugarTypeLoc(PredefinedSugarTypeLoc TL) { @@ -1880,8 +1836,7 @@ bool CursorVisitor::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { bool CursorVisitor::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { - // Visit the nested-name-specifier, if there is one. - if (TL.getQualifierLoc() && VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) + if (VisitNestedNameSpecifierLoc(TL.getQualifierLoc())) return true; // Visit the template arguments. @@ -2067,7 +2022,7 @@ class NestedNameSpecifierLocVisit : public VisitorJob { public: NestedNameSpecifierLocVisit(NestedNameSpecifierLoc Qualifier, CXCursor parent) : VisitorJob(parent, VisitorJob::NestedNameSpecifierLocVisitKind, - Qualifier.getNestedNameSpecifier(), + Qualifier.getNestedNameSpecifier().getAsVoidPointer(), Qualifier.getOpaqueData()) {} static bool classof(const VisitorJob *VJ) { @@ -2076,8 +2031,7 @@ class NestedNameSpecifierLocVisit : public VisitorJob { NestedNameSpecifierLoc get() const { return NestedNameSpecifierLoc( - const_cast( - static_cast(data[0])), + NestedNameSpecifier::getFromVoidPointer(data[0]), const_cast(data[1])); } }; diff --git a/clang/tools/libclang/CursorVisitor.h b/clang/tools/libclang/CursorVisitor.h index 949b73908c315..d5ab699756988 100644 --- a/clang/tools/libclang/CursorVisitor.h +++ b/clang/tools/libclang/CursorVisitor.h @@ -255,12 +255,12 @@ class CursorVisitor : public DeclVisitor, // Name visitor bool VisitDeclarationNameInfo(DeclarationNameInfo Name); - bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range); bool VisitNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); // Template visitors bool VisitTemplateParameters(const TemplateParameterList *Params); - bool VisitTemplateName(TemplateName Name, SourceLocation Loc); + bool VisitTemplateName(TemplateName Name, SourceLocation NameLoc, + NestedNameSpecifierLoc NNS); bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); // Type visitors diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 4fd7dcdad2d7e..d58bc00c995e0 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5765,38 +5765,33 @@ TEST(NNS, DescendantsOfNestedNameSpecifiers) { "namespace a { struct A { struct B { struct C {}; }; }; };" "void f() { a::A::B::C c; }"; EXPECT_TRUE(matches( - Fragment, - nestedNameSpecifier(specifiesType(asString("struct a::A::B")), - hasDescendant(nestedNameSpecifier( - specifiesNamespace(hasName("a"))))))); + Fragment, nestedNameSpecifier(specifiesType(asString("a::A::B")), + hasDescendant(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); EXPECT_TRUE(notMatches( - Fragment, - nestedNameSpecifier(specifiesType(asString("struct a::A::B")), - has(nestedNameSpecifier( - specifiesNamespace(hasName("a"))))))); + Fragment, nestedNameSpecifier(specifiesType(asString("a::A::B")), + has(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); EXPECT_TRUE(matches( - Fragment, - nestedNameSpecifier(specifiesType(asString("struct a::A")), - has(nestedNameSpecifier( - specifiesNamespace(hasName("a"))))))); + Fragment, nestedNameSpecifier(specifiesType(asString("a::A")), + has(nestedNameSpecifier( + specifiesNamespace(hasName("a"))))))); // Not really useful because a NestedNameSpecifier can af at most one child, // but to complete the interface. EXPECT_TRUE(matchAndVerifyResultTrue( - Fragment, - nestedNameSpecifier(specifiesType(asString("struct a::A::B")), - forEach(nestedNameSpecifier().bind("x"))), - std::make_unique>("x", 1))); + Fragment, + nestedNameSpecifier(specifiesType(asString("a::A::B")), + forEach(nestedNameSpecifier().bind("x"))), + std::make_unique>("x", 1))); } TEST(NNS, NestedNameSpecifiersAsDescendants) { StringRef Fragment = "namespace a { struct A { struct B { struct C {}; }; }; };" "void f() { a::A::B::C c; }"; - EXPECT_TRUE(matches( - Fragment, - decl(hasDescendant(nestedNameSpecifier(specifiesType( - asString("struct a::A"))))))); + EXPECT_TRUE(matches(Fragment, decl(hasDescendant(nestedNameSpecifier( + specifiesType(asString("a::A"))))))); EXPECT_TRUE(matchAndVerifyResultTrue( Fragment, functionDecl(hasName("f"), @@ -5809,37 +5804,34 @@ TEST(NNSLoc, DescendantsOfNestedNameSpecifierLocs) { StringRef Fragment = "namespace a { struct A { struct B { struct C {}; }; }; };" "void f() { a::A::B::C c; }"; - EXPECT_TRUE(matches( - Fragment, - nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), - hasDescendant(loc(nestedNameSpecifier( - specifiesNamespace(hasName("a")))))))); + EXPECT_TRUE(matches(Fragment, nestedNameSpecifierLoc( + loc(specifiesType(asString("a::A::B"))), + hasDescendant(loc(nestedNameSpecifier( + specifiesNamespace(hasName("a")))))))); EXPECT_TRUE(notMatches( - Fragment, - nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), - has(loc(nestedNameSpecifier( - specifiesNamespace(hasName("a")))))))); + Fragment, + nestedNameSpecifierLoc( + loc(specifiesType(asString("a::A::B"))), + has(loc(nestedNameSpecifier(specifiesNamespace(hasName("a")))))))); EXPECT_TRUE(matches( - Fragment, - nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A"))), - has(loc(nestedNameSpecifier( - specifiesNamespace(hasName("a")))))))); + Fragment, + nestedNameSpecifierLoc( + loc(specifiesType(asString("a::A"))), + has(loc(nestedNameSpecifier(specifiesNamespace(hasName("a")))))))); EXPECT_TRUE(matchAndVerifyResultTrue( - Fragment, - nestedNameSpecifierLoc(loc(specifiesType(asString("struct a::A::B"))), - forEach(nestedNameSpecifierLoc().bind("x"))), - std::make_unique>("x", 1))); + Fragment, + nestedNameSpecifierLoc(loc(specifiesType(asString("a::A::B"))), + forEach(nestedNameSpecifierLoc().bind("x"))), + std::make_unique>("x", 1))); } TEST(NNSLoc, NestedNameSpecifierLocsAsDescendants) { StringRef Fragment = "namespace a { struct A { struct B { struct C {}; }; }; };" "void f() { a::A::B::C c; }"; - EXPECT_TRUE(matches( - Fragment, - decl(hasDescendant(loc(nestedNameSpecifier(specifiesType( - asString("struct a::A")))))))); + EXPECT_TRUE(matches(Fragment, decl(hasDescendant(loc(nestedNameSpecifier( + specifiesType(asString("a::A")))))))); EXPECT_TRUE(matchAndVerifyResultTrue( Fragment, functionDecl(hasName("f"), diff --git a/clang/unittests/Sema/HeuristicResolverTest.cpp b/clang/unittests/Sema/HeuristicResolverTest.cpp index 817654af10918..7df25e01e66d4 100644 --- a/clang/unittests/Sema/HeuristicResolverTest.cpp +++ b/clang/unittests/Sema/HeuristicResolverTest.cpp @@ -648,15 +648,16 @@ TEST(HeuristicResolver, NestedNameSpecifier) { // expected by expectResolution() (returning a vector of decls). ResolveFnT ResolveFn = [](const HeuristicResolver *H, - const NestedNameSpecifier *NNS) -> std::vector { + NestedNameSpecifier NNS) -> std::vector { return {H->resolveNestedNameSpecifierToType(NNS)->getAsCXXRecordDecl()}; }; - expectResolution(Code, ResolveFn, - nestedNameSpecifier(hasPrefix(specifiesType(hasDeclaration( - classTemplateDecl(hasName("A")))))) - .bind("input"), - classTemplateDecl(has(cxxRecordDecl( - has(cxxRecordDecl(hasName("B")).bind("output")))))); + expectResolution( + Code, ResolveFn, + nestedNameSpecifier(hasPrefix(specifiesType( + hasDeclaration(classTemplateDecl(hasName("A")))))) + .bind("input"), + classTemplateDecl( + has(cxxRecordDecl(has(cxxRecordDecl(hasName("B")).bind("output")))))); } TEST(HeuristicResolver, TemplateSpecializationType) { diff --git a/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp b/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp index 64bad8a134111..4181cd2881054 100644 --- a/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp +++ b/clang/unittests/Tooling/RecursiveASTVisitorTests/NestedNameSpecifiers.cpp @@ -22,13 +22,16 @@ class NestedNameSpecifiersVisitor : public ExpectedLocationVisitor { return true; } - bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) override { - if (!NNS) - return true; - if (const auto *ND = dyn_cast_if_present( - NNS.getNestedNameSpecifier()->getAsNamespace())) - Match(ND->getName(), NNS.getLocalBeginLoc()); - return ExpectedLocationVisitor::TraverseNestedNameSpecifierLoc(NNS); + bool + TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc QualifierLoc) override { + NestedNameSpecifier Qualifier = QualifierLoc.getNestedNameSpecifier(); + if (Qualifier.getKind() == NestedNameSpecifier::Kind::Namespace) { + if (const auto *ND = dyn_cast( + Qualifier.getAsNamespaceAndPrefix().Namespace)) + Match(ND->getName(), QualifierLoc.getLocalBeginLoc()); + } + return ExpectedLocationVisitor::TraverseNestedNameSpecifierLoc( + QualifierLoc); } }; diff --git a/clang/unittests/Tooling/RefactoringTest.cpp b/clang/unittests/Tooling/RefactoringTest.cpp index 35d114343b517..250a2630c00cf 100644 --- a/clang/unittests/Tooling/RefactoringTest.cpp +++ b/clang/unittests/Tooling/RefactoringTest.cpp @@ -747,9 +747,12 @@ TEST(Replacement, TemplatedFunctionCall) { class NestedNameSpecifierAVisitor : public TestVisitor { public: bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSLoc) override { - if (NNSLoc.getNestedNameSpecifier()) { - if (const auto *NS = dyn_cast_if_present( - NNSLoc.getNestedNameSpecifier()->getAsNamespace())) { + if (NestedNameSpecifier NNS = NNSLoc.getNestedNameSpecifier(); + NNS.getKind() == NestedNameSpecifier::Kind::Namespace) { + if (const auto *NS = + dyn_cast(NNSLoc.getNestedNameSpecifier() + .getAsNamespaceAndPrefix() + .Namespace)) { if (NS->getName() == "a") { Replace = Replacement(*SM, &NNSLoc, "", Context->getLangOpts()); }