forked from OSchip/llvm-project
Cope with anonymous tags defined within declarators by structurally
comparing their types under the assumption that they are equivalent, rather than importing the types and then checking for compatibility. A few minor tweaks here: - Teach structural matching to handle compatibility between function types with prototypes and those without prototypes. - Teach structural matching that an incomplete record decl is the same as any other record decl with the same name. - Keep track of pairs of declarations that we have already checked (but failed to find as structurally matching), so we don't emit diagnostics repeatedly. - When importing a typedef of an anonymous tag, be sure to link the imported tag type to its typedef. With these changes, we survive a repeated import of <stdlib.h> and <stdio.h>. Alas, the ASTNodeImporter is getting a little grotty. llvm-svn: 96298
This commit is contained in:
parent
a945c64b5a
commit
b4964f7705
|
@ -18,6 +18,8 @@
|
|||
#include "clang/AST/DeclarationName.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace clang {
|
||||
class ASTContext;
|
||||
|
@ -34,6 +36,10 @@ namespace clang {
|
|||
/// \brief Imports selected nodes from one AST context into another context,
|
||||
/// merging AST nodes where appropriate.
|
||||
class ASTImporter {
|
||||
public:
|
||||
typedef llvm::DenseSet<std::pair<Decl *, Decl *> > NonEquivalentDeclSet;
|
||||
|
||||
private:
|
||||
/// \brief The contexts we're importing to and from.
|
||||
ASTContext &ToContext, &FromContext;
|
||||
|
||||
|
@ -59,6 +65,14 @@ namespace clang {
|
|||
/// manager to the corresponding FileIDs in the "to" source manager.
|
||||
llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
|
||||
|
||||
/// \brief Imported, anonymous tag declarations that are missing their
|
||||
/// corresponding typedefs.
|
||||
llvm::SmallVector<TagDecl *, 4> AnonTagsWithPendingTypedefs;
|
||||
|
||||
/// \brief Declaration (from, to) pairs that are known not to be equivalent
|
||||
/// (which we have already complained about).
|
||||
NonEquivalentDeclSet NonEquivalentDecls;
|
||||
|
||||
public:
|
||||
ASTImporter(Diagnostic &Diags,
|
||||
ASTContext &ToContext, FileManager &ToFileManager,
|
||||
|
@ -202,11 +216,18 @@ namespace clang {
|
|||
/// \brief Report a diagnostic in the "from" context.
|
||||
DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID);
|
||||
|
||||
/// \brief Return the set of declarations that we know are not equivalent.
|
||||
NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; }
|
||||
|
||||
/// \brief Note that we have imported the "from" declaration by mapping it
|
||||
/// to the (potentially-newly-created) "to" declaration.
|
||||
///
|
||||
/// \returns \p To
|
||||
Decl *Imported(Decl *From, Decl *To);
|
||||
|
||||
/// \brief Determine whether the given types are structurally
|
||||
/// equivalent.
|
||||
bool IsStructurallyEquivalent(QualType From, QualType To);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -81,10 +81,6 @@ namespace {
|
|||
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
|
||||
DeclContext *&LexicalDC, DeclarationName &Name,
|
||||
SourceLocation &Loc);
|
||||
bool ImportDeclParts(ValueDecl *D,
|
||||
DeclContext *&DC, DeclContext *&LexicalDC,
|
||||
DeclarationName &Name, SourceLocation &Loc,
|
||||
QualType &T);
|
||||
bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord);
|
||||
bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord);
|
||||
Decl *VisitDecl(Decl *D);
|
||||
|
@ -128,14 +124,20 @@ namespace {
|
|||
/// with a declaration in the second context still needs to be verified.
|
||||
std::deque<Decl *> DeclsToCheck;
|
||||
|
||||
/// \brief Declaration (from, to) pairs that are known not to be equivalent
|
||||
/// (which we have already complained about).
|
||||
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls;
|
||||
|
||||
/// \brief Whether we're being strict about the spelling of types when
|
||||
/// unifying two types.
|
||||
bool StrictTypeSpelling;
|
||||
|
||||
StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2,
|
||||
Diagnostic &Diags,
|
||||
llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls,
|
||||
bool StrictTypeSpelling = false)
|
||||
: C1(C1), C2(C2), Diags(Diags), StrictTypeSpelling(StrictTypeSpelling) { }
|
||||
: C1(C1), C2(C2), Diags(Diags), NonEquivalentDecls(NonEquivalentDecls),
|
||||
StrictTypeSpelling(StrictTypeSpelling) { }
|
||||
|
||||
/// \brief Determine whether the two declarations are structurally
|
||||
/// equivalent.
|
||||
|
@ -273,11 +275,23 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
if (T1.getQualifiers() != T2.getQualifiers())
|
||||
return false;
|
||||
|
||||
if (T1->getTypeClass() != T2->getTypeClass())
|
||||
return false;
|
||||
Type::TypeClass TC = T1->getTypeClass();
|
||||
|
||||
switch (T1->getTypeClass()) {
|
||||
case Type::Builtin:
|
||||
if (T1->getTypeClass() != T2->getTypeClass()) {
|
||||
// Compare function types with prototypes vs. without prototypes as if
|
||||
// both did not have prototypes.
|
||||
if (T1->getTypeClass() == Type::FunctionProto &&
|
||||
T2->getTypeClass() == Type::FunctionNoProto)
|
||||
TC = Type::FunctionNoProto;
|
||||
else if (T1->getTypeClass() == Type::FunctionNoProto &&
|
||||
T2->getTypeClass() == Type::FunctionProto)
|
||||
TC = Type::FunctionNoProto;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (TC) {
|
||||
case Type::Builtin:
|
||||
// FIXME: Deal with Char_S/Char_U.
|
||||
if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind())
|
||||
return false;
|
||||
|
@ -641,6 +655,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
return false;
|
||||
}
|
||||
|
||||
// Compare the definitions of these two records. If either or both are
|
||||
// incomplete, we assume that they are equivalent.
|
||||
D1 = D1->getDefinition();
|
||||
D2 = D2->getDefinition();
|
||||
if (!D1 || !D2)
|
||||
return true;
|
||||
|
||||
if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) {
|
||||
if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) {
|
||||
if (D1CXX->getNumBases() != D2CXX->getNumBases()) {
|
||||
|
@ -834,6 +855,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
|||
Decl *D1, Decl *D2) {
|
||||
// FIXME: Check for known structural equivalences via a callback of some sort.
|
||||
|
||||
// Check whether we already know that these two declarations are not
|
||||
// structurally equivalent.
|
||||
if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(),
|
||||
D2->getCanonicalDecl())))
|
||||
return false;
|
||||
|
||||
// Determine whether we've already produced a tentative equivalence for D1.
|
||||
Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()];
|
||||
if (EquivToD1)
|
||||
|
@ -870,6 +897,8 @@ bool StructuralEquivalenceContext::Finish() {
|
|||
Decl *D2 = TentativeEquivalences[D1];
|
||||
assert(D2 && "Unrecorded tentative equivalence?");
|
||||
|
||||
bool Equivalent = true;
|
||||
|
||||
// FIXME: Switch on all declaration kinds. For now, we're just going to
|
||||
// check the obvious ones.
|
||||
if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) {
|
||||
|
@ -881,20 +910,14 @@ bool StructuralEquivalenceContext::Finish() {
|
|||
IdentifierInfo *Name2 = Record2->getIdentifier();
|
||||
if (!Name2 && Record2->getTypedefForAnonDecl())
|
||||
Name2 = Record2->getTypedefForAnonDecl()->getIdentifier();
|
||||
if (!::IsStructurallyEquivalent(Name1, Name2))
|
||||
return true;
|
||||
|
||||
if (!::IsStructurallyEquivalent(*this, Record1, Record2))
|
||||
return true;
|
||||
if (!::IsStructurallyEquivalent(Name1, Name2) ||
|
||||
!::IsStructurallyEquivalent(*this, Record1, Record2))
|
||||
Equivalent = false;
|
||||
} else {
|
||||
// Record/non-record mismatch.
|
||||
return true;
|
||||
Equivalent = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
|
||||
} else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) {
|
||||
if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) {
|
||||
// Check for equivalent enum names.
|
||||
IdentifierInfo *Name1 = Enum1->getIdentifier();
|
||||
|
@ -903,37 +926,34 @@ bool StructuralEquivalenceContext::Finish() {
|
|||
IdentifierInfo *Name2 = Enum2->getIdentifier();
|
||||
if (!Name2 && Enum2->getTypedefForAnonDecl())
|
||||
Name2 = Enum2->getTypedefForAnonDecl()->getIdentifier();
|
||||
if (!::IsStructurallyEquivalent(Name1, Name2))
|
||||
return true;
|
||||
|
||||
if (!::IsStructurallyEquivalent(*this, Enum1, Enum2))
|
||||
return true;
|
||||
if (!::IsStructurallyEquivalent(Name1, Name2) ||
|
||||
!::IsStructurallyEquivalent(*this, Enum1, Enum2))
|
||||
Equivalent = false;
|
||||
} else {
|
||||
// Enum/non-enum mismatch
|
||||
return true;
|
||||
Equivalent = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
|
||||
} else if (TypedefDecl *Typedef1 = dyn_cast<TypedefDecl>(D1)) {
|
||||
if (TypedefDecl *Typedef2 = dyn_cast<TypedefDecl>(D2)) {
|
||||
if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(),
|
||||
Typedef2->getIdentifier()))
|
||||
return true;
|
||||
|
||||
if (!::IsStructurallyEquivalent(*this,
|
||||
Typedef2->getIdentifier()) ||
|
||||
!::IsStructurallyEquivalent(*this,
|
||||
Typedef1->getUnderlyingType(),
|
||||
Typedef2->getUnderlyingType()))
|
||||
return true;
|
||||
Equivalent = false;
|
||||
} else {
|
||||
// Typedef/non-typedef mismatch.
|
||||
return true;
|
||||
Equivalent = false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!Equivalent) {
|
||||
// Note that these two declarations are not equivalent (and we already
|
||||
// know about it).
|
||||
NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(),
|
||||
D2->getCanonicalDecl()));
|
||||
return true;
|
||||
}
|
||||
// FIXME: Check other declaration kinds!
|
||||
}
|
||||
|
||||
|
@ -1335,35 +1355,20 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool ASTNodeImporter::ImportDeclParts(ValueDecl *D,
|
||||
DeclContext *&DC,
|
||||
DeclContext *&LexicalDC,
|
||||
DeclarationName &Name,
|
||||
SourceLocation &Loc,
|
||||
QualType &T) {
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return true;
|
||||
|
||||
// Import the type of this declaration.
|
||||
T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
|
||||
RecordDecl *ToRecord) {
|
||||
StructuralEquivalenceContext SEC(Importer.getFromContext(),
|
||||
Importer.getToContext(),
|
||||
Importer.getDiags());
|
||||
Importer.getDiags(),
|
||||
Importer.getNonEquivalentDecls());
|
||||
return SEC.IsStructurallyEquivalent(FromRecord, ToRecord);
|
||||
}
|
||||
|
||||
bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
|
||||
StructuralEquivalenceContext SEC(Importer.getFromContext(),
|
||||
Importer.getToContext(),
|
||||
Importer.getDiags());
|
||||
Importer.getDiags(),
|
||||
Importer.getNonEquivalentDecls());
|
||||
return SEC.IsStructurallyEquivalent(FromEnum, ToEnum);
|
||||
}
|
||||
|
||||
|
@ -1381,11 +1386,6 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
|
|||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return 0;
|
||||
|
||||
// Import the underlying type of this typedef;
|
||||
QualType T = Importer.Import(D->getUnderlyingType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// If this typedef is not in block scope, determine whether we've
|
||||
// seen a typedef with the same name (that we can merge with) or any
|
||||
// other entity by that name (which name lookup could conflict with).
|
||||
|
@ -1398,8 +1398,8 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
|
|||
if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
|
||||
continue;
|
||||
if (TypedefDecl *FoundTypedef = dyn_cast<TypedefDecl>(*Lookup.first)) {
|
||||
if (Importer.getToContext().typesAreCompatible(T,
|
||||
FoundTypedef->getUnderlyingType()))
|
||||
if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(),
|
||||
FoundTypedef->getUnderlyingType()))
|
||||
return Importer.Imported(D, FoundTypedef);
|
||||
}
|
||||
|
||||
|
@ -1415,6 +1415,11 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
// Import the underlying type of this typedef;
|
||||
QualType T = Importer.Import(D->getUnderlyingType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// Create the new typedef node.
|
||||
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
|
||||
TypedefDecl *ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC,
|
||||
|
@ -1423,6 +1428,7 @@ Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) {
|
|||
ToTypedef->setLexicalDeclContext(LexicalDC);
|
||||
Importer.Imported(D, ToTypedef);
|
||||
LexicalDC->addDecl(ToTypedef);
|
||||
|
||||
return ToTypedef;
|
||||
}
|
||||
|
||||
|
@ -1648,10 +1654,13 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
|
|||
DeclContext *DC, *LexicalDC;
|
||||
DeclarationName Name;
|
||||
SourceLocation Loc;
|
||||
QualType T;
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return 0;
|
||||
|
||||
|
||||
QualType T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// Determine whether there are any other declarations with the same name and
|
||||
// in the same context.
|
||||
if (!LexicalDC->isFunctionOrMethod()) {
|
||||
|
@ -1693,9 +1702,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
// Import the major distinguishing characteristics of this function.
|
||||
DeclContext *DC, *LexicalDC;
|
||||
DeclarationName Name;
|
||||
QualType T;
|
||||
SourceLocation Loc;
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return 0;
|
||||
|
||||
// Try to find a function in our own ("to") context with the same name, same
|
||||
|
@ -1712,8 +1720,8 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) {
|
||||
if (isExternalLinkage(FoundFunction->getLinkage()) &&
|
||||
isExternalLinkage(D->getLinkage())) {
|
||||
if (Importer.getToContext().typesAreCompatible(T,
|
||||
FoundFunction->getType())) {
|
||||
if (Importer.IsStructurallyEquivalent(D->getType(),
|
||||
FoundFunction->getType())) {
|
||||
// FIXME: Actually try to merge the body and other attributes.
|
||||
return Importer.Imported(D, FoundFunction);
|
||||
}
|
||||
|
@ -1727,7 +1735,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
|
||||
// Complain about inconsistent function types.
|
||||
Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent)
|
||||
<< Name << T << FoundFunction->getType();
|
||||
<< Name << D->getType() << FoundFunction->getType();
|
||||
Importer.ToDiag(FoundFunction->getLocation(),
|
||||
diag::note_odr_value_here)
|
||||
<< FoundFunction->getType();
|
||||
|
@ -1745,6 +1753,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Import the type.
|
||||
QualType T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// Import the function parameters.
|
||||
llvm::SmallVector<ParmVarDecl *, 8> Parameters;
|
||||
|
@ -1784,9 +1797,13 @@ 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))
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return 0;
|
||||
|
||||
// Import the type.
|
||||
QualType T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
|
||||
|
@ -1807,9 +1824,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *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))
|
||||
if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
|
||||
return 0;
|
||||
|
||||
// Try to find a variable in our own ("to") context with the same name and
|
||||
|
@ -1828,8 +1844,8 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
|
|||
// 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())) {
|
||||
if (Importer.IsStructurallyEquivalent(D->getType(),
|
||||
FoundVar->getType())) {
|
||||
MergeWithVar = FoundVar;
|
||||
break;
|
||||
}
|
||||
|
@ -1837,10 +1853,15 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
|
|||
const ArrayType *FoundArray
|
||||
= Importer.getToContext().getAsArrayType(FoundVar->getType());
|
||||
const ArrayType *TArray
|
||||
= Importer.getToContext().getAsArrayType(T);
|
||||
= Importer.getToContext().getAsArrayType(D->getType());
|
||||
if (FoundArray && TArray) {
|
||||
if (isa<IncompleteArrayType>(FoundArray) &&
|
||||
isa<ConstantArrayType>(TArray)) {
|
||||
// Import the type.
|
||||
QualType T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
FoundVar->setType(T);
|
||||
MergeWithVar = FoundVar;
|
||||
break;
|
||||
|
@ -1852,7 +1873,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
|
|||
}
|
||||
|
||||
Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent)
|
||||
<< Name << T << FoundVar->getType();
|
||||
<< Name << D->getType() << FoundVar->getType();
|
||||
Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here)
|
||||
<< FoundVar->getType();
|
||||
}
|
||||
|
@ -1890,6 +1911,11 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
// Import the type.
|
||||
QualType T = Importer.Import(D->getType());
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
// Create the imported variable.
|
||||
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
|
||||
VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, Loc,
|
||||
|
@ -2045,6 +2071,29 @@ Decl *ASTImporter::Import(Decl *FromD) {
|
|||
|
||||
// Record the imported declaration.
|
||||
ImportedDecls[FromD] = ToD;
|
||||
|
||||
if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) {
|
||||
// Keep track of anonymous tags that have an associated typedef.
|
||||
if (FromTag->getTypedefForAnonDecl())
|
||||
AnonTagsWithPendingTypedefs.push_back(FromTag);
|
||||
} else if (TypedefDecl *FromTypedef = dyn_cast<TypedefDecl>(FromD)) {
|
||||
// When we've finished transforming a typedef, see whether it was the
|
||||
// typedef for an anonymous tag.
|
||||
for (llvm::SmallVector<TagDecl *, 4>::iterator
|
||||
FromTag = AnonTagsWithPendingTypedefs.begin(),
|
||||
FromTagEnd = AnonTagsWithPendingTypedefs.end();
|
||||
FromTag != FromTagEnd; ++FromTag) {
|
||||
if ((*FromTag)->getTypedefForAnonDecl() == FromTypedef) {
|
||||
if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) {
|
||||
// We found the typedef for an anonymous tag; link them.
|
||||
ToTag->setTypedefForAnonDecl(cast<TypedefDecl>(ToD));
|
||||
AnonTagsWithPendingTypedefs.erase(FromTag);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ToD;
|
||||
}
|
||||
|
||||
|
@ -2236,3 +2285,14 @@ Decl *ASTImporter::Imported(Decl *From, Decl *To) {
|
|||
ImportedDecls[From] = To;
|
||||
return To;
|
||||
}
|
||||
|
||||
bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) {
|
||||
llvm::DenseMap<Type *, Type *>::iterator Pos
|
||||
= ImportedTypes.find(From.getTypePtr());
|
||||
if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To))
|
||||
return true;
|
||||
|
||||
StructuralEquivalenceContext SEC(FromContext, ToContext, Diags,
|
||||
NonEquivalentDecls);
|
||||
return SEC.IsStructurallyEquivalent(From, To);
|
||||
}
|
||||
|
|
|
@ -32,3 +32,11 @@ enum E5 {
|
|||
E5Enumerator2,
|
||||
E5Enumerator3
|
||||
} x5;
|
||||
|
||||
// Matching, with typedef
|
||||
typedef enum {
|
||||
E6Enumerator1,
|
||||
E6Enumerator2
|
||||
} E6;
|
||||
|
||||
E6 x6;
|
||||
|
|
|
@ -33,3 +33,10 @@ enum E5 {
|
|||
E5Enumerator4
|
||||
} x5;
|
||||
|
||||
// Matching, with typedef
|
||||
typedef enum {
|
||||
E6Enumerator1,
|
||||
E6Enumerator2
|
||||
} E6;
|
||||
|
||||
E6 x6;
|
||||
|
|
|
@ -3,4 +3,4 @@ void f1(int, float);
|
|||
void f2();
|
||||
void f3(void);
|
||||
void f4(int, int);
|
||||
|
||||
int f5(int) __attribute__((const));
|
||||
|
|
|
@ -4,3 +4,4 @@ void f1(Int, double);
|
|||
void f2(int, int);
|
||||
void f3(int);
|
||||
static void f4(float, float);
|
||||
int f5(int) __attribute__((const));
|
||||
|
|
|
@ -55,3 +55,9 @@ struct DeepError {
|
|||
int value;
|
||||
struct DeeperError { int i; int f; } *Deeper;
|
||||
} xDeep;
|
||||
|
||||
// Matches
|
||||
struct {
|
||||
Int i;
|
||||
float f;
|
||||
} x11;
|
||||
|
|
|
@ -52,3 +52,9 @@ struct DeepError {
|
|||
int value;
|
||||
struct DeeperError { int i; float f; } *Deeper;
|
||||
} xDeep;
|
||||
|
||||
// Matches
|
||||
struct {
|
||||
int i;
|
||||
float f;
|
||||
} x11;
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
// CHECK: struct1.c:56:10: warning: type 'struct DeeperError' has incompatible definitions in different translation units
|
||||
// CHECK: struct1.c:56:35: note: field 'f' has type 'int' here
|
||||
// CHECK: struct2.c:53:37: note: field 'f' has type 'float' here
|
||||
// CHECK: struct1.c:54:8: warning: type 'struct DeepError' has incompatible definitions in different translation units
|
||||
// CHECK: struct1.c:56:41: note: field 'Deeper' has type 'struct DeeperError *' here
|
||||
// CHECK: struct2.c:53:43: note: field 'Deeper' has type 'struct DeeperError *' here
|
||||
// CHECK: struct2.c:54:3: error: external variable 'xDeep' declared with incompatible types in different translation units ('struct DeepError' vs. 'struct DeepError')
|
||||
// CHECK: struct1.c:57:3: note: declared here with type 'struct DeepError'
|
||||
// CHECK: 37 diagnostics
|
||||
|
|
Loading…
Reference in New Issue