[cfe-commits] r95833 - in /cfe/trunk: include/clang/AST/DeclCXX.h lib/AST/ASTImporter.cpp
Douglas Gregor
dgregor at apple.com
Wed Feb 10 16:48:18 PST 2010
Author: dgregor
Date: Wed Feb 10 18:48:18 2010
New Revision: 95833
URL: http://llvm.org/viewvc/llvm-project?rev=95833&view=rev
Log:
Implement basic AST merging for classes, structs, and unions in C.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/lib/AST/ASTImporter.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=95833&r1=95832&r2=95833&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Feb 10 18:48:18 2010
@@ -145,6 +145,10 @@
/// class (or not).
bool isVirtual() const { return Virtual; }
+ /// \brief Determine whether this base class if a base of a class declared
+ /// with the 'class' keyword (vs. one declared with the 'struct' keyword).
+ bool isBaseOfClass() const { return BaseOfClass; }
+
/// getAccessSpecifier - Returns the access specifier for this base
/// specifier. This is the actual base specifier as used for
/// semantic analysis, so the result can never be AS_none. To
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=95833&r1=95832&r2=95833&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Feb 10 18:48:18 2010
@@ -15,6 +15,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
+#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclVisitor.h"
#include "clang/AST/TypeLoc.h"
@@ -80,9 +81,12 @@
DeclContext *&DC, DeclContext *&LexicalDC,
DeclarationName &Name, SourceLocation &Loc,
QualType &T);
+ bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
Decl *VisitDecl(Decl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitRecordDecl(RecordDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D);
+ Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitVarDecl(VarDecl *D);
Decl *VisitParmVarDecl(ParmVarDecl *D);
};
@@ -500,6 +504,89 @@
return false;
}
+bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
+ RecordDecl *ToRecord) {
+ // FIXME: If we know that the two records are the same according to the ODR,
+ // we could diagnose structural mismatches here. However, we don't really
+ // have that information.
+ if (FromRecord->isUnion() != ToRecord->isUnion())
+ return false;
+
+ if (CXXRecordDecl *FromCXX = dyn_cast<CXXRecordDecl>(FromRecord)) {
+ if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(ToRecord)) {
+ if (FromCXX->getNumBases() != ToCXX->getNumBases())
+ return false;
+
+ // Check the base classes.
+ for (CXXRecordDecl::base_class_iterator FromBase = FromCXX->bases_begin(),
+ FromBaseEnd = FromCXX->bases_end(),
+ ToBase = ToCXX->bases_begin();
+ FromBase != FromBaseEnd;
+ ++FromBase, ++ToBase) {
+ // Check virtual vs. non-virtual inheritance mismatch.
+ if (FromBase->isVirtual() != ToBase->isVirtual())
+ return false;
+
+ // Check the type we're inheriting from.
+ QualType FromBaseT = Importer.Import(FromBase->getType());
+ if (FromBaseT.isNull())
+ return false;
+
+ if (!Importer.getToContext().typesAreCompatible(FromBaseT,
+ ToBase->getType()))
+ return false;
+ }
+ } else if (FromCXX->getNumBases() > 0) {
+ return false;
+ }
+ }
+
+ // Check the fields for consistency.
+ CXXRecordDecl::field_iterator ToField = ToRecord->field_begin(),
+ ToFieldEnd = ToRecord->field_end();
+ for (CXXRecordDecl::field_iterator FromField = FromRecord->field_begin(),
+ FromFieldEnd = FromRecord->field_end();
+ FromField != FromFieldEnd;
+ ++FromField, ++ToField) {
+ if (ToField == ToFieldEnd)
+ return false;
+
+ QualType FromT = Importer.Import(FromField->getType());
+ if (FromT.isNull())
+ return false;
+
+ if (FromField->isBitField() != ToField->isBitField())
+ return false;
+
+ if (!Importer.getToContext().typesAreCompatible(FromT, ToField->getType()))
+ return false;
+
+ if (FromField->isBitField()) {
+ // Make sure that the bit-fields are the same length.
+ llvm::APSInt FromBits, ToBits;
+ if (!FromField->getBitWidth()->isIntegerConstantExpr(FromBits,
+ Importer.getFromContext()))
+ return false;
+ if (!ToField->getBitWidth()->isIntegerConstantExpr(ToBits,
+ Importer.getToContext()))
+ return false;
+
+ if (FromBits.getBitWidth() > ToBits.getBitWidth())
+ ToBits.extend(FromBits.getBitWidth());
+ else if (ToBits.getBitWidth() > FromBits.getBitWidth())
+ FromBits.extend(ToBits.getBitWidth());
+
+ FromBits.setIsUnsigned(true);
+ ToBits.setIsUnsigned(true);
+
+ if (FromBits != ToBits)
+ return false;
+ }
+ }
+
+ return ToField == ToFieldEnd;
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -561,6 +648,124 @@
return ToTypedef;
}
+Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
+ // If this record has a definition in the translation unit we're coming from,
+ // but this particular declaration is not that definition, import the
+ // definition and map to that.
+ TagDecl *Definition = D->getDefinition(Importer.getFromContext());
+ if (Definition && Definition != D) {
+ Decl *ImportedDef = Importer.Import(Definition);
+ Importer.getImportedDecls()[D] = ImportedDef;
+ return ImportedDef;
+ }
+
+ // Import the major distinguishing characteristics of this record.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Figure out what structure name we're looking for.
+ unsigned IDNS = Decl::IDNS_Tag;
+ DeclarationName SearchName = Name;
+ if (!SearchName && D->getTypedefForAnonDecl()) {
+ SearchName = Importer.Import(D->getTypedefForAnonDecl()->getDeclName());
+ IDNS = Decl::IDNS_Ordinary;
+ } else if (Importer.getToContext().getLangOptions().CPlusPlus)
+ IDNS |= Decl::IDNS_Ordinary;
+
+ // We may already have a record of the same name; try to find and match it.
+ if (!DC->isFunctionOrMethod() && SearchName) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ Decl *Found = *Lookup.first;
+ if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Found)) {
+ if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>())
+ Found = Tag->getDecl();
+ }
+
+ if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundRecord)) {
+ // The record types structurally match.
+ // FIXME: For C++, we should also merge methods here.
+ Importer.getImportedDecls()[D] = FoundRecord;
+ return FoundRecord;
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the record declaration.
+ RecordDecl *ToRecord = 0;
+ if (CXXRecordDecl *FromCXX = dyn_cast<CXXRecordDecl>(D)) {
+ CXXRecordDecl *ToCXX = CXXRecordDecl::Create(Importer.getToContext(),
+ D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ ToRecord = ToCXX;
+
+ if (D->isDefinition()) {
+ // Add base classes.
+ llvm::SmallVector<CXXBaseSpecifier *, 4> Bases;
+ for (CXXRecordDecl::base_class_iterator FromBase = FromCXX->bases_begin(),
+ FromBaseEnd = FromCXX->bases_end();
+ FromBase != FromBaseEnd;
+ ++FromBase) {
+ QualType T = Importer.Import(FromBase->getType());
+ if (T.isNull())
+ return 0;
+
+ Bases.push_back(
+ new (Importer.getToContext())
+ CXXBaseSpecifier(Importer.Import(FromBase->getSourceRange()),
+ FromBase->isVirtual(),
+ FromBase->isBaseOfClass(),
+ FromBase->getAccessSpecifierAsWritten(),
+ T));
+ }
+ if (!Bases.empty())
+ ToCXX->setBases(Importer.getToContext(), Bases.data(), Bases.size());
+ }
+ } else {
+ ToRecord = RecordDecl::Create(Importer.getToContext(), D->getTagKind(),
+ DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()));
+ }
+ ToRecord->setLexicalDeclContext(LexicalDC);
+ Importer.getImportedDecls()[D] = ToRecord;
+ LexicalDC->addDecl(ToRecord);
+
+ if (D->isDefinition()) {
+ ToRecord->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ ToRecord->completeDefinition(Importer.getToContext());
+ }
+
+ return ToRecord;
+}
+
+
Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the major distinguishing characteristics of this function.
DeclContext *DC, *LexicalDC;
@@ -654,6 +859,29 @@
return ToFunction;
}
+Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
+ // Import the major distinguishing characteristics of a variable.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ QualType T;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
+ return 0;
+
+ TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
+ Expr *BitWidth = Importer.Import(D->getBitWidth());
+ if (!BitWidth && D->getBitWidth())
+ return 0;
+
+ FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC,
+ Loc, Name.getAsIdentifierInfo(),
+ T, TInfo, BitWidth, D->isMutable());
+ ToField->setLexicalDeclContext(LexicalDC);
+ Importer.getImportedDecls()[D] = ToField;
+ LexicalDC->addDecl(ToField);
+ return ToField;
+}
+
Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
// Import the major distinguishing characteristics of a variable.
DeclContext *DC, *LexicalDC;
More information about the cfe-commits
mailing list