[cfe-commits] r96298 - in /cfe/trunk: include/clang/AST/ASTImporter.h lib/AST/ASTImporter.cpp test/ASTMerge/Inputs/enum1.c test/ASTMerge/Inputs/enum2.c test/ASTMerge/Inputs/function1.c test/ASTMerge/Inputs/function2.c test/ASTMerge/Inputs/struct1.c test/ASTMerge/Inputs/struct2.c test/ASTMerge/struct.c
Douglas Gregor
dgregor at apple.com
Mon Feb 15 15:54:18 PST 2010
Author: dgregor
Date: Mon Feb 15 17:54:17 2010
New Revision: 96298
URL: http://llvm.org/viewvc/llvm-project?rev=96298&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/ASTImporter.h
cfe/trunk/lib/AST/ASTImporter.cpp
cfe/trunk/test/ASTMerge/Inputs/enum1.c
cfe/trunk/test/ASTMerge/Inputs/enum2.c
cfe/trunk/test/ASTMerge/Inputs/function1.c
cfe/trunk/test/ASTMerge/Inputs/function2.c
cfe/trunk/test/ASTMerge/Inputs/struct1.c
cfe/trunk/test/ASTMerge/Inputs/struct2.c
cfe/trunk/test/ASTMerge/struct.c
Modified: cfe/trunk/include/clang/AST/ASTImporter.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTImporter.h?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTImporter.h (original)
+++ cfe/trunk/include/clang/AST/ASTImporter.h Mon Feb 15 17:54:17 2010
@@ -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 @@
/// \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 @@
/// 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 @@
/// \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);
};
}
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Mon Feb 15 17:54:17 2010
@@ -81,10 +81,6 @@
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 @@
/// 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 @@
if (T1.getQualifiers() != T2.getQualifiers())
return false;
- if (T1->getTypeClass() != T2->getTypeClass())
- return false;
+ Type::TypeClass TC = T1->getTypeClass();
+
+ 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 (T1->getTypeClass()) {
- case Type::Builtin:
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
+ // 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 @@
ToTypedef->setLexicalDeclContext(LexicalDC);
Importer.Imported(D, ToTypedef);
LexicalDC->addDecl(ToTypedef);
+
return ToTypedef;
}
@@ -1648,10 +1654,13 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
}
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 @@
}
}
+ // 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 @@
// 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 @@
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);
+}
Modified: cfe/trunk/test/ASTMerge/Inputs/enum1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/enum1.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/enum1.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/enum1.c Mon Feb 15 17:54:17 2010
@@ -32,3 +32,11 @@
E5Enumerator2,
E5Enumerator3
} x5;
+
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
Modified: cfe/trunk/test/ASTMerge/Inputs/enum2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/enum2.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/enum2.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/enum2.c Mon Feb 15 17:54:17 2010
@@ -33,3 +33,10 @@
E5Enumerator4
} x5;
+// Matching, with typedef
+typedef enum {
+ E6Enumerator1,
+ E6Enumerator2
+} E6;
+
+E6 x6;
Modified: cfe/trunk/test/ASTMerge/Inputs/function1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/function1.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/function1.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/function1.c Mon Feb 15 17:54:17 2010
@@ -3,4 +3,4 @@
void f2();
void f3(void);
void f4(int, int);
-
+int f5(int) __attribute__((const));
Modified: cfe/trunk/test/ASTMerge/Inputs/function2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/function2.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/function2.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/function2.c Mon Feb 15 17:54:17 2010
@@ -4,3 +4,4 @@
void f2(int, int);
void f3(int);
static void f4(float, float);
+int f5(int) __attribute__((const));
Modified: cfe/trunk/test/ASTMerge/Inputs/struct1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/struct1.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/struct1.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/struct1.c Mon Feb 15 17:54:17 2010
@@ -55,3 +55,9 @@
int value;
struct DeeperError { int i; int f; } *Deeper;
} xDeep;
+
+// Matches
+struct {
+ Int i;
+ float f;
+} x11;
Modified: cfe/trunk/test/ASTMerge/Inputs/struct2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/struct2.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/struct2.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/struct2.c Mon Feb 15 17:54:17 2010
@@ -52,3 +52,9 @@
int value;
struct DeeperError { int i; float f; } *Deeper;
} xDeep;
+
+// Matches
+struct {
+ int i;
+ float f;
+} x11;
Modified: cfe/trunk/test/ASTMerge/struct.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/struct.c?rev=96298&r1=96297&r2=96298&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/struct.c (original)
+++ cfe/trunk/test/ASTMerge/struct.c Mon Feb 15 17:54:17 2010
@@ -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
More information about the cfe-commits
mailing list