[cfe-commits] r96024 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ASTImporter.cpp test/ASTMerge/Inputs/enum1.c test/ASTMerge/Inputs/enum2.c test/ASTMerge/enum.c
Douglas Gregor
dgregor at apple.com
Fri Feb 12 14:17:39 PST 2010
Author: dgregor
Date: Fri Feb 12 16:17:39 2010
New Revision: 96024
URL: http://llvm.org/viewvc/llvm-project?rev=96024&view=rev
Log:
Implement AST importing and merging for enumeration types and
enumerators, along with ImplicitCastExprs to make it work.
Added:
cfe/trunk/test/ASTMerge/Inputs/enum1.c
cfe/trunk/test/ASTMerge/Inputs/enum2.c
cfe/trunk/test/ASTMerge/enum.c
Modified:
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/lib/AST/ASTImporter.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=96024&r1=96023&r2=96024&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Fri Feb 12 16:17:39 2010
@@ -37,7 +37,7 @@
def err_odr_function_type_inconsistent : Error<
"external function %0 declared with incompatible types in different "
"translation units (%1 vs. %2)">;
-def warn_odr_class_type_inconsistent : Warning<
+def warn_odr_tag_type_inconsistent : Warning<
"type %0 has incompatible definitions in different translation units">;
def note_odr_tag_kind_here: Note<
"%0 is a %select{struct|union|class|enum}1 here">;
@@ -51,5 +51,8 @@
def note_odr_missing_base : Note<"no corresponding base class here">;
def note_odr_number_of_bases : Note<
"class has %0 base %plural{1:class|:classes}0">;
+def note_odr_enumerator : Note<"enumerator %0 with value %1 here">;
+def note_odr_missing_enumerator : Note<"no corresponding enumerator here">;
+
def err_unsupported_ast_node: Error<"cannot import unsupported AST node %0">;
}
Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=96024&r1=96023&r2=96024&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Feb 12 16:17:39 2010
@@ -80,14 +80,17 @@
bool ImportDeclParts(NamedDecl *D, DeclContext *&DC,
DeclContext *&LexicalDC, DeclarationName &Name,
SourceLocation &Loc);
- bool ImportDeclParts(DeclaratorDecl *D,
+ 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 *ToEnum);
Decl *VisitDecl(Decl *D);
Decl *VisitTypedefDecl(TypedefDecl *D);
+ Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitRecordDecl(RecordDecl *D);
+ Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitFieldDecl(FieldDecl *D);
Decl *VisitVarDecl(VarDecl *D);
@@ -99,6 +102,7 @@
// Importing expressions
Expr *VisitExpr(Expr *E);
Expr *VisitIntegerLiteral(IntegerLiteral *E);
+ Expr *VisitImplicitCastExpr(ImplicitCastExpr *E);
};
}
@@ -497,7 +501,7 @@
return false;
}
-bool ASTNodeImporter::ImportDeclParts(DeclaratorDecl *D,
+bool ASTNodeImporter::ImportDeclParts(ValueDecl *D,
DeclContext *&DC,
DeclContext *&LexicalDC,
DeclarationName &Name,
@@ -518,7 +522,7 @@
RecordDecl *ToRecord) {
if (FromRecord->isUnion() != ToRecord->isUnion()) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.FromDiag(FromRecord->getLocation(), diag::note_odr_tag_kind_here)
<< FromRecord->getDeclName() << (unsigned)FromRecord->getTagKind();
@@ -529,7 +533,7 @@
if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(ToRecord)) {
if (FromCXX->getNumBases() != ToCXX->getNumBases()) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToRecord->getLocation(), diag::note_odr_number_of_bases)
<< ToCXX->getNumBases();
@@ -553,7 +557,7 @@
if (!Importer.getToContext().typesAreCompatible(FromBaseT,
ToBase->getType())) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToBase->getSourceRange().getBegin(),
diag::note_odr_base)
@@ -569,7 +573,7 @@
// Check virtual vs. non-virtual inheritance mismatch.
if (FromBase->isVirtual() != ToBase->isVirtual()) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToBase->getSourceRange().getBegin(),
diag::note_odr_virtual_base)
@@ -583,7 +587,7 @@
}
} else if (FromCXX->getNumBases() > 0) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
const CXXBaseSpecifier *FromBase = FromCXX->bases_begin();
Importer.FromDiag(FromBase->getSourceRange().getBegin(),
@@ -604,7 +608,7 @@
++FromField, ++ToField) {
if (ToField == ToFieldEnd) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.FromDiag(FromField->getLocation(), diag::note_odr_field)
<< FromField->getDeclName() << FromField->getType();
@@ -618,7 +622,7 @@
if (!Importer.getToContext().typesAreCompatible(FromT, ToField->getType())){
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToField->getLocation(), diag::note_odr_field)
<< ToField->getDeclName() << ToField->getType();
@@ -629,7 +633,7 @@
if (FromField->isBitField() != ToField->isBitField()) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
if (FromField->isBitField()) {
llvm::APSInt Bits;
@@ -674,7 +678,7 @@
if (FromBits != ToBits) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToField->getLocation(), diag::note_odr_bit_field)
<< ToField->getDeclName() << ToField->getType()
@@ -689,7 +693,7 @@
if (ToField != ToFieldEnd) {
Importer.ToDiag(ToRecord->getLocation(),
- diag::warn_odr_class_type_inconsistent)
+ diag::warn_odr_tag_type_inconsistent)
<< Importer.getToContext().getTypeDeclType(ToRecord);
Importer.ToDiag(ToField->getLocation(), diag::note_odr_field)
<< ToField->getDeclName() << ToField->getType();
@@ -700,6 +704,67 @@
return true;
}
+bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) {
+ EnumDecl::enumerator_iterator ToEC = ToEnum->enumerator_begin(),
+ ToEnd = ToEnum->enumerator_end();
+ for (EnumDecl::enumerator_iterator FromEC = FromEnum->enumerator_begin(),
+ FromEnd = FromEnum->enumerator_end();
+ FromEC != FromEnd; ++FromEC, ++ToEC) {
+ if (ToEC == ToEnd) {
+ Importer.ToDiag(ToEnum->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Importer.getToContext().getTypeDeclType(ToEnum);
+ Importer.FromDiag(FromEC->getLocation(), diag::note_odr_enumerator)
+ << FromEC->getDeclName()
+ << FromEC->getInitVal().toString(10);
+ Importer.ToDiag(ToEnum->getLocation(),
+ diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ llvm::APSInt FromVal = FromEC->getInitVal();
+ llvm::APSInt ToVal = ToEC->getInitVal();
+ if (FromVal.getBitWidth() > ToVal.getBitWidth())
+ ToVal.extend(FromVal.getBitWidth());
+ else if (ToVal.getBitWidth() > FromVal.getBitWidth())
+ FromVal.extend(ToVal.getBitWidth());
+ if (FromVal.isSigned() != ToVal.isSigned()) {
+ if (FromVal.isSigned())
+ ToVal.setIsSigned(true);
+ else
+ FromVal.setIsSigned(true);
+ }
+
+ if (FromVal != ToVal ||
+ ToEC->getDeclName() != Importer.Import(FromEC->getDeclName())) {
+ Importer.ToDiag(ToEnum->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Importer.getToContext().getTypeDeclType(ToEnum);
+ Importer.ToDiag(ToEC->getLocation(), diag::note_odr_enumerator)
+ << ToEC->getDeclName()
+ << ToEC->getInitVal().toString(10);
+ Importer.FromDiag(FromEC->getLocation(), diag::note_odr_enumerator)
+ << FromEC->getDeclName()
+ << FromEC->getInitVal().toString(10);
+ return false;
+ }
+ }
+
+ if (ToEC != ToEnd) {
+ Importer.ToDiag(ToEnum->getLocation(),
+ diag::warn_odr_tag_type_inconsistent)
+ << Importer.getToContext().getTypeDeclType(ToEnum);
+ Importer.ToDiag(ToEC->getLocation(), diag::note_odr_enumerator)
+ << ToEC->getDeclName()
+ << ToEC->getInitVal().toString(10);
+ Importer.FromDiag(FromEnum->getLocation(),
+ diag::note_odr_missing_enumerator);
+ return false;
+ }
+
+ return true;
+}
+
Decl *ASTNodeImporter::VisitDecl(Decl *D) {
Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node)
<< D->getDeclKindName();
@@ -761,6 +826,94 @@
return ToTypedef;
}
+Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) {
+ // Import the major distinguishing characteristics of this enum.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc))
+ return 0;
+
+ // Figure out what enum 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 an enum 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 (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) {
+ if (IsStructuralMatch(D, FoundEnum)) {
+ // The enum types structurally match.
+ Importer.getImportedDecls()[D] = FoundEnum;
+ return FoundEnum;
+ }
+ }
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ }
+ }
+
+ // Create the enum declaration.
+ EnumDecl *ToEnum = EnumDecl::Create(Importer.getToContext(), DC, Loc,
+ Name.getAsIdentifierInfo(),
+ Importer.Import(D->getTagKeywordLoc()),
+ 0);
+ ToEnum->setLexicalDeclContext(LexicalDC);
+ Importer.getImportedDecls()[D] = ToEnum;
+ LexicalDC->addDecl(ToEnum);
+
+ // Import the integer type.
+ QualType ToIntegerType = Importer.Import(D->getIntegerType());
+ if (ToIntegerType.isNull())
+ return 0;
+ ToEnum->setIntegerType(ToIntegerType);
+
+ // Import the definition
+ if (D->isDefinition()) {
+ QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D));
+ if (T.isNull())
+ return 0;
+
+ QualType ToPromotionType = Importer.Import(D->getPromotionType());
+ if (ToPromotionType.isNull())
+ return 0;
+
+ ToEnum->startDefinition();
+ for (DeclContext::decl_iterator FromMem = D->decls_begin(),
+ FromMemEnd = D->decls_end();
+ FromMem != FromMemEnd;
+ ++FromMem)
+ Importer.Import(*FromMem);
+
+ ToEnum->completeDefinition(T, ToPromotionType);
+ }
+
+ return ToEnum;
+}
+
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
@@ -891,6 +1044,51 @@
return ToRecord;
}
+Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) {
+ // Import the major distinguishing characteristics of this enumerator.
+ DeclContext *DC, *LexicalDC;
+ DeclarationName Name;
+ SourceLocation Loc;
+ QualType T;
+ if (ImportDeclParts(D, DC, LexicalDC, Name, Loc, T))
+ return 0;
+
+ // Determine whether there are any other declarations with the same name and
+ // in the same context.
+ if (!LexicalDC->isFunctionOrMethod()) {
+ llvm::SmallVector<NamedDecl *, 4> ConflictingDecls;
+ unsigned IDNS = Decl::IDNS_Ordinary;
+ for (DeclContext::lookup_result Lookup = DC->lookup(Name);
+ Lookup.first != Lookup.second;
+ ++Lookup.first) {
+ if (!(*Lookup.first)->isInIdentifierNamespace(IDNS))
+ continue;
+
+ ConflictingDecls.push_back(*Lookup.first);
+ }
+
+ if (!ConflictingDecls.empty()) {
+ Name = Importer.HandleNameConflict(Name, DC, IDNS,
+ ConflictingDecls.data(),
+ ConflictingDecls.size());
+ if (!Name)
+ return 0;
+ }
+ }
+
+ Expr *Init = Importer.Import(D->getInitExpr());
+ if (D->getInitExpr() && !Init)
+ return 0;
+
+ EnumConstantDecl *ToEnumerator
+ = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc,
+ Name.getAsIdentifierInfo(), T,
+ Init, D->getInitVal());
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.getImportedDecls()[D] = ToEnumerator;
+ LexicalDC->addDecl(ToEnumerator);
+ return ToEnumerator;
+}
Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Import the major distinguishing characteristics of this function.
@@ -963,25 +1161,25 @@
// Create the imported function.
TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo());
- FunctionDecl *ToFunction
+ FunctionDecl *ToEnumerator
= FunctionDecl::Create(Importer.getToContext(), DC, Loc,
Name, T, TInfo, D->getStorageClass(),
D->isInlineSpecified(),
D->hasWrittenPrototype());
- ToFunction->setLexicalDeclContext(LexicalDC);
- Importer.getImportedDecls()[D] = ToFunction;
- LexicalDC->addDecl(ToFunction);
+ ToEnumerator->setLexicalDeclContext(LexicalDC);
+ Importer.getImportedDecls()[D] = ToEnumerator;
+ LexicalDC->addDecl(ToEnumerator);
// Set the parameters.
for (unsigned I = 0, N = Parameters.size(); I != N; ++I) {
- Parameters[I]->setOwningFunction(ToFunction);
- ToFunction->addDecl(Parameters[I]);
+ Parameters[I]->setOwningFunction(ToEnumerator);
+ ToEnumerator->addDecl(Parameters[I]);
}
- ToFunction->setParams(Parameters.data(), Parameters.size());
+ ToEnumerator->setParams(Parameters.data(), Parameters.size());
// FIXME: Other bits to merge?
- return ToFunction;
+ return ToEnumerator;
}
Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
@@ -1170,6 +1368,20 @@
IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation()));
}
+Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) {
+ QualType T = Importer.Import(E->getType());
+ if (T.isNull())
+ return 0;
+
+ Expr *SubExpr = Importer.Import(E->getSubExpr());
+ if (!SubExpr)
+ return 0;
+
+ return new (Importer.getToContext()) ImplicitCastExpr(T, E->getCastKind(),
+ SubExpr,
+ E->isLvalueCast());
+}
+
ASTImporter::ASTImporter(Diagnostic &Diags,
ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager)
Added: cfe/trunk/test/ASTMerge/Inputs/enum1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/enum1.c?rev=96024&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/enum1.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/enum1.c Fri Feb 12 16:17:39 2010
@@ -0,0 +1,34 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 3,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator2 = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2,
+ E4Enumerator3
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3
+} x5;
Added: cfe/trunk/test/ASTMerge/Inputs/enum2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/enum2.c?rev=96024&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/enum2.c (added)
+++ cfe/trunk/test/ASTMerge/Inputs/enum2.c Fri Feb 12 16:17:39 2010
@@ -0,0 +1,35 @@
+// Matching
+enum E1 {
+ E1Enumerator1,
+ E1Enumerator2 = 3,
+ E1Enumerator3
+} x1;
+
+// Value mismatch
+enum E2 {
+ E2Enumerator1,
+ E2Enumerator2 = 4,
+ E2Enumerator3
+} x2;
+
+// Name mismatch
+enum E3 {
+ E3Enumerator1,
+ E3Enumerator = 3,
+ E3Enumerator3
+} x3;
+
+// Missing enumerator
+enum E4 {
+ E4Enumerator1,
+ E4Enumerator2
+} x4;
+
+// Extra enumerator
+enum E5 {
+ E5Enumerator1,
+ E5Enumerator2,
+ E5Enumerator3,
+ E5Enumerator4
+} x5;
+
Added: cfe/trunk/test/ASTMerge/enum.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/enum.c?rev=96024&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/enum.c (added)
+++ cfe/trunk/test/ASTMerge/enum.c Fri Feb 12 16:17:39 2010
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/enum1.c
+// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/enum2.c
+// RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
+
+// CHECK: enum1.c:9:6: warning: type 'enum E2' has incompatible definitions in different translation units
+// CHECK: enum1.c:11:3: note: enumerator 'E2Enumerator2' with value 3 here
+// CHECK: enum2.c:11:3: note: enumerator 'E2Enumerator2' with value 4 here
+// CHECK: enum2.c:13:3: error: external variable 'x2' declared with incompatible types in different translation units ('enum E2' vs. 'enum E2')
+// CHECK: enum1.c:13:3: note: declared here with type 'enum E2'
+// CHECK: enum1.c:16:6: warning: type 'enum E3' has incompatible definitions in different translation units
+// CHECK: enum1.c:18:3: note: enumerator 'E3Enumerator2' with value 3 here
+// CHECK: enum2.c:18:3: note: enumerator 'E3Enumerator' with value 3 here
+// CHECK: enum2.c:20:3: error: external variable 'x3' declared with incompatible types in different translation units ('enum E3' vs. 'enum E3')
+// CHECK: enum1.c:20:3: note: declared here with type 'enum E3'
+// CHECK: enum1.c:23:6: warning: type 'enum E4' has incompatible definitions in different translation units
+// CHECK: enum1.c:26:3: note: enumerator 'E4Enumerator3' with value 2 here
+// CHECK: enum2.c:23:6: note: no corresponding enumerator here
+// CHECK: enum2.c:26:3: error: external variable 'x4' declared with incompatible types in different translation units ('enum E4' vs. 'enum E4')
+// CHECK: enum1.c:27:3: note: declared here with type 'enum E4'
+// CHECK: enum1.c:30:6: warning: type 'enum E5' has incompatible definitions in different translation units
+// CHECK: enum2.c:33:3: note: enumerator 'E5Enumerator4' with value 3 here
+// CHECK: enum1.c:30:6: note: no corresponding enumerator here
+// CHECK: enum2.c:34:3: error: external variable 'x5' declared with incompatible types in different translation units ('enum E5' vs. 'enum E5')
+// CHECK: enum1.c:34:3: note: declared here with type 'enum E5'
+// CHECK: 20 diagnostics generated
More information about the cfe-commits
mailing list