From 15de72cf580840c61e5704c2f8a2b56f9d0638e1 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 2 Dec 2011 23:23:56 +0000 Subject: [PATCH] Introduce a module import declaration, so that we properly represent, e.g., __import_module__ std.vector; in the AST. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@145725 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Decl.h | 66 ++++++++++++++++++- include/clang/AST/RecursiveASTVisitor.h | 2 + include/clang/Basic/DeclNodes.td | 2 + include/clang/Serialization/ASTBitCodes.h | 4 +- lib/AST/Decl.cpp | 79 +++++++++++++++++++++++ lib/AST/DeclBase.cpp | 1 + lib/AST/DeclPrinter.cpp | 7 ++ lib/CodeGen/CGDecl.cpp | 1 + lib/CodeGen/CodeGenModule.cpp | 1 + lib/Sema/SemaDecl.cpp | 21 +++++- lib/Serialization/ASTReaderDecl.cpp | 20 ++++++ lib/Serialization/ASTWriterDecl.cpp | 19 ++++++ tools/libclang/CIndex.cpp | 1 + 13 files changed, 219 insertions(+), 5 deletions(-) diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index b3b8da057d..c3f5bd0acf 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -40,7 +40,8 @@ class DependentFunctionTemplateSpecializationInfo; class TypeLoc; class UnresolvedSetImpl; class LabelStmt; - +class Module; + /// \brief A container of type source information. /// /// A client can read the relevant info using TypeLoc wrappers, e.g: @@ -3075,6 +3076,69 @@ public: } }; +/// \brief Describes a module import declaration, which makes the contents +/// of the named module visible in the current translation unit. +/// +/// An import declaration imports the named module (or submodule). For example: +/// \code +/// __import_module__ std.vector; +/// \endcode +/// +/// Import declarations can also be implicitly generated from #include/#import +/// directives. +class ImportDecl : public Decl { + /// \brief The imported module, along with a bit that indicates whether + /// we have source-location information for each identifier in the module + /// name. + /// + /// When the bit is false, we only have a single source location for the + /// end of the import declaration. + llvm::PointerIntPair ImportedAndComplete; + + friend class ASTReader; + friend class ASTDeclReader; + + ImportDecl(DeclContext *DC, SourceLocation ImportLoc, Module *Imported, + ArrayRef IdentifierLocs); + + ImportDecl(DeclContext *DC, SourceLocation ImportLoc, Module *Imported, + SourceLocation EndLoc); + + ImportDecl(EmptyShell Empty) : Decl(Import, Empty) { } + +public: + /// \brief Create a new module import declaration. + static ImportDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation ImportLoc, Module *Imported, + ArrayRef IdentifierLocs); + + /// \brief Create a new module import declaration for an implicitly-generated + /// import. + static ImportDecl *CreateImplicit(ASTContext &C, DeclContext *DC, + SourceLocation ImportLoc, Module *Imported, + SourceLocation EndLoc); + + /// \brief Create a new module import declaration. + static ImportDecl *CreateEmpty(ASTContext &C, unsigned NumLocations); + + /// \brief Retrieve the module that was imported by the import declaration. + Module *getImportedModule() const { return ImportedAndComplete.getPointer(); } + + /// \brief Retrieves the locations of each of the identifiers that make up + /// the complete module name in the import declaration. + /// + /// This will return an empty array if the locations of the individual + /// identifiers aren't available. + ArrayRef getIdentifierLocs() const; + + virtual SourceRange getSourceRange() const; + + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const ImportDecl *D) { return true; } + static bool classofKind(Kind K) { return K == Import; } +}; + + /// Insertion operator for diagnostics. This allows sending NamedDecl's /// into a diagnostic with <<. inline const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index f553ec1f95..cca85ac865 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1131,6 +1131,8 @@ DEF_TRAVERSE_DECL(FileScopeAsmDecl, { TRY_TO(TraverseStmt(D->getAsmString())); }) +DEF_TRAVERSE_DECL(ImportDecl, { }) + DEF_TRAVERSE_DECL(FriendDecl, { // Friend is either decl or a type. if (D->getFriendType()) diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index a37dc10398..37c6a8b15a 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -75,3 +75,5 @@ def FriendTemplate : Decl; def StaticAssert : Decl; def Block : Decl, DeclContext; def ClassScopeFunctionSpecialization : Decl; +def Import : Decl; + diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 88e0650c04..3233a83931 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -909,7 +909,9 @@ namespace clang { DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK, /// \brief A ClassScopeFunctionSpecializationDecl record a class scope /// function specialization. (Microsoft extension). - DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION + DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION, + /// \brief An ImportDecl recording a module import. + DECL_IMPORT }; /// \brief Record codes for each kind of statement or expression. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 5c7c0694a0..2f167eedd1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Module.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" #include "llvm/Support/ErrorHandling.h" @@ -2609,3 +2610,81 @@ FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation RParenLoc) { return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc); } + +//===----------------------------------------------------------------------===// +// ImportDecl Implementation +//===----------------------------------------------------------------------===// + +/// \brief Retrieve the number of module identifiers needed to name the given +/// module. +static unsigned getNumModuleIdentifiers(Module *Mod) { + unsigned Result = 1; + while (Mod->Parent) { + Mod = Mod->Parent; + ++Result; + } + return Result; +} + +ImportDecl::ImportDecl(DeclContext *DC, SourceLocation ImportLoc, + Module *Imported, + ArrayRef IdentifierLocs) + : Decl(Import, DC, ImportLoc), ImportedAndComplete(Imported, true) +{ + assert(getNumModuleIdentifiers(Imported) == IdentifierLocs.size()); + SourceLocation *StoredLocs = reinterpret_cast(this + 1); + memcpy(StoredLocs, IdentifierLocs.data(), + IdentifierLocs.size() * sizeof(SourceLocation)); +} + +ImportDecl::ImportDecl(DeclContext *DC, SourceLocation ImportLoc, + Module *Imported, SourceLocation EndLoc) + : Decl(Import, DC, ImportLoc), ImportedAndComplete(Imported, false) +{ + *reinterpret_cast(this + 1) = EndLoc; +} + +ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation ImportLoc, Module *Imported, + ArrayRef IdentifierLocs) { + void *Mem = C.Allocate(sizeof(ImportDecl) + + IdentifierLocs.size() * sizeof(SourceLocation)); + return new (Mem) ImportDecl(DC, ImportLoc, Imported, IdentifierLocs); +} + +ImportDecl *ImportDecl::CreateImplicit(ASTContext &C, DeclContext *DC, + SourceLocation ImportLoc, + Module *Imported, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(ImportDecl) + sizeof(SourceLocation)); + ImportDecl *Import + = new (Mem) ImportDecl(DC, ImportLoc, Imported, + ArrayRef(&EndLoc, 1)); + Import->setImplicit(); + return Import; +} + +ImportDecl *ImportDecl::CreateEmpty(ASTContext &C, unsigned NumLocations) { + void *Mem = C.Allocate(sizeof(ImportDecl) + + NumLocations * sizeof(SourceLocation)); + return new (Mem) ImportDecl(EmptyShell()); +} + +ArrayRef ImportDecl::getIdentifierLocs() const { + if (!ImportedAndComplete.getInt()) + return ArrayRef(); + + const SourceLocation *StoredLocs + = reinterpret_cast(this + 1); + return ArrayRef(StoredLocs, + getNumModuleIdentifiers(getImportedModule())); +} + +SourceRange ImportDecl::getSourceRange() const { + if (!ImportedAndComplete.getInt()) + return SourceRange(getLocation(), + *reinterpret_cast(this + 1)); + + return SourceRange(getLocation(), getIdentifierLocs().back()); +} + diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d892c56f71..f4507e3603 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -501,6 +501,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case ObjCImplementation: case ObjCCategory: case ObjCCategoryImpl: + case Import: // Never looked up by name. return 0; } diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index e5b4b0431b..91b011fbda 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Module.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -58,6 +59,7 @@ namespace { void VisitLabelDecl(LabelDecl *D); void VisitParmVarDecl(ParmVarDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitImportDecl(ImportDecl *D); void VisitStaticAssertDecl(StaticAssertDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); @@ -646,6 +648,11 @@ void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { Out << ")"; } +void DeclPrinter::VisitImportDecl(ImportDecl *D) { + Out << "__import_module__ " << D->getImportedModule()->getFullModuleName() + << ";\n"; +} + void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { Out << "static_assert("; D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation); diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 59efea0dae..c7bc87ba1e 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -84,6 +84,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::NamespaceAlias: case Decl::StaticAssert: // static_assert(X, ""); [C++0x] case Decl::Label: // __label__ x; + case Decl::Import: // None of these decls require codegen support. return; diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 0905c4b283..0e8468f31d 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -2335,6 +2335,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::TypeAliasTemplate: case Decl::NamespaceAlias: case Decl::Block: + case Decl::Import: break; case Decl::CXXConstructor: // Skip function templates diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 1e57a00f1f..01c7906e80 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -9897,9 +9897,24 @@ DeclResult Sema::ActOnModuleImport(SourceLocation ImportLoc, ModuleIdPath Path) if (!Mod) return true; - // FIXME: Actually create a declaration to describe the module import. - (void)Mod; - return DeclResult((Decl *)0); + llvm::SmallVector IdentifierLocs; + Module *ModCheck = Mod; + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + // If we've run out of module parents, just drop the remaining identifiers. + // We need the length to be consistent. + if (!ModCheck) + break; + ModCheck = ModCheck->Parent; + + IdentifierLocs.push_back(Path[I].second); + } + + ImportDecl *Import = ImportDecl::Create(Context, + Context.getTranslationUnitDecl(), + ImportLoc, Mod, + IdentifierLocs); + Context.getTranslationUnitDecl()->addDecl(Import); + return Import; } void diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 85cd72840a..e9833c394c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -94,6 +94,10 @@ namespace clang { return Reader.getGlobalSubmoduleID(F, R[I++]); } + Module *readModule(const RecordData &R, unsigned &I) { + return Reader.getSubmodule(readSubmoduleID(R, I)); + } + void ReadCXXDefinitionData(struct CXXRecordDecl::DefinitionData &Data, const RecordData &R, unsigned &I); @@ -168,6 +172,7 @@ namespace clang { void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *AD); + void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); @@ -1054,6 +1059,16 @@ void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { D->IsExplicitSpecified = Record[Idx++]; } +void ASTDeclReader::VisitImportDecl(ImportDecl *D) { + VisitDecl(D); + D->ImportedAndComplete.setPointer(readModule(Record, Idx)); + D->ImportedAndComplete.setInt(Record[Idx++]); + SourceLocation *StoredLocs = reinterpret_cast(D + 1); + for (unsigned I = 0, N = Record.back(); I != N; ++I) + StoredLocs[I] = ReadSourceLocation(Record, Idx); + ++Idx; +} + void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); D->setColonLoc(ReadSourceLocation(Record, Idx)); @@ -1760,6 +1775,11 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_CXX_BASE_SPECIFIERS: Error("attempt to read a C++ base-specifier record as a declaration"); return 0; + case DECL_IMPORT: + // Note: last entry of the ImportDecl record is the number of stored source + // locations. + D = ImportDecl::CreateEmpty(Context, Record.back()); + break; } assert(D && "Unknown declaration reading AST file"); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 4075db8d26..afb7ca9f9f 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -94,6 +94,7 @@ namespace clang { void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitImportDecl(ImportDecl *D); void VisitAccessSpecDecl(AccessSpecDecl *D); void VisitFriendDecl(FriendDecl *D); void VisitFriendTemplateDecl(FriendTemplateDecl *D); @@ -972,6 +973,24 @@ void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { Code = serialization::DECL_CXX_CONVERSION; } +void ASTDeclWriter::VisitImportDecl(ImportDecl *D) { + VisitDecl(D); + Writer.SubmoduleIDs[D->getImportedModule()]; + ArrayRef IdentifierLocs = D->getIdentifierLocs(); + Record.push_back(!IdentifierLocs.empty()); + if (IdentifierLocs.empty()) { + Writer.AddSourceLocation(D->getLocEnd(), Record); + Record.push_back(1); + } else { + for (unsigned I = 0, N = IdentifierLocs.size(); I != N; ++I) + Writer.AddSourceLocation(IdentifierLocs[I], Record); + Record.push_back(IdentifierLocs.size()); + } + // Note: the number of source locations must always be the last element in + // the record. + Code = serialization::DECL_IMPORT; +} + void ASTDeclWriter::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); Writer.AddSourceLocation(D->getColonLoc(), Record); diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index beb50a7c87..5e1d1234d9 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -4000,6 +4000,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Block: case Decl::Label: // FIXME: Is this right?? case Decl::ClassScopeFunctionSpecialization: + case Decl::Import: return C; // Declaration kinds that don't make any sense here, but are -- 2.40.0