forked from OSchip/llvm-project
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) llvm-svn: 95900
This commit is contained in:
parent
8a30324e51
commit
7eeb59752a
|
@ -40,9 +40,8 @@ namespace clang {
|
|||
/// \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 @@ namespace clang {
|
|||
/// \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 @@ namespace clang {
|
|||
/// \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; }
|
||||
|
|
|
@ -37,5 +37,19 @@ def note_odr_defined_here : Note<"also defined here">;
|
|||
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">;
|
||||
}
|
||||
|
|
|
@ -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 @@ using namespace clang;
|
|||
|
||||
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 @@ namespace {
|
|||
|
||||
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 @@ namespace {
|
|||
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::ImportDeclParts(DeclaratorDecl *D,
|
|||
|
||||
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 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
|
|||
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 @@ bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord,
|
|||
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 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
|
|||
}
|
||||
|
||||
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 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) {
|
|||
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 @@ Stmt *ASTImporter::Import(Stmt *FromS) {
|
|||
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 @@ DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name,
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -37,21 +37,16 @@ void ASTMergeAction::ExecuteAction() {
|
|||
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(),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
typedef int Int;
|
||||
typedef float Float;
|
||||
|
||||
// Matches
|
||||
struct S0 {
|
||||
Int field1;
|
||||
Float field2;
|
||||
|
@ -8,9 +9,28 @@ struct S0 {
|
|||
|
||||
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;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// Matches
|
||||
struct S0 {
|
||||
int field1;
|
||||
float field2;
|
||||
|
@ -5,9 +6,28 @@ struct S0 {
|
|||
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue