зеркало из https://github.com/microsoft/clang.git
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:
Родитель
7aaa953581
Коммит
089459a16b
|
@ -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);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче