Implement basic importing and merging of variable declarations within

the AST importer. This doesn't actually do anything (yet), because we
don't have driver logic for merging ASTs.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@95570 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-02-08 21:09:39 +00:00
Родитель 7aaa953581
Коммит 089459a16b
5 изменённых файлов: 190 добавлений и 3 удалений

Просмотреть файл

@ -44,11 +44,15 @@ namespace clang {
/// to the corresponding types in the "to" context.
llvm::DenseMap<Type *, Type *> ImportedTypes;
/// \brief Mapping from the already-imported declarations in the "from"
/// context to the corresponding declarations in the "to" context.
llvm::DenseMap<Decl *, Decl *> ImportedDecls;
public:
ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
ASTContext &FromContext, Diagnostic &FromDiags);
~ASTImporter();
virtual ~ASTImporter();
/// \brief Import the given type from the "from" context into the "to"
/// context.
@ -126,6 +130,38 @@ namespace clang {
/// \returns the equivalent identifier in the "to" context.
IdentifierInfo *Import(IdentifierInfo *FromId);
/// \brief Cope with a name conflict when importing a declaration into the
/// given context.
///
/// This routine is invoked whenever there is a name conflict while
/// importing a declaration. The returned name will become the name of the
/// imported declaration. By default, the returned name is the same as the
/// original name, leaving the conflict unresolve such that name lookup
/// for this name is likely to find an ambiguity later.
///
/// Subclasses may override this routine to resolve the conflict, e.g., by
/// renaming the declaration being imported.
///
/// \param Name the name of the declaration being imported, which conflicts
/// with other declarations.
///
/// \param DC the declaration context (in the "to" AST context) in which
/// the name is being imported.
///
/// \param IDNS the identifier namespace in which the name will be found.
///
/// \param Decls the set of declarations with the same name as the
/// declaration being imported.
///
/// \param NumDecls the number of conflicting declarations in \p Decls.
///
/// \returns the name that the newly-imported declaration should have.
virtual DeclarationName HandleNameConflict(DeclarationName Name,
DeclContext *DC,
unsigned IDNS,
NamedDecl **Decls,
unsigned NumDecls);
/// \brief Retrieve the context that AST nodes are being imported into.
ASTContext &getToContext() const { return ToContext; }
@ -139,6 +175,16 @@ namespace clang {
/// \brief Retrieve the diagnostics object to use to report errors within
/// the context we're importing from.
Diagnostic &getFromDiags() const { return FromDiags; }
/// \brief Retrieve the mapping from declarations in the "from" context
/// to the already-imported declarations in the "to" context.
llvm::DenseMap<Decl *, Decl *> &getImportedDecls() { return ImportedDecls; }
/// \brief Report a diagnostic in the "to" context.
DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID);
/// \brief Report a diagnostic in the "from" context.
DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID);
};
}

Просмотреть файл

@ -26,4 +26,12 @@ def err_asm_empty_symbolic_operand_name : Error<
def err_asm_invalid_operand_number : Error<
"invalid operand number in inline asm string">;
// Importing ASTs
def err_odr_variable_type_inconsistent : Error<
"external variable %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
def err_odr_variable_multiple_def : Error<
"external variable %0 defined in multiple translation units">;
def note_odr_value_here : Note<"declared here with type %0">;
def note_odr_defined_here : Note<"also defined here">;
}

Просмотреть файл

@ -2724,6 +2724,7 @@ def err_undeclared_protocol_suggest : Error<
"cannot find protocol declaration for %0; did you mean %1?">;
def note_base_class_specified_here : Note<
"base class %0 specified here">;
}

Просмотреть файл

@ -167,7 +167,7 @@ public:
};
/// ASTFrontendAction - Abstract base class to use for AST consumer based
/// frontend actios.
/// frontend actions.
class ASTFrontendAction : public FrontendAction {
/// ExecuteAction - Implement the ExecuteAction interface by running Sema on
/// the already initialized AST consumer.

Просмотреть файл

@ -15,12 +15,15 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeVisitor.h"
#include "clang/AST/ASTDiagnostic.h"
using namespace clang;
namespace {
class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType> {
class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
public DeclVisitor<ASTNodeImporter, Decl *> {
ASTImporter &Importer;
public:
@ -62,6 +65,9 @@ namespace {
// FIXME: TypenameType
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
// Importing declarations
Decl *VisitVarDecl(VarDecl *D);
};
}
@ -425,6 +431,114 @@ QualType ASTNodeImporter::VisitObjCObjectPointerType(ObjCObjectPointerType *T) {
Protocols.size());
}
//----------------------------------------------------------------------------
// Import Declarations
//----------------------------------------------------------------------------
Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Import the context of this declaration.
DeclContext *DC = Importer.ImportContext(D->getDeclContext());
if (!DC)
return 0;
// Import the name of this declaration.
DeclarationName Name = Importer.Import(D->getDeclName());
if (D->getDeclName() && !Name)
return 0;
// Import the type of this declaration.
QualType T = Importer.Import(D->getType());
if (T.isNull())
return 0;
// Import the location of this declaration.
SourceLocation Loc = Importer.Import(D->getLocation());
// Try to find a variable in our own ("to") context with the same name and
// in the same context as the variable we're importing.
if (!D->isFileVarDecl()) {
VarDecl *MergeWithVar = 0;
llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
unsigned IDNS = Decl::IDNS_Ordinary;
for (DeclContext::lookup_result Lookup = DC->lookup(D->getDeclName());
Lookup.first != Lookup.second;
++Lookup.first) {
if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
continue;
if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) {
// We have found a variable that we may need to merge with. Check it.
if (isExternalLinkage(FoundVar->getLinkage()) &&
isExternalLinkage(D->getLinkage())) {
if (Importer.getToContext().typesAreCompatible(T,
FoundVar->getType())) {
MergeWithVar = FoundVar;
break;
}
Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent)
<< Name << T << FoundVar->getType();
Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
<< FoundVar->getType();
}
}
ConflictingDecls.push_back(*Lookup.first);
}
if (MergeWithVar) {
// An equivalent variable with external linkage has been found. Link
// the two declarations, then merge them.
Importer.getImportedDecls()[D] = MergeWithVar;
if (VarDecl *DDef = D->getDefinition()) {
if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) {
Importer.ToDiag(ExistingDef->getLocation(),
diag::err_odr_variable_multiple_def)
<< Name;
Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here);
} else {
Expr *Init = Importer.Import(DDef->getInit());
MergeWithVar->setInit(Importer.getToContext(), Init);
}
}
return MergeWithVar;
}
if (!ConflictingDecls.empty()) {
Name = Importer.HandleNameConflict(Name, DC, IDNS,
ConflictingDecls.data(),
ConflictingDecls.size());
if (!Name)
return 0;
}
}
TypeSourceInfo *TInfo = 0;
if (TypeSourceInfo *FromTInfo = D->getTypeSourceInfo()) {
TInfo = Importer.Import(FromTInfo);
if (!TInfo)
return 0;
}
// Create the imported variable.
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
Name.getAsIdentifierInfo(), T, TInfo,
D->getStorageClass());
Importer.getImportedDecls()[D] = ToVar;
// Merge the initializer.
// FIXME: Can we really import any initializer? Alternatively, we could force
// ourselves to import every declaration of a variable and then only use
// getInit() here.
ToVar->setInit(Importer.getToContext(),
Importer.Import(const_cast<Expr *>(D->getAnyInitializer())));
// FIXME: Other bits to merge?
return ToVar;
}
ASTImporter::ASTImporter(ASTContext &ToContext, Diagnostic &ToDiags,
ASTContext &FromContext, Diagnostic &FromDiags)
: ToContext(ToContext), FromContext(FromContext),
@ -515,3 +629,21 @@ IdentifierInfo *ASTImporter::Import(IdentifierInfo *FromId) {
return &ToContext.Idents.get(FromId->getName());
}
DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
DeclContext *DC,
unsigned IDNS,
NamedDecl **Decls,
unsigned NumDecls) {
return Name;
}
DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
return ToDiags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()),
DiagID);
}
DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
return FromDiags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()),
DiagID);
}