[cfe-commits] r95570 - in /cfe/trunk: include/clang/AST/ASTImporter.h include/clang/Basic/DiagnosticASTKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Frontend/FrontendAction.h lib/AST/ASTImporter.cpp
Douglas Gregor
dgregor at apple.com
Mon Feb 8 13:09:39 PST 2010
Author: dgregor
Date: Mon Feb 8 15:09:39 2010
New Revision: 95570
URL: http://llvm.org/viewvc/llvm-project?rev=95570&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/ASTImporter.h
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Frontend/FrontendAction.h
cfe/trunk/lib/AST/ASTImporter.cpp
Modified: cfe/trunk/include/clang/AST/ASTImporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTImporter.h?rev=95570&r1=95569&r2=95570&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTImporter.h (original)
+++ cfe/trunk/include/clang/AST/ASTImporter.h Mon Feb 8 15:09:39 2010
@@ -44,11 +44,15 @@
/// 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 @@
/// \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 @@
/// \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);
};
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=95570&r1=95569&r2=95570&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Mon Feb 8 15:09:39 2010
@@ -26,4 +26,12 @@
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">;
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=95570&r1=95569&r2=95570&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Feb 8 15:09:39 2010
@@ -2724,6 +2724,7 @@
"cannot find protocol declaration for %0; did you mean %1?">;
def note_base_class_specified_here : Note<
"base class %0 specified here">;
+
}
Modified: cfe/trunk/include/clang/Frontend/FrontendAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=95570&r1=95569&r2=95570&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendAction.h (original)
+++ cfe/trunk/include/clang/Frontend/FrontendAction.h Mon Feb 8 15:09:39 2010
@@ -167,7 +167,7 @@
};
/// 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.
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=95570&r1=95569&r2=95570&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Feb 8 15:09:39 2010
@@ -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 @@
// FIXME: TypenameType
QualType VisitObjCInterfaceType(ObjCInterfaceType *T);
QualType VisitObjCObjectPointerType(ObjCObjectPointerType *T);
+
+ // Importing declarations
+ Decl *VisitVarDecl(VarDecl *D);
};
}
@@ -425,6 +431,114 @@
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 @@
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);
+}
More information about the cfe-commits
mailing list