[cfe-commits] r95900 - in /cfe/trunk: include/clang/AST/ASTImporter.h include/clang/Basic/DiagnosticASTKinds.td lib/AST/ASTImporter.cpp lib/Frontend/ASTMerge.cpp test/ASTMerge/Inputs/struct1.c test/ASTMerge/Inputs/struct2.c test/ASTMerge/struct.c

Douglas Gregor dgregor at apple.com
Thu Feb 11 11:21:55 PST 2010


Author: dgregor
Date: Thu Feb 11 13:21:55 2010
New Revision: 95900

URL: http://llvm.org/viewvc/llvm-project?rev=95900&view=rev
Log:
When AST merging for record declarations fails, warn about the
incompatibility and show where the structural differences are. For
example:

struct1.c:36:8: warning: type 'struct S7' has incompatible definitions
in different translation units
struct S7 { int i : 8; unsigned j : 8; } x7;
       ^
struct1.c:36:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
struct S7 { int i : 8; unsigned j : 8; } x7;
                                ^
struct2.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 16 here
struct S7 { int i : 8; unsigned j : 16; } x7;
                                ^

There are a few changes to make this work:
  - ASTImporter now has only a single Diagnostic object, not multiple
  diagnostic objects. Otherwise, having a warning/error printed via
  one Diagnostic and its note printed on the other Diagnostic could
  cause the note to be suppressed.
  - Implemented import functionality for IntegerLiteral (along with
  general support for statements and expressions)


Modified:
    cfe/trunk/include/clang/AST/ASTImporter.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/Frontend/ASTMerge.cpp
    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=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTImporter.h (original)
+++ cfe/trunk/include/clang/AST/ASTImporter.h Thu Feb 11 13:21:55 2010
@@ -40,9 +40,8 @@
     /// \brief The file managers we're importing to and from.
     FileManager &ToFileManager, &FromFileManager;
     
-    /// \brief The diagnostics object that we should use to emit diagnostics
-    /// within the context we're importing to and from.
-    Diagnostic &ToDiags, &FromDiags;
+    /// \brief The diagnostics object that we should use to emit diagnostics.
+    Diagnostic &Diags;
     
     /// \brief Mapping from the already-imported types in the "from" context
     /// to the corresponding types in the "to" context.
@@ -51,16 +50,19 @@
     /// \brief Mapping from the already-imported declarations in the "from"
     /// context to the corresponding declarations in the "to" context.
     llvm::DenseMap<Decl *, Decl *> ImportedDecls;
-    
+
+    /// \brief Mapping from the already-imported statements in the "from"
+    /// context to the corresponding statements in the "to" context.
+    llvm::DenseMap<Stmt *, Stmt *> ImportedStmts;
+
     /// \brief Mapping from the already-imported FileIDs in the "from" source
     /// manager to the corresponding FileIDs in the "to" source manager.
     llvm::DenseMap<unsigned, FileID> ImportedFileIDs;
     
   public:
-    ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
-                Diagnostic &ToDiags,
-                ASTContext &FromContext, FileManager &FromFileManager,
-                Diagnostic &FromDiags);
+    ASTImporter(Diagnostic &Diags,
+                ASTContext &ToContext, FileManager &ToFileManager,
+                ASTContext &FromContext, FileManager &FromFileManager);
     
     virtual ~ASTImporter();
     
@@ -191,14 +193,6 @@
     /// \brief Retrieve the file manager that AST nodes are being imported from.
     FileManager &getFromFileManager() const { return FromFileManager; }
 
-    /// \brief Retrieve the diagnostics object to use to report errors within
-    /// the context we're importing into.
-    Diagnostic &getToDiags() const { return ToDiags; }
-
-    /// \brief Retrieve the diagnostics object to use to report errors within
-    /// the context we're importing from.
-    Diagnostic &getFromDiags() const { return FromDiags; }
-    
     /// \brief Retrieve the mapping from declarations in the "from" context
     /// to the already-imported declarations in the "to" context.
     llvm::DenseMap<Decl *, Decl *> &getImportedDecls() { return ImportedDecls; }

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Thu Feb 11 13:21:55 2010
@@ -37,5 +37,19 @@
 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<
+  "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">;
+def note_odr_field : Note<"field %0 has type %1 here">;
+def note_odr_missing_field : Note<"no corresponding field here">;
+def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
+def note_odr_not_bit_field : Note<"field %0 is not a bit-field">;
+def note_odr_base : Note<"class has base type %0">;
+def note_odr_virtual_base : Note<
+  "%select{non-virtual|virtual}0 derivation here">;
+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 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=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Thu Feb 11 13:21:55 2010
@@ -18,6 +18,7 @@
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclVisitor.h"
+#include "clang/AST/StmtVisitor.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/AST/TypeVisitor.h"
 #include "clang/Basic/FileManager.h"
@@ -28,7 +29,8 @@
 
 namespace {
   class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>,
-                          public DeclVisitor<ASTNodeImporter, Decl *> {
+                          public DeclVisitor<ASTNodeImporter, Decl *>,
+                          public StmtVisitor<ASTNodeImporter, Stmt *> {
     ASTImporter &Importer;
     
   public:
@@ -36,6 +38,7 @@
     
     using TypeVisitor<ASTNodeImporter, QualType>::Visit;
     using DeclVisitor<ASTNodeImporter, Decl *>::Visit;
+    using StmtVisitor<ASTNodeImporter, Stmt *>::Visit;
 
     // Importing types
     QualType VisitType(Type *T);
@@ -89,6 +92,13 @@
     Decl *VisitFieldDecl(FieldDecl *D);
     Decl *VisitVarDecl(VarDecl *D);
     Decl *VisitParmVarDecl(ParmVarDecl *D);
+
+    // Importing statements
+    Stmt *VisitStmt(Stmt *S);
+
+    // Importing expressions
+    Expr *VisitExpr(Expr *E);
+    Expr *VisitIntegerLiteral(IntegerLiteral *E);
   };
 }
 
@@ -506,37 +516,81 @@
 
 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())
+  if (FromRecord->isUnion() != ToRecord->isUnion()) {
+    Importer.ToDiag(ToRecord->getLocation(), 
+                    diag::warn_odr_class_type_inconsistent)
+      << Importer.getToContext().getTypeDeclType(ToRecord);
+    Importer.FromDiag(FromRecord->getLocation(), diag::note_odr_tag_kind_here)
+      << FromRecord->getDeclName() << (unsigned)FromRecord->getTagKind();
     return false;
-  
+  }
+
   if (CXXRecordDecl *FromCXX = dyn_cast<CXXRecordDecl>(FromRecord)) {
     if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(ToRecord)) {
-      if (FromCXX->getNumBases() != ToCXX->getNumBases())
+      if (FromCXX->getNumBases() != ToCXX->getNumBases()) {
+        Importer.ToDiag(ToRecord->getLocation(), 
+                        diag::warn_odr_class_type_inconsistent)
+          << Importer.getToContext().getTypeDeclType(ToRecord);
+        Importer.ToDiag(ToRecord->getLocation(), diag::note_odr_number_of_bases)
+          << ToCXX->getNumBases();
+        Importer.FromDiag(FromRecord->getLocation(), 
+                          diag::note_odr_number_of_bases)
+          << FromCXX->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;
-        
+          ++FromBase, ++ToBase) {        
         // 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()))
+                                                        ToBase->getType())) {
+          Importer.ToDiag(ToRecord->getLocation(), 
+                          diag::warn_odr_class_type_inconsistent)
+            << Importer.getToContext().getTypeDeclType(ToRecord);
+          Importer.ToDiag(ToBase->getSourceRange().getBegin(),
+                          diag::note_odr_base)
+            << ToBase->getType()
+            << ToBase->getSourceRange();
+          Importer.FromDiag(FromBase->getSourceRange().getBegin(),
+                            diag::note_odr_base)
+            << FromBase->getType()
+            << FromBase->getSourceRange();
           return false;
+        }
+
+        // Check virtual vs. non-virtual inheritance mismatch.
+        if (FromBase->isVirtual() != ToBase->isVirtual()) {
+          Importer.ToDiag(ToRecord->getLocation(), 
+                          diag::warn_odr_class_type_inconsistent)
+            << Importer.getToContext().getTypeDeclType(ToRecord);
+          Importer.ToDiag(ToBase->getSourceRange().getBegin(),
+                          diag::note_odr_virtual_base)
+            << ToBase->isVirtual() << ToBase->getSourceRange();
+          Importer.FromDiag(FromBase->getSourceRange().getBegin(),
+                            diag::note_odr_base)
+            << FromBase->isVirtual()
+            << FromBase->getSourceRange();
+          return false;
+        }
       }
     } else if (FromCXX->getNumBases() > 0) {
+      Importer.ToDiag(ToRecord->getLocation(), 
+                      diag::warn_odr_class_type_inconsistent)
+        << Importer.getToContext().getTypeDeclType(ToRecord);
+      const CXXBaseSpecifier *FromBase = FromCXX->bases_begin();
+      Importer.FromDiag(FromBase->getSourceRange().getBegin(),
+                        diag::note_odr_base)
+        << FromBase->getType()
+        << FromBase->getSourceRange();
+      Importer.ToDiag(ToRecord->getLocation(), diag::note_odr_missing_base);
       return false;
     }
   }
@@ -548,19 +602,58 @@
                                   FromFieldEnd = FromRecord->field_end();
        FromField != FromFieldEnd;
        ++FromField, ++ToField) {
-    if (ToField == ToFieldEnd)
+    if (ToField == ToFieldEnd) {
+      Importer.ToDiag(ToRecord->getLocation(), 
+                      diag::warn_odr_class_type_inconsistent)
+        << Importer.getToContext().getTypeDeclType(ToRecord);
+      Importer.FromDiag(FromField->getLocation(), diag::note_odr_field)
+        << FromField->getDeclName() << FromField->getType();
+      Importer.ToDiag(ToRecord->getLocation(), diag::note_odr_missing_field);
       return false;
-    
+    }
+
     QualType FromT = Importer.Import(FromField->getType());
     if (FromT.isNull())
       return false;
   
-    if (FromField->isBitField() != ToField->isBitField())
+    if (!Importer.getToContext().typesAreCompatible(FromT, ToField->getType())){
+      Importer.ToDiag(ToRecord->getLocation(), 
+                      diag::warn_odr_class_type_inconsistent)
+        << Importer.getToContext().getTypeDeclType(ToRecord);
+      Importer.ToDiag(ToField->getLocation(), diag::note_odr_field)
+        << ToField->getDeclName() << ToField->getType();
+      Importer.FromDiag(FromField->getLocation(), diag::note_odr_field)
+        << FromField->getDeclName() << FromField->getType();
       return false;
+    }
 
-    if (!Importer.getToContext().typesAreCompatible(FromT, ToField->getType()))
+    if (FromField->isBitField() != ToField->isBitField()) {
+      Importer.ToDiag(ToRecord->getLocation(), 
+                      diag::warn_odr_class_type_inconsistent)
+        << Importer.getToContext().getTypeDeclType(ToRecord);
+      if (FromField->isBitField()) {
+        llvm::APSInt Bits;
+        FromField->getBitWidth()->isIntegerConstantExpr(Bits,
+                                                   Importer.getFromContext());
+        Importer.FromDiag(FromField->getLocation(), diag::note_odr_bit_field)
+          << FromField->getDeclName() << FromField->getType()
+          << Bits.toString(10, false);
+        Importer.ToDiag(ToField->getLocation(), diag::note_odr_not_bit_field)
+          << ToField->getDeclName();
+      } else {
+        llvm::APSInt Bits;
+        ToField->getBitWidth()->isIntegerConstantExpr(Bits,
+                                                   Importer.getToContext());
+        Importer.ToDiag(ToField->getLocation(), diag::note_odr_bit_field)
+          << ToField->getDeclName() << ToField->getType()
+          << Bits.toString(10, false);
+        Importer.FromDiag(FromField->getLocation(), 
+                          diag::note_odr_not_bit_field)
+          << FromField->getDeclName();
+      }
       return false;
-    
+    }
+
     if (FromField->isBitField()) {
       // Make sure that the bit-fields are the same length.
       llvm::APSInt FromBits, ToBits;
@@ -579,12 +672,32 @@
       FromBits.setIsUnsigned(true);
       ToBits.setIsUnsigned(true);
       
-      if (FromBits != ToBits)
+      if (FromBits != ToBits) {
+        Importer.ToDiag(ToRecord->getLocation(), 
+                        diag::warn_odr_class_type_inconsistent)
+          << Importer.getToContext().getTypeDeclType(ToRecord);
+        Importer.ToDiag(ToField->getLocation(), diag::note_odr_bit_field)
+          << ToField->getDeclName() << ToField->getType()
+          << ToBits.toString(10, false);
+        Importer.FromDiag(FromField->getLocation(), diag::note_odr_bit_field)
+          << FromField->getDeclName() << FromField->getType()
+          << FromBits.toString(10, false);
         return false;
+      }
     }
   }
   
-  return ToField == ToFieldEnd;
+  if (ToField != ToFieldEnd) {
+    Importer.ToDiag(ToRecord->getLocation(), 
+                    diag::warn_odr_class_type_inconsistent)
+      << Importer.getToContext().getTypeDeclType(ToRecord);
+    Importer.ToDiag(ToField->getLocation(), diag::note_odr_field)
+      << ToField->getDeclName() << ToField->getType();
+    Importer.FromDiag(FromRecord->getLocation(), diag::note_odr_missing_field);
+    return false;
+  }
+
+  return true;
 }
 
 Decl *ASTNodeImporter::VisitDecl(Decl *D) {
@@ -691,11 +804,14 @@
       }
       
       if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
-        if (IsStructuralMatch(D, FoundRecord)) {
+        RecordDecl *FoundDef = FoundRecord->getDefinition();
+        // FIXME: If we found something but there is no definition,
+        // assume the types are the same and fill in the gaps.
+        if (FoundDef && IsStructuralMatch(D, FoundDef)) {
           // The record types structurally match.
           // FIXME: For C++, we should also merge methods here.
-          Importer.getImportedDecls()[D] = FoundRecord;
-          return FoundRecord;
+          Importer.getImportedDecls()[D] = FoundDef;
+          return FoundDef;
         }
       }
       
@@ -1026,13 +1142,40 @@
   return ToParm;
 }
 
-ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
-                         Diagnostic &ToDiags,
-                         ASTContext &FromContext, FileManager &FromFileManager,
-                         Diagnostic &FromDiags)
+//----------------------------------------------------------------------------
+// Import Statements
+//----------------------------------------------------------------------------
+
+Stmt *ASTNodeImporter::VisitStmt(Stmt *S) {
+  Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node)
+    << S->getStmtClassName();
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+// Import Expressions
+//----------------------------------------------------------------------------
+Expr *ASTNodeImporter::VisitExpr(Expr *E) {
+  Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node)
+    << E->getStmtClassName();
+  return 0;
+}
+
+Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) {
+  QualType T = Importer.Import(E->getType());
+  if (T.isNull())
+    return 0;
+
+  return new (Importer.getToContext()) 
+    IntegerLiteral(E->getValue(), T, Importer.Import(E->getLocation()));
+}
+
+ASTImporter::ASTImporter(Diagnostic &Diags,
+                         ASTContext &ToContext, FileManager &ToFileManager,
+                         ASTContext &FromContext, FileManager &FromFileManager)
   : ToContext(ToContext), FromContext(FromContext),
     ToFileManager(ToFileManager), FromFileManager(FromFileManager),
-    ToDiags(ToDiags), FromDiags(FromDiags) { 
+    Diags(Diags) {
   ImportedDecls[FromContext.getTranslationUnitDecl()]
     = ToContext.getTranslationUnitDecl();
 }
@@ -1114,8 +1257,20 @@
   if (!FromS)
     return 0;
 
-  // FIXME: Implement!
-  return 0;
+  // Check whether we've already imported this declaration.  
+  llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS);
+  if (Pos != ImportedStmts.end())
+    return Pos->second;
+  
+  // Import the type
+  ASTNodeImporter Importer(*this);
+  Stmt *ToS = Importer.Visit(FromS);
+  if (!ToS)
+    return 0;
+  
+  // Record the imported declaration.
+  ImportedStmts[FromS] = ToS;
+  return ToS;
 }
 
 NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) {
@@ -1259,11 +1414,11 @@
 }
 
 DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) {
-  return ToDiags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()), 
-                        DiagID);
+  return Diags.Report(FullSourceLoc(Loc, ToContext.getSourceManager()), 
+                      DiagID);
 }
 
 DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) {
-  return FromDiags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()), 
-                          DiagID);
+  return Diags.Report(FullSourceLoc(Loc, FromContext.getSourceManager()), 
+                      DiagID);
 }

Modified: cfe/trunk/lib/Frontend/ASTMerge.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/ASTMerge.cpp?rev=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/ASTMerge.cpp (original)
+++ cfe/trunk/lib/Frontend/ASTMerge.cpp Thu Feb 11 13:21:55 2010
@@ -37,21 +37,16 @@
   CI.getDiagnostics().SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
                                        &CI.getASTContext());
   for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) {
-    Diagnostic ASTDiags(CI.getDiagnostics().getClient());
-    
-    ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], ASTDiags,
+    ASTUnit *Unit = ASTUnit::LoadFromPCHFile(ASTFiles[I], CI.getDiagnostics(),
                                              false, true);
     if (!Unit)
       continue;
 
-    ASTDiags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument,
-                              &Unit->getASTContext());
-    ASTImporter Importer(CI.getASTContext(), 
+    ASTImporter Importer(CI.getDiagnostics(),
+                         CI.getASTContext(), 
                          CI.getFileManager(),
-                         CI.getDiagnostics(),
                          Unit->getASTContext(), 
-                         Unit->getFileManager(),
-                         ASTDiags);
+                         Unit->getFileManager());
 
     TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
     for (DeclContext::decl_iterator D = TU->decls_begin(), 

Modified: cfe/trunk/test/ASTMerge/Inputs/struct1.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/struct1.c?rev=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/struct1.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/struct1.c Thu Feb 11 13:21:55 2010
@@ -1,6 +1,7 @@
 typedef int Int;
 typedef float Float;
 
+// Matches
 struct S0 {
   Int field1;
   Float field2;
@@ -8,9 +9,28 @@
 
 struct S0 x0;
 
+// Mismatch in field type
 struct S1 {
   Int field1;
   int field2;
 };
 
 struct S1 x1;
+
+// Mismatch in tag kind.
+struct S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; double d; } x3;
+
+// Extra fields
+struct S4 { int i; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j : 8; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 8; } x7;

Modified: cfe/trunk/test/ASTMerge/Inputs/struct2.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/struct2.c?rev=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/struct2.c (original)
+++ cfe/trunk/test/ASTMerge/Inputs/struct2.c Thu Feb 11 13:21:55 2010
@@ -1,3 +1,4 @@
+// Matches
 struct S0 {
   int field1;
   float field2;
@@ -5,9 +6,28 @@
 
 struct S0 x0;
 
+// Mismatch in field type
 struct S1 {
   int field1;
   float field2;
 };
 
 struct S1 x1;
+
+// Mismatch in tag kind.
+union S2 { int i; float f; } x2;
+
+// Missing fields
+struct S3 { int i; float f; } x3;
+
+// Extra fields
+struct S4 { int i; float f; } x4;
+
+// Bit-field matches
+struct S5 { int i : 8; unsigned j : 8; } x5;
+
+// Bit-field mismatch
+struct S6 { int i : 8; unsigned j; } x6;
+
+// Bit-field mismatch
+struct S7 { int i : 8; unsigned j : 16; } x7;

Modified: cfe/trunk/test/ASTMerge/struct.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/struct.c?rev=95900&r1=95899&r2=95900&view=diff

==============================================================================
--- cfe/trunk/test/ASTMerge/struct.c (original)
+++ cfe/trunk/test/ASTMerge/struct.c Thu Feb 11 13:21:55 2010
@@ -2,6 +2,33 @@
 // RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/struct2.c
 // RUN: %clang_cc1 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s
 
-// CHECK: struct2.c:13:11: error: external variable 'x1' declared with incompatible types in different translation units ('struct S1' vs. 'struct S1')
-// CHECK: struct1.c:16:11: note: declared here with type 'struct S1'
-// CHECK: 2 diagnostics
+// CHECK: struct1.c:13:8: warning: type 'struct S1' has incompatible definitions in different translation units
+// CHECK: struct1.c:15:7: note: field 'field2' has type 'int' here
+// CHECK: struct2.c:12:9: note: field 'field2' has type 'float' here
+// CHECK: struct2.c:15:11: error: external variable 'x1' declared with incompatible types in different translation units ('struct S1' vs. 'struct S1')
+// CHECK: struct1.c:18:11: note: declared here with type 'struct S1'
+// CHECK: struct1.c:21:8: warning: type 'struct S2' has incompatible definitions in different translation units
+// CHECK: struct2.c:18:7: note: 'S2' is a union here
+// CHECK: struct2.c:18:30: error: external variable 'x2' declared with incompatible types in different translation units ('union S2' vs. 'struct S2')
+// CHECK: struct1.c:21:31: note: declared here with type 'struct S2'
+// CHECK: struct1.c:24:8: warning: type 'struct S3' has incompatible definitions in different translation units
+// CHECK: struct1.c:24:36: note: field 'd' has type 'double' here
+// CHECK: struct2.c:21:8: note: no corresponding field here
+// CHECK: struct2.c:21:31: error: external variable 'x3' declared with incompatible types in different translation units ('struct S3' vs. 'struct S3')
+// CHECK: struct1.c:24:41: note: declared here with type 'struct S3'
+// CHECK: struct1.c:27:8: warning: type 'struct S4' has incompatible definitions in different translation units
+// CHECK: struct2.c:24:26: note: field 'f' has type 'float' here
+// CHECK: struct1.c:27:8: note: no corresponding field here
+// CHECK: struct2.c:24:31: error: external variable 'x4' declared with incompatible types in different translation units ('struct S4' vs. 'struct S4')
+// CHECK: struct1.c:27:22: note: declared here with type 'struct S4'
+// CHECK: struct1.c:33:8: warning: type 'struct S6' has incompatible definitions in different translation units
+// CHECK: struct1.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:30:33: note: field 'j' is not a bit-field
+// CHECK: struct2.c:30:38: error: external variable 'x6' declared with incompatible types in different translation units ('struct S6' vs. 'struct S6')
+// CHECK: struct1.c:33:42: note: declared here with type 'struct S6'
+// CHECK: struct1.c:36:8: warning: type 'struct S7' has incompatible definitions in different translation units
+// CHECK: struct1.c:36:33: note: bit-field 'j' with type 'unsigned int' and length 8 here
+// CHECK: struct2.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 16 here
+// CHECK: struct2.c:33:43: error: external variable 'x7' declared with incompatible types in different translation units ('struct S7' vs. 'struct S7')
+// CHECK: struct1.c:36:42: note: declared here with type 'struct S7'
+// CHECK: 29 diagnostics





More information about the cfe-commits mailing list