Introduce a module import declaration, so that we properly represent, e.g.,

__import_module__ std.vector;

in the AST.

llvm-svn: 145725
This commit is contained in:
Douglas Gregor 2011-12-02 23:23:56 +00:00
parent 45ccba64ab
commit ba34552e79
13 changed files with 219 additions and 5 deletions

View File

@ -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<Module *, 1, bool> ImportedAndComplete;
friend class ASTReader;
friend class ASTDeclReader;
ImportDecl(DeclContext *DC, SourceLocation ImportLoc, Module *Imported,
ArrayRef<SourceLocation> 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<SourceLocation> 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<SourceLocation> 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,

View File

@ -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())

View File

@ -75,3 +75,5 @@ def FriendTemplate : Decl;
def StaticAssert : Decl;
def Block : Decl, DeclContext;
def ClassScopeFunctionSpecialization : Decl;
def Import : Decl;

View File

@ -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.

View File

@ -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<SourceLocation> IdentifierLocs)
: Decl(Import, DC, ImportLoc), ImportedAndComplete(Imported, true)
{
assert(getNumModuleIdentifiers(Imported) == IdentifierLocs.size());
SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(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<SourceLocation *>(this + 1) = EndLoc;
}
ImportDecl *ImportDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation ImportLoc, Module *Imported,
ArrayRef<SourceLocation> 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<SourceLocation>(&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<SourceLocation> ImportDecl::getIdentifierLocs() const {
if (!ImportedAndComplete.getInt())
return ArrayRef<SourceLocation>();
const SourceLocation *StoredLocs
= reinterpret_cast<const SourceLocation *>(this + 1);
return ArrayRef<SourceLocation>(StoredLocs,
getNumModuleIdentifiers(getImportedModule()));
}
SourceRange ImportDecl::getSourceRange() const {
if (!ImportedAndComplete.getInt())
return SourceRange(getLocation(),
*reinterpret_cast<const SourceLocation *>(this + 1));
return SourceRange(getLocation(), getIdentifierLocs().back());
}

View File

@ -501,6 +501,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) {
case ObjCImplementation:
case ObjCCategory:
case ObjCCategoryImpl:
case Import:
// Never looked up by name.
return 0;
}

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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<SourceLocation, 2> 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

View File

@ -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<SourceLocation *>(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");

View File

@ -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<SourceLocation> 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);

View File

@ -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