[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