diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 98034cfcd8413..55611497db280 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -296,13 +296,6 @@ C23 Feature Support scope. - Fixed a bug where you could not cast a null pointer constant to type ``nullptr_t``. Fixes #GH133644. -- Implemented `WG14 N3037 `_ - which allows tag types to be redefined within the same translation unit so - long as both definitions are structurally equivalent (same tag types, same - tag names, same tag members, etc). As a result of this paper, ``-Wvisibility`` - is no longer diagnosed in C23 if the parameter is a complete tag type (it - does still fire when the parameter is an incomplete tag type as that cannot - be completed). - Fixed a failed assertion with an invalid parameter to the ``#embed`` directive. Fixes #GH126940. - Fixed a crash when a declaration of a ``constexpr`` variable with an invalid diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index b0abb491fc3fc..f2019afc63a57 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3354,7 +3354,6 @@ class ASTContext : public RefCountedBase { QualType mergeTransparentUnionType(QualType, QualType, bool OfBlockPointer=false, bool Unqualified = false); - QualType mergeTagDefinitions(QualType, QualType); QualType mergeObjCGCQualifiers(QualType, QualType); diff --git a/clang/include/clang/AST/ASTStructuralEquivalence.h b/clang/include/clang/AST/ASTStructuralEquivalence.h index 5e431a14f1756..b0caded2f49a6 100644 --- a/clang/include/clang/AST/ASTStructuralEquivalence.h +++ b/clang/include/clang/AST/ASTStructuralEquivalence.h @@ -43,9 +43,6 @@ struct StructuralEquivalenceContext { /// key: (from, to, IgnoreTemplateParmDepth) using NonEquivalentDeclSet = llvm::DenseSet>; - /// The language options to use for making a structural equivalence check. - const LangOptions &LangOpts; - /// AST contexts for which we are checking structural equivalence. ASTContext &FromCtx, &ToCtx; @@ -79,17 +76,15 @@ struct StructuralEquivalenceContext { /// Whether to ignore comparing the depth of template param(TemplateTypeParm) bool IgnoreTemplateParmDepth; - StructuralEquivalenceContext(const LangOptions &LangOpts, ASTContext &FromCtx, - ASTContext &ToCtx, + StructuralEquivalenceContext(ASTContext &FromCtx, ASTContext &ToCtx, NonEquivalentDeclSet &NonEquivalentDecls, StructuralEquivalenceKind EqKind, bool StrictTypeSpelling = false, bool Complain = true, bool ErrorOnTagTypeMismatch = false, bool IgnoreTemplateParmDepth = false) - : LangOpts(LangOpts), FromCtx(FromCtx), ToCtx(ToCtx), - NonEquivalentDecls(NonEquivalentDecls), EqKind(EqKind), - StrictTypeSpelling(StrictTypeSpelling), + : FromCtx(FromCtx), ToCtx(ToCtx), NonEquivalentDecls(NonEquivalentDecls), + EqKind(EqKind), StrictTypeSpelling(StrictTypeSpelling), ErrorOnTagTypeMismatch(ErrorOnTagTypeMismatch), Complain(Complain), IgnoreTemplateParmDepth(IgnoreTemplateParmDepth) {} diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index 775741fb755e9..31707dbc89631 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -480,23 +480,16 @@ def warn_odr_function_type_inconsistent : Warning< "external function %0 declared with incompatible types in different " "translation units (%1 vs. %2)">, InGroup; -def warn_odr_tag_type_with_attributes : Warning< - "type %0 has %select{an attribute|a member with an attribute}1 which " - "currently causes the types to be treated as though they are incompatible">, - InGroup, DefaultError; -def note_odr_attr_here : Note<"attribute %0 here">; def err_odr_tag_type_inconsistent - : Error<"type %0 has incompatible definitions%select{| in different " - "translation units}1">; + : Error<"type %0 has incompatible definitions in different translation " + "units">; def warn_odr_tag_type_inconsistent - : Warning<"type %0 has incompatible definitions%select{| in different " - "translation units}1">, + : Warning<"type %0 has incompatible definitions in different translation " + "units">, InGroup; def note_odr_tag_kind_here: Note< "%0 is a %select{struct|interface|union|class|enum}1 here">; def note_odr_field : Note<"field %0 has type %1 here">; -def note_odr_field_bit_width : Note<"bit-field %0 has bit-width %1 here">; -def note_odr_field_not_bit_field : Note<"field %0 is not a bit-field">; def note_odr_field_name : Note<"field has name %0 here">; def note_odr_missing_field : Note<"no corresponding field here">; def note_odr_base : Note<"class has base type %0">; @@ -507,14 +500,6 @@ 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 note_odr_incompatible_fixed_underlying_type : Note< - "enumeration %0 declared with incompatible fixed underlying types (%1 vs. " - "%2)">; -def note_odr_fixed_underlying_type : Note< - "enumeration %0 has fixed underlying type here">; -def note_odr_missing_fixed_underlying_type : Note< - "enumeration %0 missing fixed underlying type here">; - def err_odr_field_type_inconsistent : Error< "field %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 5a4de122482c7..a24126ddd31a8 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1964,21 +1964,6 @@ class Parser : public CodeCompletionHandler { const ParsedTemplateInfo &TemplateInfo, AccessSpecifier AS, DeclSpecContext DSC); - /// ParseEnumBody - Parse a {} enclosed enumerator-list. - /// \verbatim - /// enumerator-list: - /// enumerator - /// enumerator-list ',' enumerator - /// enumerator: - /// enumeration-constant attributes[opt] - /// enumeration-constant attributes[opt] '=' constant-expression - /// enumeration-constant: - /// identifier - /// \endverbatim - /// - void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl, - SkipBodyInfo *SkipBody = nullptr); - /// ParseStructUnionBody /// \verbatim /// struct-contents: @@ -1991,6 +1976,7 @@ class Parser : public CodeCompletionHandler { /// [OBC] '@' 'defs' '(' class-name ')' /// \endverbatim /// + void ParseEnumBody(SourceLocation StartLoc, Decl *TagDecl); void ParseStructUnionBody(SourceLocation StartLoc, DeclSpec::TST TagType, RecordDecl *TagDecl); diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 98ac143bf1dcb..4f50987232b9b 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4811,8 +4811,7 @@ class Sema final : public SemaBase { Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, const ParsedAttributesView &Attrs, - SourceLocation EqualLoc, Expr *Val, - SkipBodyInfo *SkipBody = nullptr); + SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef Elements, Scope *S, const ParsedAttributesView &Attr); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fe663e2986d3b..6ff1b8f3fac9f 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -16,7 +16,6 @@ #include "clang/AST/APValue.h" #include "clang/AST/ASTConcept.h" #include "clang/AST/ASTMutationListener.h" -#include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" #include "clang/AST/AttrIterator.h" @@ -12358,28 +12357,6 @@ static QualType mergeEnumWithInteger(ASTContext &Context, const EnumType *ET, return {}; } -QualType ASTContext::mergeTagDefinitions(QualType LHS, QualType RHS) { - // C17 and earlier and C++ disallow two tag definitions within the same TU - // from being compatible. - if (LangOpts.CPlusPlus || !LangOpts.C23) - return {}; - - // Nameless tags are comparable only within outer definitions. At the top - // level they are not comparable. - const TagDecl *LTagD = LHS->getAsTagDecl(), *RTagD = RHS->getAsTagDecl(); - if (!LTagD->getIdentifier() || !RTagD->getIdentifier()) - return {}; - - // C23, on the other hand, requires the members to be "the same enough", so - // we use a structural equivalence check. - StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls; - StructuralEquivalenceContext Ctx( - getLangOpts(), *this, *this, NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/true); - return Ctx.IsEquivalent(LHS, RHS) ? LHS : QualType{}; -} - QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, bool Unqualified, bool BlockReturnType, bool IsConditionalOperator) { @@ -12701,7 +12678,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, /*AllowCXX=*/false, IsConditionalOperator); case Type::Record: case Type::Enum: - return mergeTagDefinitions(LHS, RHS); + return {}; case Type::Builtin: // Only exactly equal builtin types are compatible, which is tested above. return {}; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 944d18bdaacca..02ee96592d494 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -2723,9 +2723,8 @@ bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain, } StructuralEquivalenceContext Ctx( - Importer.getToContext().getLangOpts(), Importer.getFromContext(), - Importer.getToContext(), Importer.getNonEquivalentDecls(), - getStructuralEquivalenceKind(Importer), + Importer.getFromContext(), Importer.getToContext(), + Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), /*StrictTypeSpelling=*/false, Complain, /*ErrorOnTagTypeMismatch=*/false, IgnoreTemplateParmDepth); return Ctx.IsEquivalent(From, To); @@ -4587,8 +4586,7 @@ static bool IsEquivalentFriend(ASTImporter &Importer, FriendDecl *FD1, ASTImporter::NonEquivalentDeclSet NonEquivalentDecls; StructuralEquivalenceContext Ctx( - Importer.getToContext().getLangOpts(), FD1->getASTContext(), - FD2->getASTContext(), NonEquivalentDecls, + FD1->getASTContext(), FD2->getASTContext(), NonEquivalentDecls, StructuralEquivalenceKind::Default, /* StrictTypeSpelling = */ false, /* Complain = */ false); return Ctx.IsEquivalent(FD1, FD2); @@ -10885,8 +10883,8 @@ bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To, } } - StructuralEquivalenceContext Ctx( - getToContext().getLangOpts(), FromContext, ToContext, NonEquivalentDecls, - getStructuralEquivalenceKind(*this), false, Complain); + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls, + getStructuralEquivalenceKind(*this), false, + Complain); return Ctx.IsEquivalent(From, To); } diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 2cfff06e15541..e81cfa5425425 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -61,7 +61,6 @@ #include "clang/AST/ASTStructuralEquivalence.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" -#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -451,43 +450,6 @@ class StmtComparer { }; } // namespace -static bool -CheckStructurallyEquivalentAttributes(StructuralEquivalenceContext &Context, - const Decl *D1, const Decl *D2, - const Decl *PrimaryDecl = nullptr) { - // If either declaration has an attribute on it, we treat the declarations - // as not being structurally equivalent unless both declarations are implicit - // (ones generated by the compiler like __NSConstantString_tag). - // - // FIXME: this should be handled on a case-by-case basis via tablegen in - // Attr.td. There are multiple cases to consider: one declaration with the - // attribute, another without it; different attribute syntax|spellings for - // the same semantic attribute, differences in attribute arguments, order - // in which attributes are applied, how to merge attributes if the types are - // structurally equivalent, etc. - const Attr *D1Attr = nullptr, *D2Attr = nullptr; - if (D1->hasAttrs()) - D1Attr = *D1->getAttrs().begin(); - if (D2->hasAttrs()) - D2Attr = *D2->getAttrs().begin(); - if ((D1Attr || D2Attr) && !D1->isImplicit() && !D2->isImplicit()) { - const auto *DiagnoseDecl = cast(PrimaryDecl ? PrimaryDecl : D2); - Context.Diag2(DiagnoseDecl->getLocation(), - diag::warn_odr_tag_type_with_attributes) - << Context.ToCtx.getTypeDeclType(DiagnoseDecl) - << (PrimaryDecl != nullptr); - if (D1Attr) - Context.Diag1(D1Attr->getLoc(), diag::note_odr_attr_here) << D1Attr; - if (D2Attr) - Context.Diag1(D2Attr->getLoc(), diag::note_odr_attr_here) << D2Attr; - } - - // The above diagnostic is a warning which defaults to an error. If treated - // as a warning, we'll go ahead and allow any attribute differences to be - // undefined behavior and the user gets what they get in terms of behavior. - return true; -} - static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, const UnaryOperator *E1, const CXXOperatorCallExpr *E2) { @@ -875,29 +837,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, else if (T1->getTypeClass() == Type::FunctionNoProto && T2->getTypeClass() == Type::FunctionProto) TC = Type::FunctionNoProto; - else if (Context.LangOpts.C23 && !Context.StrictTypeSpelling && - (T1->getTypeClass() == Type::Enum || - T2->getTypeClass() == Type::Enum)) { - // In C23, if not being strict about token equivalence, we need to handle - // the case where one type is an enumeration and the other type is an - // integral type. - // - // C23 6.7.3.3p16: The enumerated type is compatible with the underlying - // type of the enumeration. - // - // Treat the enumeration as its underlying type and use the builtin type - // class comparison. - if (T1->getTypeClass() == Type::Enum) { - T1 = T1->getAs()->getDecl()->getIntegerType(); - if (!T2->isBuiltinType() || T1.isNull()) // Sanity check - return false; - } else if (T2->getTypeClass() == Type::Enum) { - T2 = T2->getAs()->getDecl()->getIntegerType(); - if (!T1->isBuiltinType() || T2.isNull()) // Sanity check - return false; - } - TC = Type::Builtin; - } else + else return false; } @@ -1560,12 +1500,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, QualType Owner2Type) { const auto *Owner2 = cast(Field2->getDeclContext()); - // In C23 mode, check for structural equivalence of attributes on the fields. - // FIXME: Should this happen in C++ as well? - if (Context.LangOpts.C23 && - !CheckStructurallyEquivalentAttributes(Context, Field1, Field2, Owner2)) - return false; - // For anonymous structs/unions, match up the anonymous struct/union type // declarations directly, so that we don't go off searching for anonymous // types @@ -1584,7 +1518,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2( Owner2->getLocation(), Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) - << Owner2Type << (&Context.FromCtx != &Context.ToCtx); + << Owner2Type; Context.Diag2(Field2->getLocation(), diag::note_odr_field_name) << Field2->getDeclName(); Context.Diag1(Field1->getLocation(), diag::note_odr_field_name) @@ -1599,7 +1533,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2( Owner2->getLocation(), Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) - << Owner2Type << (&Context.FromCtx != &Context.ToCtx); + << Owner2Type; Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); Context.Diag1(Field1->getLocation(), diag::note_odr_field) @@ -1608,39 +1542,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return false; } - if ((Field1->isBitField() || Field2->isBitField()) && - !IsStructurallyEquivalent(Context, Field1->getBitWidth(), - Field2->getBitWidth())) { - // Two bit-fields can be structurally unequivalent but still be okay for - // the purposes of C where they simply need to have the same values, not - // the same token sequences. - bool Diagnose = true; - if (Context.LangOpts.C23 && Field1->isBitField() && Field2->isBitField()) - Diagnose = Field1->getBitWidthValue() != Field2->getBitWidthValue(); - - if (Diagnose && Context.Complain) { - auto DiagNote = [&](const FieldDecl *FD, - DiagnosticBuilder ( - StructuralEquivalenceContext::*Diag)( - SourceLocation, unsigned)) { - if (FD->isBitField()) { - (Context.*Diag)(FD->getLocation(), diag::note_odr_field_bit_width) - << FD->getDeclName() << FD->getBitWidthValue(); - } else { - (Context.*Diag)(FD->getLocation(), diag::note_odr_field_not_bit_field) - << FD->getDeclName(); - } - }; - - Context.Diag2( - Owner2->getLocation(), - Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) - << Owner2Type << (&Context.FromCtx != &Context.ToCtx); - DiagNote(Field2, &StructuralEquivalenceContext::Diag2); - DiagNote(Field1, &StructuralEquivalenceContext::Diag1); - } - return false; - } + if (Field1->isBitField()) + return IsStructurallyEquivalent(Context, Field1->getBitWidth(), + Field2->getBitWidth()); return true; } @@ -1803,15 +1707,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // another anonymous structure or union, respectively, if their members // fulfill the preceding requirements. ... Otherwise, the structure, union, // or enumerated types are incompatible. - if (!NameIsStructurallyEquivalent(*D1, *D2)) + if (!NameIsStructurallyEquivalent(*D1, *D2)) { return false; + } if (D1->isUnion() != D2->isUnion()) { if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) << D1->getDeclName() << (unsigned)D1->getTagKind(); } @@ -1832,19 +1736,10 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } } - // In C23 mode, check for structural equivalence of attributes on the record - // itself. FIXME: Should this happen in C++ as well? - if (Context.LangOpts.C23 && - !CheckStructurallyEquivalentAttributes(Context, D1, D2)) - return false; - // If the records occur in different context (namespace), these should be // different. This is specially important if the definition of one or both - // records is missing. In C23, different contexts do not make for a different - // structural type (a local struct definition can be a valid redefinition of - // a file scope struct definition). - if (!Context.LangOpts.C23 && - !IsRecordContextStructurallyEquivalent(Context, D1, D2)) + // records is missing. + if (!IsRecordContextStructurallyEquivalent(Context, D1, D2)) return false; // If both declarations are class template specializations, we know @@ -1873,11 +1768,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Compare the definitions of these two records. If either or both are // incomplete (i.e. it is a forward decl), we assume that they are - // equivalent. except in C23 mode. + // equivalent. D1 = D1->getDefinition(); D2 = D2->getDefinition(); if (!D1 || !D2) - return !Context.LangOpts.C23; + return true; // If any of the records has external storage and we do a minimal check (or // AST import) we assume they are equivalent. (If we didn't have this @@ -1912,8 +1807,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) << D2CXX->getNumBases(); Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) @@ -1933,8 +1827,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_base) << Base2->getType() << Base2->getSourceRange(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -1949,8 +1842,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Base2->getBeginLoc(), diag::note_odr_virtual_base) << Base2->isVirtual() << Base2->getSourceRange(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) @@ -1971,8 +1863,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend); } @@ -1984,8 +1875,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2CXX) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2CXX); Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); } @@ -1998,8 +1888,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend); Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend); } @@ -2010,8 +1899,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); Context.Diag1(Base1->getBeginLoc(), diag::note_odr_base) << Base1->getType() << Base1->getSourceRange(); @@ -2033,8 +1921,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag1(Field1->getLocation(), diag::note_odr_field) << Field1->getDeclName() << Field1->getType(); Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); @@ -2050,8 +1937,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); + << Context.ToCtx.getTypeDeclType(D2); Context.Diag2(Field2->getLocation(), diag::note_odr_field) << Field2->getDeclName() << Field2->getType(); Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); @@ -2091,126 +1977,54 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, // Compare the definitions of these two enums. If either or both are // incomplete (i.e. forward declared), we assume that they are equivalent. - // In C23, the order of the enumerations does not matter, only the names and - // values do. D1 = D1->getDefinition(); D2 = D2->getDefinition(); if (!D1 || !D2) return true; - if (Context.LangOpts.C23 && - !CheckStructurallyEquivalentAttributes(Context, D1, D2)) - return false; - - // In C23, if one enumeration has a fixed underlying type, the other shall - // have a compatible fixed underlying type (6.2.7). - if (Context.LangOpts.C23) { - if (D1->isFixed() != D2->isFixed()) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.getApplicableDiagnostic( - diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); - Context.Diag1(D1->getLocation(), - D1->isFixed() - ? diag::note_odr_fixed_underlying_type - : diag::note_odr_missing_fixed_underlying_type) - << D1; - Context.Diag2(D2->getLocation(), - D2->isFixed() - ? diag::note_odr_fixed_underlying_type - : diag::note_odr_missing_fixed_underlying_type) - << D2; - } - return false; - } - if (D1->isFixed()) { - assert(D2->isFixed() && "enums expected to have fixed underlying types"); - if (!IsStructurallyEquivalent(Context, D1->getIntegerType(), - D2->getIntegerType())) { - if (Context.Complain) { - Context.Diag2(D2->getLocation(), - Context.getApplicableDiagnostic( - diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); - Context.Diag2(D2->getLocation(), - diag::note_odr_incompatible_fixed_underlying_type) - << D2 << D2->getIntegerType() << D1->getIntegerType(); - } - return false; - } - } - } - - llvm::SmallVector D1Enums, D2Enums; - auto CopyEnumerators = - [](auto &&Range, llvm::SmallVectorImpl &Cont) { - for (const EnumConstantDecl *ECD : Range) - Cont.push_back(ECD); - }; - CopyEnumerators(D1->enumerators(), D1Enums); - CopyEnumerators(D2->enumerators(), D2Enums); - - // In C23 mode, the order of the enumerations does not matter, so sort them - // by name to get them both into a consistent ordering. - if (Context.LangOpts.C23) { - auto Sorter = [](const EnumConstantDecl *LHS, const EnumConstantDecl *RHS) { - return LHS->getName() < RHS->getName(); - }; - llvm::sort(D1Enums, Sorter); - llvm::sort(D2Enums, Sorter); - } - - auto EC2 = D2Enums.begin(), EC2End = D2Enums.end(); - for (auto EC1 = D1Enums.begin(), EC1End = D1Enums.end(); EC1 != EC1End; - ++EC1, ++EC2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { if (EC2 == EC2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); - Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator) - << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10); + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << toString(EC1->getInitVal(), 10); Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); } return false; } - llvm::APSInt Val1 = (*EC1)->getInitVal(); - llvm::APSInt Val2 = (*EC2)->getInitVal(); + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); if (!llvm::APSInt::isSameValue(Val1, Val2) || - !IsStructurallyEquivalent((*EC1)->getIdentifier(), - (*EC2)->getIdentifier())) { + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); - Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) - << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); - Context.Diag1((*EC1)->getLocation(), diag::note_odr_enumerator) - << (*EC1)->getDeclName() << toString((*EC1)->getInitVal(), 10); + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << toString(EC2->getInitVal(), 10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() << toString(EC1->getInitVal(), 10); } return false; } - if (Context.LangOpts.C23 && - !CheckStructurallyEquivalentAttributes(Context, *EC1, *EC2, D2)) - return false; } if (EC2 != EC2End) { if (Context.Complain) { Context.Diag2(D2->getLocation(), Context.getApplicableDiagnostic( diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(D2) - << (&Context.FromCtx != &Context.ToCtx); - Context.Diag2((*EC2)->getLocation(), diag::note_odr_enumerator) - << (*EC2)->getDeclName() << toString((*EC2)->getInitVal(), 10); + << Context.ToCtx.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() << toString(EC2->getInitVal(), 10); Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); } return false; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 206be6629c28e..c0c40406bc21c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5572,7 +5572,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (Tok.is(tok::l_brace) && TUK == TagUseKind::Definition) { Decl *D = SkipBody.CheckSameAsPrevious ? SkipBody.New : TagDecl; - ParseEnumBody(StartLoc, D, &SkipBody); + ParseEnumBody(StartLoc, D); if (SkipBody.CheckSameAsPrevious && !Actions.ActOnDuplicateDefinition(getCurScope(), TagDecl, SkipBody)) { DS.SetTypeSpecError(); @@ -5587,8 +5587,17 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, Diag(StartLoc, DiagID) << PrevSpec; } -void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl, - SkipBodyInfo *SkipBody) { +/// ParseEnumBody - Parse a {} enclosed enumerator-list. +/// enumerator-list: +/// enumerator +/// enumerator-list ',' enumerator +/// enumerator: +/// enumeration-constant attributes[opt] +/// enumeration-constant attributes[opt] '=' constant-expression +/// enumeration-constant: +/// identifier +/// +void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // Enter the scope of the enum body and start the definition. ParseScope EnumScope(this, Scope::DeclScope | Scope::EnumScope); Actions.ActOnTagStartDefinition(getCurScope(), EnumDecl); @@ -5646,7 +5655,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl, // Install the enumerator constant into EnumDecl. Decl *EnumConstDecl = Actions.ActOnEnumConstant( getCurScope(), EnumDecl, LastEnumConstDecl, IdentLoc, Ident, attrs, - EqualLoc, AssignedVal.get(), SkipBody); + EqualLoc, AssignedVal.get()); EnumAvailabilityDiags.back().done(); EnumConstantDecls.push_back(EnumConstDecl); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 473131ba8f4d2..094921fbc0a92 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -19240,8 +19240,7 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, // ensure the decl passes the structural compatibility check in // C11 6.2.7/1 (or 6.1.2.6/1 in C89). NamedDecl *Hidden = nullptr; - if (SkipBody && - (!hasVisibleDefinition(Def, &Hidden) || getLangOpts().C23)) { + if (SkipBody && !hasVisibleDefinition(Def, &Hidden)) { // There is a definition of this tag, but it is not visible. We // explicitly make use of C++'s one definition rule here, and // assume that this definition is identical to the hidden one @@ -19254,8 +19253,6 @@ Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SkipBody->CheckSameAsPrevious = true; SkipBody->New = createTagFromNewDecl(); SkipBody->Previous = Def; - - ProcessDeclAttributeList(S, SkipBody->New, Attrs); return Def; } else { SkipBody->ShouldSkip = true; @@ -21294,8 +21291,7 @@ SkipBodyInfo Sema::shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, const ParsedAttributesView &Attrs, - SourceLocation EqualLoc, Expr *Val, - SkipBodyInfo *SkipBody) { + SourceLocation EqualLoc, Expr *Val) { EnumDecl *TheEnumDecl = cast(theEnumDecl); EnumConstantDecl *LastEnumConst = cast_or_null(lastEnumConst); @@ -21332,7 +21328,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, if (!New) return nullptr; - if (PrevDecl && (!SkipBody || !SkipBody->CheckSameAsPrevious)) { + if (PrevDecl) { if (!TheEnumDecl->isScoped() && isa(PrevDecl)) { // Check for other kinds of shadowing not already handled. CheckShadow(New, PrevDecl, R); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 59d6d185575dc..4a308811c11f5 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -10158,10 +10158,10 @@ bool Sema::hasStructuralCompatLayout(Decl *D, Decl *Suggested) { // FIXME: Add a specific mode for C11 6.2.7/1 in StructuralEquivalenceContext // and isolate from other C++ specific checks. StructuralEquivalenceContext Ctx( - getLangOpts(), D->getASTContext(), Suggested->getASTContext(), - NonEquivalentDecls, StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, /*Complain=*/true, - /*ErrorOnTagTypeMismatch=*/true); + D->getASTContext(), Suggested->getASTContext(), NonEquivalentDecls, + StructuralEquivalenceKind::Default, + false /*StrictTypeSpelling*/, true /*Complain*/, + true /*ErrorOnTagTypeMismatch*/); return Ctx.IsEquivalent(D, Suggested); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 086976d72a784..b719396cc60eb 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -10547,7 +10547,7 @@ void ASTReader::finishPendingActions() { PendingObjCExtensionIvarRedeclarations.back().second; StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls; StructuralEquivalenceContext Ctx( - ContextObj->getLangOpts(), ExtensionsPair.first->getASTContext(), + ExtensionsPair.first->getASTContext(), ExtensionsPair.second->getASTContext(), NonEquivalentDecls, StructuralEquivalenceKind::Default, /*StrictTypeSpelling =*/false, /*Complain =*/false, diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index ce51ba9fec246..2c50a45a1202a 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -4561,12 +4561,11 @@ namespace { Reader.getOwningModuleFile(Cat)) { StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls; StructuralEquivalenceContext Ctx( - Reader.getContext().getLangOpts(), Cat->getASTContext(), - Existing->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, - /*Complain=*/false, - /*ErrorOnTagTypeMismatch=*/true); + Cat->getASTContext(), Existing->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, + /*StrictTypeSpelling =*/false, + /*Complain =*/false, + /*ErrorOnTagTypeMismatch =*/true); if (!Ctx.IsEquivalent(Cat, Existing)) { // Warn only if the categories with the same name are different. Reader.Diag(Cat->getLocation(), diag::warn_dup_category_def) diff --git a/clang/test/ASTMerge/enum/Inputs/enum3.c b/clang/test/ASTMerge/enum/Inputs/enum3.c deleted file mode 100644 index 32ad5366434ac..0000000000000 --- a/clang/test/ASTMerge/enum/Inputs/enum3.c +++ /dev/null @@ -1,14 +0,0 @@ -// [C23] missing underlying types -enum E1 : int { - E1Enumerator1 -}; - -enum E2 { - E2Enumerator1 -}; - -// [C23] Incompatible underlying types -enum E3 : long { - E3Enumerator1 -}; - diff --git a/clang/test/ASTMerge/enum/Inputs/enum4.c b/clang/test/ASTMerge/enum/Inputs/enum4.c deleted file mode 100644 index 15f5c603c7abb..0000000000000 --- a/clang/test/ASTMerge/enum/Inputs/enum4.c +++ /dev/null @@ -1,14 +0,0 @@ -// [C23] missing underlying types -enum E1 { - E1Enumerator1 -}; - -enum E2 : int { - E2Enumerator1 -}; - -// [C23] Incompatible underlying types -enum E3 : short { - E3Enumerator1 -}; - diff --git a/clang/test/ASTMerge/enum/test2.c b/clang/test/ASTMerge/enum/test2.c deleted file mode 100644 index bdd8b13ee4c21..0000000000000 --- a/clang/test/ASTMerge/enum/test2.c +++ /dev/null @@ -1,14 +0,0 @@ -// RUN: %clang_cc1 -std=c23 -emit-pch -o %t.1.ast %S/Inputs/enum3.c -// RUN: %clang_cc1 -std=c23 -emit-pch -o %t.2.ast %S/Inputs/enum4.c -// RUN: %clang_cc1 -std=c23 -ast-merge %t.1.ast -ast-merge %t.2.ast -fsyntax-only %s 2>&1 | FileCheck %s - -// CHECK: enum3.c:2:6: warning: type 'enum E1' has incompatible definitions in different translation units -// CHECK: enum4.c:2:6: note: enumeration 'E1' missing fixed underlying type here -// CHECK: enum3.c:2:6: note: enumeration 'E1' has fixed underlying type here -// CHECK: enum3.c:6:6: warning: type 'enum E2' has incompatible definitions in different translation units -// CHECK: enum4.c:6:6: note: enumeration 'E2' has fixed underlying type here -// CHECK: enum3.c:6:6: note: enumeration 'E2' missing fixed underlying type here -// CHECK: enum3.c:11:6: warning: type 'enum E3' has incompatible definitions in different translation units -// CHECK: enum3.c:11:6: note: enumeration 'E3' declared with incompatible fixed underlying types ('long' vs. 'short') -// CHECK: 3 warnings generated - diff --git a/clang/test/ASTMerge/struct/test.c b/clang/test/ASTMerge/struct/test.c index 10ea753b142bd..4dfa74737eed8 100644 --- a/clang/test/ASTMerge/struct/test.c +++ b/clang/test/ASTMerge/struct/test.c @@ -21,16 +21,6 @@ // CHECK: struct1.c:27:8: note: no corresponding field here // CHECK: struct2.c:24:31: warning: 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' has bit-width 8 here -// CHECK: struct2.c:30:33: note: field 'j' is not a bit-field -// CHECK: struct2.c:30:38: warning: 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' has bit-width 8 here -// CHECK: struct2.c:33:33: note: bit-field 'j' has bit-width 16 here -// CHECK: struct2.c:33:43: warning: 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: struct1.c:56:10: warning: type 'struct DeeperError' has incompatible definitions in different translation units // CHECK: struct1.c:56:35: note: field 'f' has type 'int' here // CHECK: struct2.c:53:37: note: field 'f' has type 'float' here @@ -52,4 +42,4 @@ // CHECK: struct2.c:129:9: note: field 'S' has type 'struct (unnamed struct at [[PATH_TO_INPUTS]]struct2.c:127:7)' here // CHECK: struct2.c:138:3: warning: external variable 'x16' declared with incompatible types in different translation units ('struct DeepUnnamedError' vs. 'struct DeepUnnamedError') // CHECK: struct1.c:141:3: note: declared here with type 'struct DeepUnnamedError' -// CHECK: 20 warnings generated +// CHECK: 17 warnings generated diff --git a/clang/test/C/C23/n3037.c b/clang/test/C/C23/n3037.c deleted file mode 100644 index 1ef26b0b20a7c..0000000000000 --- a/clang/test/C/C23/n3037.c +++ /dev/null @@ -1,517 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c23 -pedantic -Wall -Wno-comment -verify=both,c23 %s -// RUN: %clang_cc1 -fsyntax-only -std=c17 -pedantic -Wall -Wno-comment -Wno-c23-extensions -verify=both,c17 %s - -/* WG14 N3037: Clang 21 - * Improved tag compatibility - * - * Identical tag types have always been compatible across TU boundaries. This - * paper made identical tag types compatible within the same TU. - */ - -struct foo { int a; } p; - -void baz(struct foo f); // c17-note {{passing argument to parameter 'f' here}} - -void bar(void) { - struct foo { int a; } q = {}; - baz(q); // c17-error {{passing 'struct foo' to parameter of incompatible type 'struct foo'}} -} - -#define PRODUCT(A ,B) struct prod { A a; B b; } // expected-note 2 {{expanded from macro 'PRODUCT'}} -#define SUM(A, B) struct sum { _Bool flag; union { A a; B b; }; } // expected-note 2 {{expanded from macro 'SUM'}} - -void func1(PRODUCT(int, SUM(float, double)) x); // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \ - c17-warning {{declaration of 'struct sum' will not be visible outside of this function}} \ - c17-note {{passing argument to parameter 'x' here}} -void func2(PRODUCT(int, SUM(float, double)) y) { // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \ - c17-warning {{declaration of 'struct sum' will not be visible outside of this function}} - func1(y); // c17-error {{passing 'struct prod' to parameter of incompatible type 'struct prod'}} -} - -struct foop { struct { int x; }; }; // c17-note {{previous definition is here}} -struct foop { struct { int x; }; }; // c17-error {{redefinition of 'foop'}} -// Test the field lookup compatibility isn't sufficient, the structure of types should be compatible. -struct AnonymousStructNotMatchingFields { // c17-note {{previous definition is here}} - struct { // c23-note {{field has name '' here}} - int x; - }; -}; -struct AnonymousStructNotMatchingFields { // c23-error {{type 'struct AnonymousStructNotMatchingFields' has incompatible definitions}} \ - c17-error {{redefinition of 'AnonymousStructNotMatchingFields'}} - int x; // c23-note {{field has name 'x' here}} -}; - -union barp { int x; float y; }; // c17-note {{previous definition is here}} -union barp { int x; float y; }; // c17-error {{redefinition of 'barp'}} -typedef struct q { int x; } q_t; // c17-note 2 {{previous definition is here}} -typedef struct q { int x; } q_t; // c17-error {{redefinition of 'q'}} \ - c17-error-re {{typedef redefinition with different types ('struct (unnamed struct at {{.*}})' vs 'struct q')}} -typedef struct { int x; } untagged_q_t; // both-note {{previous definition is here}} -typedef struct { int x; } untagged_q_t; // both-error {{typedef redefinition with different types}} -void func3(void) { - struct S { int x; }; // c17-note {{previous definition is here}} - struct T { struct S s; }; // c17-note {{previous definition is here}} - struct S { int x; }; // c17-error {{redefinition of 'S'}} - struct T { struct S s; }; // c17-error {{redefinition of 'T'}} -} - -struct food { int (*p)[3]; }; // c23-note {{field 'p' has type 'int (*)[3]' here}} \ - c17-note {{previous definition is here}} -struct food { int (*p)[]; }; // c23-error {{type 'struct food' has incompatible definitions}} \ - c23-note {{field 'p' has type 'int (*)[]' here}} \ - c17-error {{redefinition of 'food'}} -union bard { int x; float y; }; // c23-note {{field has name 'x' here}} \ - c17-note {{previous definition is here}} -union bard { int z; float y; }; // c23-error {{type 'union bard' has incompatible definitions}} \ - c23-note {{field has name 'z' here}} \ - c17-error {{redefinition of 'bard'}} -union purr { int x; float y; }; // c23-note {{field has name 'x' here}} \ - c17-note {{previous definition is here}} -union purr { float y; int x; }; // c23-error {{type 'union purr' has incompatible definitions}} \ - c23-note {{field has name 'y' here}} \ - c17-error {{redefinition of 'purr'}} - -// The presence of an attribute makes two types not compatible. -struct [[gnu::packed]] attr_test { // c17-note {{previous definition is here}} \ - c23-note {{attribute 'gnu::packed' here}} - int x; -}; - -struct attr_test { // c17-error {{redefinition of 'attr_test'}} \ - c23-error {{type 'struct attr_test' has an attribute which currently causes the types to be treated as though they are incompatible}} - int x; -}; - -struct attr_test_2 { // c17-note {{previous definition is here}} - int x; -}; - -struct [[gnu::packed]] attr_test_2 { // c17-error {{redefinition of 'attr_test_2'}} \ - c23-error {{type 'struct attr_test_2' has an attribute which currently causes the types to be treated as though they are incompatible}} \ - c23-note {{attribute 'gnu::packed' here}} - int x; -}; - -// This includes the same attribute on both types. -struct [[gnu::packed]] attr_test_3 { // c17-note {{previous definition is here}} \ - c23-note {{attribute 'gnu::packed' here}} - int x; -}; - -struct [[gnu::packed]] attr_test_3 { // c17-error {{redefinition of 'attr_test_3'}} \ - c23-error {{type 'struct attr_test_3' has an attribute which currently causes the types to be treated as though they are incompatible}} \ - c23-note {{attribute 'gnu::packed' here}} - int x; -}; - -// Everything which applies to the tag itself also applies to fields. -struct field_attr_test_1 { // c17-note {{previous definition is here}} - int x; - [[gnu::packed]] int y; // c23-note {{attribute 'gnu::packed' here}} -}; - -struct field_attr_test_1 { // c17-error {{redefinition of 'field_attr_test_1'}} \ - c23-error {{type 'struct field_attr_test_1' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} - int x; - int y; -}; - -struct field_attr_test_2 { // c17-note {{previous definition is here}} - [[gnu::packed]] int x; // c23-note {{attribute 'gnu::packed' here}} - int y; -}; - -struct field_attr_test_2 { // c17-error {{redefinition of 'field_attr_test_2'}} \ - c23-error {{type 'struct field_attr_test_2' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} - int x; - int y; -}; - -struct field_attr_test_3 { // c17-note {{previous definition is here}} - [[gnu::packed]] int x; // c23-note {{attribute 'gnu::packed' here}} - int y; -}; - -struct field_attr_test_3 { // c17-error {{redefinition of 'field_attr_test_3'}} \ - c23-error {{type 'struct field_attr_test_3' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} - int x [[gnu::packed]]; // c23-note {{attribute 'gnu::packed' here}} - int y; -}; - -// Show that equivalent field types are not an issue. -typedef int typedef_of_type_int; -struct equivalent_field_types { // c17-note {{previous definition is here}} - int x; -}; - -struct equivalent_field_types { // c17-error {{redefinition of 'equivalent_field_types'}} - typedef_of_type_int x; -}; - -struct quals_matter { // c17-note {{previous definition is here}} - int x; // c23-note {{field 'x' has type 'int' here}} -}; - -struct quals_matter { // c17-error {{redefinition of 'quals_matter'}} \ - c23-error {{type 'struct quals_matter' has incompatible definitions}} - const int x; // c23-note {{field 'x' has type 'const int' here}} -}; - -struct qual_order_does_not_matter { // c17-note {{previous definition is here}} - const volatile int x; -}; - -struct qual_order_does_not_matter { // c17-error {{redefinition of 'qual_order_does_not_matter'}} - volatile const int x; -}; - -struct nested { // both-note {{previous definition is here}} - int x; - struct nested { // both-error {{nested redefinition of 'nested'}} - int x; - }; -}; - -// Show that bit-field order does matter, including anonymous bit-fields. -struct bit_field_1 { // c17-note 2 {{previous definition is here}} - int a : 1; - int : 0; // c23-note {{field has name '' here}} - int b : 1; -}; - -struct bit_field_1 { // c17-error {{redefinition of 'bit_field_1'}} - int a : 1; - int : 0; - int b : 1; -}; - -struct bit_field_1 { // c17-error {{redefinition of 'bit_field_1'}} \ - c23-error {{type 'struct bit_field_1' has incompatible definitions}} - int a : 1; - int b : 1; // c23-note {{field has name 'b' here}} -}; - -struct bit_field_2 { // c17-note {{previous definition is here}} - int a : 1; - int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}} -}; - -struct bit_field_2 { // c17-error {{redefinition of 'bit_field_2'}} \ - c23-error {{type 'struct bit_field_2' has incompatible definitions}} - int a : 1; - int b : 2; // c23-note {{bit-field 'b' has bit-width 2 here}} -}; - -// Test a bit-field with an attribute. -struct bit_field_3 { // c17-note {{previous definition is here}} - int a : 1; - int b : 1; -}; - -struct bit_field_3 { // c17-error {{redefinition of 'bit_field_3'}} \ - c23-error {{type 'struct bit_field_3' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} - int a : 1; - [[deprecated]] int b : 1; // c23-note {{attribute 'deprecated' here}} -}; - -struct bit_field_4 { // c17-note {{previous definition is here}} - int a : 1; - int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}} -}; - -struct bit_field_4 { // c17-error {{redefinition of 'bit_field_4'}} \ - c23-error {{type 'struct bit_field_4' has incompatible definitions}} - int a : 1; - int b; // c23-note {{field 'b' is not a bit-field}} -}; - -struct bit_field_5 { // c17-note {{previous definition is here}} - int a : 1; - int b; // c23-note {{field 'b' is not a bit-field}} -}; - -struct bit_field_5 { // c17-error {{redefinition of 'bit_field_5'}} \ - c23-error {{type 'struct bit_field_5' has incompatible definitions}} - int a : 1; - int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}} -}; - -struct bit_field_6 { // c17-note {{previous definition is here}} - int a : 2; -}; - -struct bit_field_6 { // c17-error {{redefinition of 'bit_field_6'}} - int a : 1 + 1; -}; - -enum E { A }; // c17-note 2 {{previous definition is here}} -enum E { A }; // c17-error {{redefinition of 'E'}} \ - c17-error {{redefinition of enumerator 'A'}} - -enum Q { D = 1 }; // c17-note 2 {{previous definition is here}} -enum Q { D = D }; // c17-error {{redefinition of 'Q'}} \ - c17-error {{redefinition of enumerator 'D'}} - -// The order of the enumeration constants does not matter, only the values do. -enum X { B = 1, C = 1 + 1 }; // c17-note 3 {{previous definition is here}} -enum X { C = 2, B = 1 }; // c17-error {{redefinition of 'X'}} \ - c17-error {{redefinition of enumerator 'C'}} \ - c17-error {{redefinition of enumerator 'B'}} - -// Different enumeration constants. -enum Y { YA = 1, YB = 2 }; // c23-note {{enumerator 'YB' with value 2 here}} \ - c17-note 3 {{previous definition is here}} -enum Y { YA = 1, YB = 3 }; // c23-error {{type 'enum Y' has incompatible definitions}} \ - c23-note {{enumerator 'YB' with value 3 here}} \ - c17-error {{redefinition of 'Y'}} \ - c17-error {{redefinition of enumerator 'YA'}} \ - c17-error {{redefinition of enumerator 'YB'}} - -// Different enumeration names, same named constants. -enum Z1 { ZC = 1 }; // both-note {{previous definition is here}} -enum Z2 { ZC = 1 }; // both-error {{redefinition of enumerator 'ZC'}} - -// Test attributes on the enumeration and enumerators. -enum [[deprecated]] enum_attr_test_1 { // c17-note {{previous definition is here}} \ - c23-note {{attribute 'deprecated' here}} - EAT1 [[deprecated]] // c17-note {{previous definition is here}} \ - c23-note {{attribute 'deprecated' here}} -}; - -enum [[deprecated]] enum_attr_test_1 { // c17-error {{redefinition of 'enum_attr_test_1'}} \ - c23-error {{type 'enum enum_attr_test_1' has an attribute which currently causes the types to be treated as though they are incompatible}} \ - c23-error {{type 'enum enum_attr_test_1' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} \ - c23-note {{attribute 'deprecated' here}} - EAT1 [[deprecated]] // c17-error {{redefinition of enumerator 'EAT1'}} \ - c23-note {{attribute 'deprecated' here}} -}; - -enum [[deprecated]] enum_attr_test_2 { // c17-note {{previous definition is here}} \ - c23-note {{attribute 'deprecated' here}} - EAT2 // c17-note {{previous definition is here}} -}; - -enum enum_attr_test_2 { // c17-error {{redefinition of 'enum_attr_test_2'}} \ - c23-error {{type 'enum enum_attr_test_2' has an attribute which currently causes the types to be treated as though they are incompatible}} - EAT2 // c17-error {{redefinition of enumerator 'EAT2'}} -}; - -enum enum_attr_test_3 { // c17-note {{previous definition is here}} - EAT3 // c17-note {{previous definition is here}} -}; - -enum [[deprecated]] enum_attr_test_3 { // c17-error {{redefinition of 'enum_attr_test_3'}} \ - c23-error {{type 'enum enum_attr_test_3' has an attribute which currently causes the types to be treated as though they are incompatible}} \ - c23-note {{attribute 'deprecated' here}} - EAT3 // c17-error {{redefinition of enumerator 'EAT3'}} -}; - -// You cannot declare one with a fixed underlying type and the other without a -// fixed underlying type, or a different underlying type. However, it's worth -// showing that the underlying type doesn't change the redefinition behavior. -enum fixed_test_1 : int { FT1 }; // c17-note 2 {{previous definition is here}} -enum fixed_test_1 : int { FT1 }; // c17-error {{redefinition of 'fixed_test_1'}} \ - c17-error {{redefinition of enumerator 'FT1'}} - -enum fixed_test_2 : int { FT2 }; // c17-note 2 {{previous definition is here}} -enum fixed_test_2 : typedef_of_type_int { FT2 }; // c17-error {{redefinition of 'fixed_test_2'}} \ - c17-error {{redefinition of enumerator 'FT2'}} - -// Test more bizarre situations in terms of where the type is declared. This -// has always been allowed. -struct declared_funny_1 { int x; } -declared_funny_func(struct declared_funny_1 { int x; } arg) { // c17-warning {{declaration of 'struct declared_funny_1' will not be visible outside of this function}} - return declared_funny_func((__typeof__(arg)){ 0 }); -} - -// However, this is new. -struct Outer { - struct Inner { // c17-note {{previous definition is here}} - int x; - } i; - - enum InnerEnum { // c17-note {{previous definition is here}} - IE1 // c17-note {{previous definition is here}} - } j; -}; - -struct Inner { // c17-error {{redefinition of 'Inner'}} - int x; -}; - -enum InnerEnum { // c17-error {{redefinition of 'InnerEnum'}} - IE1 // c17-error {{redefinition of enumerator 'IE1'}} -}; - -void hidden(void) { - struct hidden_struct { int x; }; -} - -struct hidden_struct { // This is fine because the previous declaration is not visible. - int y; - int z; -}; - -struct array { int y; int x[]; }; // c17-note {{previous definition is here}} \ - c23-note {{field 'x' has type 'int[]' here}} -struct array { int y; int x[0]; }; // c17-error {{redefinition of 'array'}} \ - c23-error {{type 'struct array' has incompatible definitions}} \ - c23-note {{field 'x' has type 'int[0]' here}} \ - both-warning {{zero size arrays are an extension}} - -// So long as the bounds are the same value, everything is fine. They do not -// have to be token equivalent. -struct array_2 { int y; int x[3]; }; // c17-note {{previous definition is here}} -struct array_2 { int y; int x[1 + 1 + 1]; }; // c17-error {{redefinition of 'array_2'}} - -struct alignment { // c17-note {{previous definition is here}} - _Alignas(int) int x; // c23-note {{attribute '_Alignas' here}} -}; - -struct alignment { // c17-error {{redefinition of 'alignment'}} \ - c23-error {{type 'struct alignment' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} - int x; -}; - -// Both structures need to have a tag in order to be compatible within the same -// translation unit. -struct {int i;} nontag; -struct tag {int i;} tagged; // c17-note 2 {{previous definition is here}} - -_Static_assert(1 == _Generic(tagged, struct tag {int i;}:1, default:0)); // c17-error {{redefinition of 'tag'}} \ - c17-error {{static assertion failed}} -_Static_assert(0 == _Generic(tagged, struct {int i;}:1, default:0)); -_Static_assert(0 == _Generic(nontag, struct tag {int i;}:1, default:0)); // c17-error {{redefinition of 'tag'}} -// That means these two structures are not actually compatible; see GH141724. -_Static_assert(0 == _Generic(nontag, struct {int i;}:1, default:0)); - -// Also test the behavior within a function (so the declaration context is not -// at the translation unit level). -void nontag_func_test(void) { - struct { int i; } test; - _Static_assert(0 == _Generic(test, struct { int i; } : 1, default : 0)); -} - -// Same kind of test, but this time for a declaration in the parameter list. -void nontag_param_test(struct { int i; } herp) { - _Static_assert(0 == _Generic(herp, struct { int i; } : 1, default : 0)); -} - -// Same kind of test, but demonstrating that these still aren't compatible. -void nontag_both_in_params(struct { int i; } Arg1, struct { int i; } Arg2) { - _Static_assert(0 == _Generic(__typeof__(Arg1), __typeof__(Arg2) : 1, default : 0)); // both-warning {{passing a type argument as the first operand to '_Generic' is a C2y extension}} -} - -struct InnerUnnamedStruct { - struct { - int i; - } untagged; -} inner_unnamed_tagged; -_Static_assert(0 == _Generic(inner_unnamed_tagged.untagged, struct { int i; } : 1, default : 0)); - -struct InnerUnnamedStruct_same { - struct { - int i; - } untagged; -}; -struct InnerUnnamedStruct_differentNaming { - struct { - int i; - } untaggedDifferent; -}; -struct InnerUnnamedStruct_differentShape { - float x; - struct { - int i; - } untagged; - int y; -}; -void compare_unnamed_struct_from_different_outer_type( - struct InnerUnnamedStruct sameOuterType, - struct InnerUnnamedStruct_same matchingType, - struct InnerUnnamedStruct_differentNaming differentFieldName, - struct InnerUnnamedStruct_differentShape differentType) { - inner_unnamed_tagged.untagged = sameOuterType.untagged; - inner_unnamed_tagged.untagged = matchingType.untagged; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}} - inner_unnamed_tagged.untagged = differentFieldName.untaggedDifferent; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}} - inner_unnamed_tagged.untagged = differentType.untagged; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}} -} - -// Test the same thing with enumerations (test for unions is omitted because -// unions and structures are both RecordDecl objects, whereas EnumDecl is not). -enum { E_Untagged1 } nontag_enum; // both-note {{previous definition is here}} -_Static_assert(0 == _Generic(nontag_enum, enum { E_Untagged1 } : 1, default : 0)); // both-error {{redefinition of enumerator 'E_Untagged1'}} - -// Test that enumerations are compatible with their underlying type, but still -// diagnose when "same type" is required rather than merely "compatible type". -enum E1 : int { e1 }; // Fixed underlying type -enum E2 { e2 }; // Unfixed underlying type, defaults to int or unsigned int - -struct GH149965_1 { int h; }; -// This typeof trick is used to get the underlying type of the enumeration in a -// platform agnostic way. -struct GH149965_2 { __typeof__(+(enum E2){}) h; }; -void gh149965(void) { - extern struct GH149965_1 x1; // c17-note {{previous declaration is here}} - extern struct GH149965_2 x2; // c17-note {{previous declaration is here}} - - // Both the structure and the variable declarations are fine because only a - // compatible type is required, not the same type, because the structures are - // declared in different scopes. - struct GH149965_1 { enum E1 h; }; - struct GH149965_2 { enum E2 h; }; - - extern struct GH149965_1 x1; // c17-error {{redeclaration of 'x1'}} - extern struct GH149965_2 x2; // c17-error {{redeclaration of 'x2'}} - - // However, in the same scope, the same type is required, not just compatible - // types. - // FIXME: this should be an error in both C17 and C23 mode. - struct GH149965_3 { int h; }; // c17-note {{previous definition is here}} - struct GH149965_3 { enum E1 h; }; // c17-error {{redefinition of 'GH149965_3'}} - - // For Clang, the composite type after declaration merging is the enumeration - // type rather than an integer type. - enum E1 *eptr; - [[maybe_unused]] __typeof__(x1.h) *ptr = eptr; - enum E2 *eptr2; - [[maybe_unused]] __typeof__(x2.h) *ptr2 = eptr2; -} - -// Test that enumerations with mixed underlying types are properly handled. -enum GH150594_E1 : int { GH150594_Val1 }; -enum GH150594_E2 : int { GH150594_Val2 }; -enum GH150594_E3 { GH150594_Val3 }; -enum GH150594_E4 : int { GH150594_Val4 }; -void GH150594(void) { - extern enum GH150594_E1 Fn1(void); // both-note {{previous declaration is here}} - extern enum GH150594_E2 Fn2(void); // c17-note {{previous declaration is here}} - extern enum GH150594_E3 Fn3(void); // both-note {{previous declaration is here}} - extern enum GH150594_E4 Fn4(void); // both-note {{previous declaration is here}} - enum GH150594_E1 { GH150594_Val1 }; - enum GH150594_E2 : int { GH150594_Val2 }; - enum GH150594_E3 : int { GH150594_Val3 }; - enum GH150594_E4 : short { GH150594_Val4 }; - extern enum GH150594_E1 Fn1(void); // both-error {{conflicting types for 'Fn1'}} - extern enum GH150594_E2 Fn2(void); // c17-error {{conflicting types for 'Fn2'}} - extern enum GH150594_E3 Fn3(void); // both-error {{conflicting types for 'Fn3'}} - extern enum GH150594_E4 Fn4(void); // both-error {{conflicting types for 'Fn4'}} - - // Show that two declarations in the same scope give expected diagnostics. - enum E1 { e1 }; // both-note {{previous declaration is here}} - enum E1 : int { e1 }; // both-error {{enumeration previously declared with nonfixed underlying type}} - - enum E2 : int { e2 }; // both-note {{previous declaration is here}} - enum E2 { e2 }; // both-error {{enumeration previously declared with fixed underlying type}} - - enum E3 : int { e3 }; // both-note {{previous declaration is here}} - enum E3 : short { e3 }; // both-error {{enumeration redeclared with different underlying type 'short' (was 'int')}} - - typedef short foo; - enum E4 : foo { e4 }; // c17-note 2 {{previous definition is here}} - enum E4 : short { e4 }; // c17-error {{redefinition of 'E4'}} \ - c17-error {{redefinition of enumerator 'e4'}} - - enum E5 : foo { e5 }; // both-note {{previous declaration is here}} - enum E5 : int { e5 }; // both-error {{enumeration redeclared with different underlying type 'int' (was 'foo' (aka 'short'))}} -} diff --git a/clang/test/C/C23/n3037_1.c b/clang/test/C/C23/n3037_1.c deleted file mode 100644 index e494eaf5828aa..0000000000000 --- a/clang/test/C/C23/n3037_1.c +++ /dev/null @@ -1,88 +0,0 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 -// RUN: %clang_cc1 -std=c23 -Wno-error=odr -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s - -// This tests the codegen behavior of redefined tag types to ensure the -// generated code looks reasonable. - -enum E { - One = 1, - Zero = 0, - Two = 2 -}; - -struct S { - int x; - int y; -}; - -struct S func(struct S s, enum E e); - -struct S { - int x, y; -} what(); - -// CHECK-LABEL: define dso_local i64 @func( -// CHECK-SAME: i64 [[S_COERCE:%.*]], i32 noundef [[E:%.*]]) #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[RETVAL:%.*]] = alloca [[STRUCT_S:%.*]], align 4 -// CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_S]], align 4 -// CHECK-NEXT: [[E_ADDR:%.*]] = alloca i32, align 4 -// CHECK-NEXT: store i64 [[S_COERCE]], ptr [[S]], align 4 -// CHECK-NEXT: store i32 [[E]], ptr [[E_ADDR]], align 4 -// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[E_ADDR]], align 4 -// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_S]], ptr [[S]], i32 0, i32 0 -// CHECK-NEXT: store i32 [[TMP0]], ptr [[X]], align 4 -// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[RETVAL]], ptr align 4 [[S]], i64 8, i1 false) -// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[RETVAL]], align 4 -// CHECK-NEXT: ret i64 [[TMP1]] -// -struct S func(struct S s, enum E e) { - s.x = (int)e; - return s; -} - -enum E { - Zero, - One, - Two -}; - -// Ensure that ignoring the incompatibility due to attributes does not cause a -// crash. Note, this is undefined behavior in Clang until we implement -// attribute structural compatibility logic, so this is not intended to verify -// any particular behavior beyond "don't crash." -struct T { - _Alignas(double) int x; -}; - -// CHECK-LABEL: define dso_local i32 @foo( -// CHECK-SAME: i32 [[T_COERCE:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[T:%.*]] = alloca [[STRUCT_T:%.*]], align 8 -// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_T]], ptr [[T]], i32 0, i32 0 -// CHECK-NEXT: store i32 [[T_COERCE]], ptr [[COERCE_DIVE]], align 8 -// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_T]], ptr [[T]], i32 0, i32 0 -// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X]], align 8 -// CHECK-NEXT: ret i32 [[TMP0]] -// -int foo(struct T t) { - return t.x; -} - -struct T { - int x; -}; - -// CHECK-LABEL: define dso_local i32 @bar( -// CHECK-SAME: i32 [[T_COERCE:%.*]]) #[[ATTR0]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[T:%.*]] = alloca [[STRUCT_T:%.*]], align 8 -// CHECK-NEXT: [[COERCE_DIVE:%.*]] = getelementptr inbounds nuw [[STRUCT_T]], ptr [[T]], i32 0, i32 0 -// CHECK-NEXT: store i32 [[T_COERCE]], ptr [[COERCE_DIVE]], align 8 -// CHECK-NEXT: [[X:%.*]] = getelementptr inbounds nuw [[STRUCT_T]], ptr [[T]], i32 0, i32 0 -// CHECK-NEXT: [[TMP0:%.*]] = load i32, ptr [[X]], align 8 -// CHECK-NEXT: ret i32 [[TMP0]] -// -int bar(struct T t) { - return t.x; -} diff --git a/clang/test/C/drs/dr1xx.c b/clang/test/C/drs/dr1xx.c index 055a30cc9c4b8..2bf68dd82cdde 100644 --- a/clang/test/C/drs/dr1xx.c +++ b/clang/test/C/drs/dr1xx.c @@ -1,8 +1,8 @@ -/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only,untilc23 -pedantic -Wno-c11-extensions %s - RUN: %clang_cc1 -std=c99 -fsyntax-only -verify=expected,c99untilc2x,untilc23 -pedantic -Wno-c11-extensions %s - RUN: %clang_cc1 -std=c11 -fsyntax-only -verify=expected,c99untilc2x,untilc23 -pedantic %s - RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=expected,c99untilc2x,untilc23 -pedantic %s - RUN: %clang_cc1 -std=c23 -fsyntax-only -verify=expected,c2xandup -pedantic %s +/* RUN: %clang_cc1 -std=c89 -fsyntax-only -verify=expected,c89only -pedantic -Wno-c11-extensions %s + RUN: %clang_cc1 -std=c99 -fsyntax-only -verify=expected,c99untilc2x -pedantic -Wno-c11-extensions %s + RUN: %clang_cc1 -std=c11 -fsyntax-only -verify=expected,c99untilc2x -pedantic %s + RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=expected,c99untilc2x -pedantic %s + RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=expected,c2xandup -pedantic %s */ /* The following are DRs which do not require tests to demonstrate @@ -87,15 +87,15 @@ void dr101_caller(void) { * Tag redeclaration constraints */ void dr102(void) { - struct S { int member; }; /* untilc23-note {{previous definition is here}} */ - struct S { int member; }; /* untilc23-error {{redefinition of 'S'}} */ + struct S { int member; }; /* expected-note {{previous definition is here}} */ + struct S { int member; }; /* expected-error {{redefinition of 'S'}} */ - union U { int member; }; /* untilc23-note {{previous definition is here}} */ - union U { int member; }; /* untilc23-error {{redefinition of 'U'}} */ + union U { int member; }; /* expected-note {{previous definition is here}} */ + union U { int member; }; /* expected-error {{redefinition of 'U'}} */ - enum E { member }; /* untilc23-note 2{{previous definition is here}} */ - enum E { member }; /* untilc23-error {{redefinition of 'E'}} - untilc23-error {{redefinition of enumerator 'member'}} */ + enum E { member }; /* expected-note 2{{previous definition is here}} */ + enum E { member }; /* expected-error {{redefinition of 'E'}} + expected-error {{redefinition of enumerator 'member'}} */ } /* WG14 DR103: yes diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp index ef82afaf3f8dc..7cf52df9b14d0 100644 --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -137,15 +137,13 @@ struct StructuralEquivalenceTest : ::testing::Test { StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01; StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10; StructuralEquivalenceContext Ctx01( - D0->getLangOpts(), D0->getASTContext(), D1->getASTContext(), - NonEquivalentDecls01, StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, + D0->getASTContext(), D1->getASTContext(), NonEquivalentDecls01, + StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, IgnoreTemplateParmDepth); StructuralEquivalenceContext Ctx10( - D1->getLangOpts(), D1->getASTContext(), D0->getASTContext(), - NonEquivalentDecls10, StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, + D1->getASTContext(), D0->getASTContext(), NonEquivalentDecls10, + StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, IgnoreTemplateParmDepth); bool Eq01 = Ctx01.IsEquivalent(D0, D1); @@ -157,16 +155,12 @@ struct StructuralEquivalenceTest : ::testing::Test { bool testStructuralMatch(StmtWithASTContext S0, StmtWithASTContext S1) { StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls01; StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls10; - StructuralEquivalenceContext Ctx01(S0.Context->getLangOpts(), *S0.Context, - *S1.Context, NonEquivalentDecls01, - StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, - /*Complain=*/false); - StructuralEquivalenceContext Ctx10(S1.Context->getLangOpts(), *S1.Context, - *S0.Context, NonEquivalentDecls10, - StructuralEquivalenceKind::Default, - /*StrictTypeSpelling=*/false, - /*Complain=*/false); + StructuralEquivalenceContext Ctx01( + *S0.Context, *S1.Context, NonEquivalentDecls01, + StructuralEquivalenceKind::Default, false, false); + StructuralEquivalenceContext Ctx10( + *S1.Context, *S0.Context, NonEquivalentDecls10, + StructuralEquivalenceKind::Default, false, false); bool Eq01 = Ctx01.IsEquivalent(S0.S, S1.S); bool Eq10 = Ctx10.IsEquivalent(S1.S, S0.S); EXPECT_EQ(Eq01, Eq10); @@ -1832,10 +1826,8 @@ TEST_F(StructuralEquivalenceCacheTest, SimpleNonEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto X = findDeclPair(TU, functionDecl(hasName("x"))); EXPECT_FALSE(Ctx.IsEquivalent(X.first, X.second)); @@ -1857,10 +1849,8 @@ TEST_F(StructuralEquivalenceCacheTest, ReturnStmtNonEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto X = findDeclPair(TU, functionDecl(hasName("x"))); EXPECT_FALSE(Ctx.IsEquivalent(X.first->getBody(), X.second->getBody())); @@ -1878,10 +1868,8 @@ TEST_F(StructuralEquivalenceCacheTest, VarDeclNoEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto Var = findDeclPair(TU, varDecl()); EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second)); @@ -1898,10 +1886,8 @@ TEST_F(StructuralEquivalenceCacheTest, VarDeclWithDifferentStorageClassNoEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto Var = findDeclPair(TU, varDecl()); EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second)); @@ -1927,10 +1913,8 @@ TEST_F(StructuralEquivalenceCacheTest, Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto NTTP = findDeclPair( TU, nonTypeTemplateParmDecl(hasName("T"))); @@ -1948,10 +1932,8 @@ TEST_F(StructuralEquivalenceCacheTest, VarDeclWithInitNoEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto Var = findDeclPair(TU, varDecl()); EXPECT_FALSE(Ctx.IsEquivalent(Var.first, Var.second)); @@ -1982,10 +1964,8 @@ TEST_F(StructuralEquivalenceCacheTest, SpecialNonEq) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto C = findDeclPair( TU, cxxRecordDecl(hasName("C"), unless(isImplicit()))); @@ -2023,10 +2003,8 @@ TEST_F(StructuralEquivalenceCacheTest, Cycle) { Lang_CXX03); StructuralEquivalenceContext Ctx( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false); auto C = findDeclPair( TU, cxxRecordDecl(hasName("C"), unless(isImplicit()))); @@ -2088,11 +2066,9 @@ TEST_F(StructuralEquivalenceCacheTest, TemplateParmDepth) { ASSERT_EQ(D1->getTemplateDepth(), 0u); StructuralEquivalenceContext Ctx_NoIgnoreTemplateParmDepth( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, - /*IgnoreTemplateParmDepth=*/false); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false, + false, false); EXPECT_FALSE(Ctx_NoIgnoreTemplateParmDepth.IsEquivalent(D0, D1)); @@ -2104,11 +2080,9 @@ TEST_F(StructuralEquivalenceCacheTest, TemplateParmDepth) { EXPECT_FALSE(isInNonEqCache(std::make_pair(NonEqDecl0, NonEqDecl1), true)); StructuralEquivalenceContext Ctx_IgnoreTemplateParmDepth( - get<0>(TU)->getASTContext().getLangOpts(), get<0>(TU)->getASTContext(), - get<1>(TU)->getASTContext(), NonEquivalentDecls, - StructuralEquivalenceKind::Default, /*StrictTypeSpelling=*/false, - /*Complain=*/false, /*ErrorOnTagTypeMismatch=*/false, - /*IgnoreTemplateParmDepth=*/true); + get<0>(TU)->getASTContext(), get<1>(TU)->getASTContext(), + NonEquivalentDecls, StructuralEquivalenceKind::Default, false, false, + false, true); EXPECT_TRUE(Ctx_IgnoreTemplateParmDepth.IsEquivalent(D0, D1)); diff --git a/clang/www/c_status.html b/clang/www/c_status.html index dcff2fc2b1a3e..80402e6b14447 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -899,7 +899,7 @@

C23 implementation status

Improved tag compatibility N3037 - Clang 21 + No #embed