diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-02-24 17:54:50 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-02-24 17:54:50 +0000 |
commit | c34348a7ef1a6b3f92a644a227953800cd1f9947 (patch) | |
tree | 5c41fb25b5d08155409083ea9d8987f68513470c | |
parent | 5fa05cb906e9ddd34ef2ae2a872014aeaf4bc04d (diff) |
Retain complete source-location information for C++
nested-name-specifiers throughout the parser, and provide a new class
(NestedNameSpecifierLoc) that contains a nested-name-specifier along
with its type-source information.
Right now, this information is completely useless, because we don't
actually store the source-location information anywhere in the
AST. Call this Step 1/N.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126391 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/NestedNameSpecifier.h | 70 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 57 | ||||
-rw-r--r-- | include/clang/Sema/ParsedTemplate.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 24 | ||||
-rw-r--r-- | lib/AST/NestedNameSpecifier.cpp | 92 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 5 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 189 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 35 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 24 |
17 files changed, 503 insertions, 43 deletions
diff --git a/include/clang/AST/NestedNameSpecifier.h b/include/clang/AST/NestedNameSpecifier.h index 88ae02c1d0..6d1798c168 100644 --- a/include/clang/AST/NestedNameSpecifier.h +++ b/include/clang/AST/NestedNameSpecifier.h @@ -203,6 +203,76 @@ public: void dump(const LangOptions &LO); }; +/// \brief A C++ nested-name-specifier augmented with source location +/// information. +class NestedNameSpecifierLoc { + NestedNameSpecifier *Qualifier; + void *Data; + + /// \brief Determines the data length for the last component in the + /// given nested-name-specifier. + static unsigned getLocalDataLength(NestedNameSpecifier *Qualifier); + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + static unsigned getDataLength(NestedNameSpecifier *Qualifier); + +public: + /// \brief Construct an empty nested-name-specifier. + NestedNameSpecifierLoc() : Qualifier(0), Data(0) { } + + /// \brief Construct a nested-name-specifier with source location information + /// from + NestedNameSpecifierLoc(NestedNameSpecifier *Qualifier, void *Data) + : Qualifier(Qualifier), Data(Data) { } + + /// \brief Evalutes true when this nested-name-specifier location is + /// non-empty. + operator bool() const { return Qualifier; } + + /// \brief Retrieve the nested-name-specifier to which this instance + /// refers. + NestedNameSpecifier *getNestedNameSpecifier() const { + return Qualifier; + } + + /// \brief Retrieve the opaque pointer that refers to source-location data. + void *getOpaqueData() const { return Data; } + + /// \brief 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<int>::, the returned source range would cover + /// from the initial '::' to the last '::'. + SourceRange getSourceRange(); + + /// \brief 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<int>::, the returned source range would cover + /// from "vector" to the last '::'. + SourceRange getLocalSourceRange(); + + /// \brief Return the prefix of this nested-name-specifier. + /// + /// For example, if this instance refers to a nested-name-specifier + /// \c ::std::vector<int>::, 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); + } + + /// \brief Determines the data length for the entire + /// nested-name-specifier. + unsigned getDataLength() const { return getDataLength(Qualifier); } +}; + /// Insertion operator for diagnostics. This allows sending NestedNameSpecifiers /// into a diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 49efdddb77..9386d35873 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -37,6 +37,7 @@ namespace clang { class NamespaceAliasDecl; class NamespaceDecl; class NestedNameSpecifier; + class NestedNameSpecifierLoc; class Preprocessor; class Declarator; struct TemplateIdAnnotation; @@ -55,10 +56,30 @@ namespace clang { class CXXScopeSpec { SourceRange Range; NestedNameSpecifier *ScopeRep; + + /// \brief 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. + char *Buffer; -public: - CXXScopeSpec() : Range(), ScopeRep() { } + /// \brief The size of the buffer used to store source-location information + /// for the nested-name-specifier. + unsigned BufferSize; + + /// \brief The capacity of the buffer used to store source-location + /// information for the nested-name-specifier. + unsigned BufferCapacity; +public: + CXXScopeSpec() : Range(), ScopeRep(), Buffer(0), BufferSize(0), + BufferCapacity(0) { } + CXXScopeSpec(const CXXScopeSpec &Other); + CXXScopeSpec &operator=(const CXXScopeSpec &Other); + ~CXXScopeSpec(); + const SourceRange &getRange() const { return Range; } void setRange(const SourceRange &R) { Range = R; } void setBeginLoc(SourceLocation Loc) { Range.setBegin(Loc); } @@ -129,13 +150,26 @@ public: /// nested-name-specifier '::'. void MakeGlobal(ASTContext &Context, SourceLocation ColonColonLoc); - /// \brief Adopt an existing nested-name-specifier and its source range - /// as our own. - void Adopt(NestedNameSpecifier *Qualifier, SourceRange R) { - ScopeRep = Qualifier; - Range = R; - } + /// \brief Make a new nested-name-specifier from incomplete source-location + /// information. + /// + /// 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, + SourceRange R); + + /// \brief Adopt an existing nested-name-specifier (with source-range + /// information). + void Adopt(NestedNameSpecifierLoc Other); + /// \brief 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); + /// No scope specifier. bool isEmpty() const { return !Range.isValid(); } /// A scope specifier is present, but may be valid or invalid. @@ -163,6 +197,13 @@ public: Range = SourceRange(); ScopeRep = 0; } + + /// \brief Retrieve the data associated with the source-location information. + char *location_data() const { return Buffer; } + + /// \brief Retrieve the size of the data associated with source-location + /// information. + unsigned location_size() const { return BufferSize; } }; /// DeclSpec - This class captures information about "declaration specifiers", diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h index 5aa6f47425..9e1a6165b1 100644 --- a/include/clang/Sema/ParsedTemplate.h +++ b/include/clang/Sema/ParsedTemplate.h @@ -177,6 +177,12 @@ namespace clang { = (TemplateIdAnnotation *)std::malloc(sizeof(TemplateIdAnnotation) + sizeof(ParsedTemplateArgument) * NumArgs); TemplateId->NumArgs = NumArgs; + + // Default-construct parsed template arguments. + ParsedTemplateArgument *TemplateArgs = TemplateId->getTemplateArgs(); + for (unsigned I = 0; I != NumArgs; ++I) + new (TemplateArgs + I) ParsedTemplateArgument(); + return TemplateId; } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4539c039ac..8573f1dbfc 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2679,6 +2679,30 @@ public: SourceLocation CCLoc, CXXScopeSpec &SS); + /// \brief Given a C++ nested-name-specifier, produce an annotation value + /// that the parser can use later to reconstruct the given + /// nested-name-specifier. + /// + /// \param SS A nested-name-specifier. + /// + /// \returns A pointer containing all of the information in the + /// nested-name-specifier \p SS. + void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); + + /// \brief Given an annotation pointer for a nested-name-specifier, restore + /// the nested-name-specifier structure. + /// + /// \param Annotation The annotation pointer, produced by + /// \c SaveNestedNameSpecifierAnnotation(). + /// + /// \param AnnotationRange The source range corresponding to the annotation. + /// + /// \param SS The nested-name-specifier that will be updated with the contents + /// of the annotation pointer. + void RestoreNestedNameSpecifierAnnotation(void *Annotation, + SourceRange AnnotationRange, + CXXScopeSpec &SS); + bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 1b477d85a9..da12aa77dd 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -262,3 +263,94 @@ NestedNameSpecifier::print(llvm::raw_ostream &OS, void NestedNameSpecifier::dump(const LangOptions &LO) { print(llvm::errs(), PrintingPolicy(LO)); } + +unsigned +NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { + assert(Qualifier && "Expected a non-NULL qualifier"); + + // Location of the trailing '::'. + unsigned Length = sizeof(unsigned); + + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + // Nothing more to add. + break; + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + // The location of the identifier or namespace name. + Length += sizeof(unsigned); + break; + + case NestedNameSpecifier::TypeSpecWithTemplate: + 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; +} + +namespace { + /// \brief Load a (possibly unaligned) source location from a given address + /// and offset. + SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { + unsigned Raw; + memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned)); + return SourceLocation::getFromRawEncoding(Raw); + } + + /// \brief Load a (possibly unaligned) pointer from a given address and + /// offset. + void *LoadPointer(void *Data, unsigned Offset) { + void *Result; + memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); + return Result; + } +} + +SourceRange NestedNameSpecifierLoc::getSourceRange() { + NestedNameSpecifierLoc First = *this; + while (NestedNameSpecifierLoc Prefix= First.getPrefix()) + First = Prefix; + + return SourceRange(First.getLocalSourceRange().getBegin(), + getLocalSourceRange().getEnd()); +} + +SourceRange NestedNameSpecifierLoc::getLocalSourceRange() { + unsigned Offset = getDataLength(Qualifier->getPrefix()); + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + return LoadSourceLocation(Data, Offset); + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + return SourceRange(LoadSourceLocation(Data, Offset), + LoadSourceLocation(Data, Offset + sizeof(unsigned))); + + case NestedNameSpecifier::TypeSpecWithTemplate: + 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 SourceRange(); +} diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index caf7226c4d..077edd700a 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -956,8 +956,9 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, goto DoneWithDeclSpec; CXXScopeSpec SS; - SS.Adopt(static_cast<NestedNameSpecifier *>(Tok.getAnnotationValue()), - Tok.getAnnotationRange()); + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); // We are looking for a qualified typename. Token Next = NextToken(); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index ee87135601..2abec6f0cc 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -65,8 +65,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, "Call sites of this function should be guarded by checking for C++"); if (Tok.is(tok::annot_cxxscope)) { - SS.Adopt(static_cast<NestedNameSpecifier*>(Tok.getAnnotationValue()), - Tok.getAnnotationRange()); + Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(), + Tok.getAnnotationRange(), + SS); ConsumeToken(); return false; } @@ -207,10 +208,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); - if (!HasScopeSpecifier) { - SS.setBeginLoc(TypeToken.getLocation()); + if (!HasScopeSpecifier) HasScopeSpecifier = true; - } if (ParsedType T = getTypeAnnotation(TypeToken)) { if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), T, CCLoc, SS)) diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 8387c88195..59ced8b07f 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -829,7 +829,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, TemplateId->RAngleLoc = RAngleLoc; ParsedTemplateArgument *Args = TemplateId->getTemplateArgs(); for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) - Args[Arg] = TemplateArgs[Arg]; + Args[Arg] = ParsedTemplateArgument(TemplateArgs[Arg]); Tok.setAnnotationValue(TemplateId); if (TemplateKWLoc.isValid()) Tok.setLocation(TemplateKWLoc); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 3e1574c33d..07e592cdb0 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1163,7 +1163,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { else PP.EnterToken(Tok); Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); Tok.setAnnotationRange(SS.getRange()); // In case the tokens were cached, have Preprocessor replace them @@ -1200,7 +1200,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { else PP.EnterToken(Tok); Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(SS.getScopeRep()); + Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); Tok.setAnnotationRange(SS.getRange()); // In case the tokens were cached, have Preprocessor replace them with the diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index f21d90f7c8..2d85374280 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -14,6 +14,7 @@ #include "clang/Parse/ParseDiagnostic.h" // FIXME: remove this back-dependency! #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ParsedTemplate.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TypeLoc.h" #include "clang/Lex/Preprocessor.h" @@ -46,6 +47,85 @@ void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { EndLocation = TemplateId->RAngleLoc; } +CXXScopeSpec::CXXScopeSpec(const CXXScopeSpec &Other) + : Range(Other.Range), ScopeRep(Other.ScopeRep), Buffer(0), + BufferSize(Other.BufferSize), BufferCapacity(Other.BufferSize) +{ + if (BufferSize) { + Buffer = static_cast<char *>(malloc(BufferSize)); + memcpy(Buffer, Other.Buffer, BufferSize); + } +} + +CXXScopeSpec &CXXScopeSpec::operator=(const CXXScopeSpec &Other) { + Range = Other.Range; + ScopeRep = Other.ScopeRep; + if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) { + // Re-use our storage. + BufferSize = Other.BufferSize; + memcpy(Buffer, Other.Buffer, BufferSize); + return *this; + } + + if (BufferCapacity) + free(Buffer); + if (Other.Buffer) { + BufferSize = Other.BufferSize; + BufferCapacity = BufferSize; + Buffer = static_cast<char *>(malloc(BufferSize)); + memcpy(Buffer, Other.Buffer, BufferSize); + } else { + Buffer = 0; + BufferSize = 0; + BufferCapacity = 0; + } + return *this; +} + +CXXScopeSpec::~CXXScopeSpec() { + if (BufferCapacity) + free(Buffer); +} + +namespace { + void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + if (BufferSize + (End - Start) > BufferCapacity) { + // Reallocate the buffer. + unsigned NewCapacity + = std::max((unsigned)(BufferCapacity? BufferCapacity * 2 + : sizeof(void*) * 2), + (unsigned)(BufferSize + (End - Start))); + char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); + memcpy(NewBuffer, Buffer, BufferSize); + + if (BufferCapacity) + free(Buffer); + Buffer = NewBuffer; + BufferCapacity = NewCapacity; + } + + memcpy(Buffer + BufferSize, Start, End - Start); + BufferSize += End-Start; + } + + /// \brief Save a source location to the given buffer. + void SaveSourceLocation(SourceLocation Loc, char *&Buffer, + unsigned &BufferSize, unsigned &BufferCapacity) { + unsigned Raw = Loc.getRawEncoding(); + Append(reinterpret_cast<char *>(&Raw), + reinterpret_cast<char *>(&Raw) + sizeof(unsigned), + Buffer, BufferSize, BufferCapacity); + } + + /// \brief Save a pointer to the given buffer. + void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + Append(reinterpret_cast<char *>(&Ptr), + reinterpret_cast<char *>(&Ptr) + sizeof(void *), + Buffer, BufferSize, BufferCapacity); + } +} void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc, TypeLoc TL, SourceLocation ColonColonLoc) { ScopeRep = NestedNameSpecifier::Create(Context, ScopeRep, @@ -54,6 +134,13 @@ void CXXScopeSpec::Extend(ASTContext &Context, SourceLocation TemplateKWLoc, if (Range.getBegin().isInvalid()) Range.setBegin(TL.getBeginLoc()); Range.setEnd(ColonColonLoc); + + // Push source-location info into the buffer. + SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + + assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier, @@ -63,6 +150,13 @@ void CXXScopeSpec::Extend(ASTContext &Context, IdentifierInfo *Identifier, if (Range.getBegin().isInvalid()) Range.setBegin(IdentifierLoc); Range.setEnd(ColonColonLoc); + + // Push source-location info into the buffer. + SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + + assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace, @@ -72,6 +166,13 @@ void CXXScopeSpec::Extend(ASTContext &Context, NamespaceDecl *Namespace, if (Range.getBegin().isInvalid()) Range.setBegin(NamespaceLoc); Range.setEnd(ColonColonLoc); + + // Push source-location info into the buffer. + SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + + assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias, @@ -81,6 +182,13 @@ void CXXScopeSpec::Extend(ASTContext &Context, NamespaceAliasDecl *Alias, if (Range.getBegin().isInvalid()) Range.setBegin(AliasLoc); Range.setEnd(ColonColonLoc); + + // Push source-location info into the buffer. + SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + + assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); } void CXXScopeSpec::MakeGlobal(ASTContext &Context, @@ -88,6 +196,87 @@ void CXXScopeSpec::MakeGlobal(ASTContext &Context, assert(!ScopeRep && "Already have a nested-name-specifier!?"); ScopeRep = NestedNameSpecifier::GlobalSpecifier(Context); Range = SourceRange(ColonColonLoc); + + // Push source-location info into the buffer. + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); + + assert(Range == NestedNameSpecifierLoc(ScopeRep, Buffer).getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); +} + +void CXXScopeSpec::MakeTrivial(ASTContext &Context, + NestedNameSpecifier *Qualifier, SourceRange R) { + ScopeRep = Qualifier; + Range = R; + + // Construct bogus (but well-formed) source information for the + // nested-name-specifier. + BufferSize = 0; + llvm::SmallVector<NestedNameSpecifier *, 4> Stack; + for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) + Stack.push_back(NNS); + while (!Stack.empty()) { + NestedNameSpecifier *NNS = Stack.back(); + Stack.pop_back(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + TypeSourceInfo *TSInfo + = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), + R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + + case NestedNameSpecifier::Global: + break; + } + + // Save the location of the '::'. + SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), + Buffer, BufferSize, BufferCapacity); + } +} + +void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { + if (!Other) { + Range = SourceRange(); + ScopeRep = 0; + return; + } + + if (BufferCapacity) + free(Buffer); + + // Rather than copying the data (which is wasteful), "adopt" the + // pointer (which points into the ASTContext) but set the capacity to zero to + // indicate that we don't own it. + Range = Other.getSourceRange(); + ScopeRep = Other.getNestedNameSpecifier(); + Buffer = static_cast<char *>(Other.getOpaqueData()); + BufferSize = Other.getDataLength(); + BufferCapacity = 0; +} + +NestedNameSpecifierLoc CXXScopeSpec::getWithLocInContext(ASTContext &Context) { + if (isEmpty() || isInvalid()) + return NestedNameSpecifierLoc(); + + // If we adopted our data pointer from elsewhere in the AST context, there's + // no need to copy the memory. + if (BufferCapacity == 0) + return NestedNameSpecifierLoc(ScopeRep, Buffer); + + void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>()); + memcpy(Mem, Buffer, BufferSize); + return NestedNameSpecifierLoc(ScopeRep, Mem); } /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 9daec58d4e..7ad4b45945 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -658,6 +658,41 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, return false; } +namespace { + /// \brief A structure that stores a nested-name-specifier annotation, + /// including both the nested-name-specifier + struct NestedNameSpecifierAnnotation { + NestedNameSpecifier *NNS; + }; +} + +void *Sema::SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS) { + if (SS.isEmpty() || SS.isInvalid()) + return 0; + + void *Mem = Context.Allocate((sizeof(NestedNameSpecifierAnnotation) + + SS.location_size()), + llvm::alignOf<NestedNameSpecifierAnnotation>()); + NestedNameSpecifierAnnotation *Annotation + = new (Mem) NestedNameSpecifierAnnotation; + Annotation->NNS = SS.getScopeRep(); + memcpy(Annotation + 1, SS.location_data(), SS.location_size()); + return Annotation; +} + +void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr, + SourceRange AnnotationRange, + CXXScopeSpec &SS) { + if (!AnnotationPtr) { + SS.SetInvalid(AnnotationRange); + return; + } + + NestedNameSpecifierAnnotation *Annotation + = static_cast<NestedNameSpecifierAnnotation *>(AnnotationPtr); + SS.Adopt(NestedNameSpecifierLoc(Annotation->NNS, Annotation + 1)); +} + bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 30946224e5..8e1792bf1d 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -5085,8 +5085,10 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // reference to operator=; this is required to suppress the virtual // call mechanism. CXXScopeSpec SS; - SS.Adopt(NestedNameSpecifier::Create(S.Context, 0, false, T.getTypePtr()), - Loc); + SS.MakeTrivial(S.Context, + NestedNameSpecifier::Create(S.Context, 0, false, + T.getTypePtr()), + Loc); // Create the reference to operator=. ExprResult OpEqualRef diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c0e08c0720..81bdbc6eef 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -107,7 +107,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // Nothing left to do. } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { CXXScopeSpec PrefixSS; - PrefixSS.Adopt(Prefix, SS.getRange()); + PrefixSS.MakeTrivial(Context, Prefix, SS.getRange()); LookupCtx = computeDeclContext(PrefixSS, EnteringContext); isDependent = isDependentScopeSpecifier(PrefixSS); } else if (ObjectTypePtr) { diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 7d3de8dde0..60873cd969 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -7594,7 +7594,8 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, CXXScopeSpec SS; if (ULE->getQualifier()) - SS.Adopt(ULE->getQualifier(), ULE->getQualifierRange()); + SS.MakeTrivial(SemaRef.Context, + ULE->getQualifier(), ULE->getQualifierRange()); TemplateArgumentListInfo TABuffer; const TemplateArgumentListInfo *ExplicitTemplateArgs = 0; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d75a1f1503..474a18df7f 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3611,7 +3611,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, = NestedNameSpecifier::Create(Context, 0, false, ClassType.getTypePtr()); CXXScopeSpec SS; - SS.Adopt(Qualifier, Loc); + SS.MakeTrivial(Context, Qualifier, Loc); // The actual value-ness of this is unimportant, but for // internal consistency's sake, references to instance methods @@ -5998,7 +5998,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, SourceRange NNSRange, SourceLocation IILoc) { CXXScopeSpec SS; - SS.Adopt(NNS, NNSRange); + SS.MakeTrivial(Context, NNS, NNSRange); DeclContext *Ctx = computeDeclContext(SS); if (!Ctx) { @@ -6177,7 +6177,7 @@ bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); if (!Rebuilt) return true; - SS.Adopt(Rebuilt, SS.getRange()); + SS.MakeTrivial(Context, Rebuilt, SS.getRange()); return false; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 73511fbc7a..de4cd46e7a 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -670,7 +670,7 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (isFriend) { if (Qualifier) { CXXScopeSpec SS; - SS.Adopt(Qualifier, Pattern->getQualifierRange()); + SS.MakeTrivial(SemaRef.Context, Qualifier, Pattern->getQualifierRange()); DC = SemaRef.computeDeclContext(SS); if (!DC) return 0; } else { @@ -983,7 +983,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, DC = Owner; else if (isFriend && Qualifier) { CXXScopeSpec SS; - SS.Adopt(Qualifier, D->getQualifierRange()); + SS.MakeTrivial(SemaRef.Context, Qualifier, D->getQualifierRange()); DC = SemaRef.computeDeclContext(SS); if (!DC) return 0; } else { @@ -1272,7 +1272,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, if (isFriend) { if (Qualifier) { CXXScopeSpec SS; - SS.Adopt(Qualifier, D->getQualifierRange()); + SS.MakeTrivial(SemaRef.Context, Qualifier, D->getQualifierRange()); DC = SemaRef.computeDeclContext(SS); |