aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2010-02-08 21:09:39 +0000
committerDouglas Gregor <dgregor@apple.com>2010-02-08 21:09:39 +0000
commit089459a16bf7e9cd10617d1fac5ec0240a0a1ee6 (patch)
tree96f4eb5ee5cb75969151487b4c143b7873de8951
parent7aaa9535815a9423e2574a524022c8118cc1aa3b (diff)
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
-rw-r--r--include/clang/AST/ASTImporter.h48
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td1
-rw-r--r--include/clang/Frontend/FrontendAction.h2
-rw-r--r--lib/AST/ASTImporter.cpp134
5 files changed, 190 insertions, 3 deletions
diff --git a/include/clang/AST/ASTImporter.h b/include/clang/AST/ASTImporter.h
index 01ec13470e..71b6443f50 100644
--- a/include/clang/AST/ASTImporter.h
+++ b/include/clang/AST/ASTImporter.h
@@ -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);
};
}
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index f075aaaf42..d6921df0a3 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -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">;
}
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index d31dbd531a..496e0202eb 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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">;
+
}
diff --git a/include/clang/Frontend/FrontendAction.h b/include/clang/Frontend/FrontendAction.h
index 3042767af8..29a9302c5c 100644
--- a/include/clang/Frontend/FrontendAction.h
+++ b/include/clang/Frontend/FrontendAction.h
@@ -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.
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 16fd7e6184..7668b7ba67 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -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);
+}