Skip to content

Commit 3016c5e

Browse files
committed
[C23] Fix treating unnamed records nested in different types as compatible.
Don't compare and accept unnamed records from different types only because they are defined in `RecordDecl` `DeclContext`. During recursive comparison don't reject unnamed records defined inside other ordered containers like Objective-C classes. rdar://161592007
1 parent 2342f7a commit 3016c5e

File tree

3 files changed

+34
-14
lines changed

3 files changed

+34
-14
lines changed

clang/lib/AST/ASTContext.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11581,6 +11581,12 @@ QualType ASTContext::mergeTagDefinitions(QualType LHS, QualType RHS) {
1158111581
if (LangOpts.CPlusPlus || !LangOpts.C23)
1158211582
return {};
1158311583

11584+
// Nameless tags are comparable only within outer definitions. At the top
11585+
// level they are not comparable.
11586+
const TagDecl *LTagD = LHS->castAsTagDecl(), *RTagD = RHS->castAsTagDecl();
11587+
if (!LTagD->getIdentifier() || !RTagD->getIdentifier())
11588+
return {};
11589+
1158411590
// C23, on the other hand, requires the members to be "the same enough", so
1158511591
// we use a structural equivalence check.
1158611592
StructuralEquivalenceContext::NonEquivalentDeclSet NonEquivalentDecls;

clang/lib/AST/ASTStructuralEquivalence.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,19 +1763,6 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
17631763
// another anonymous structure or union, respectively, if their members
17641764
// fulfill the preceding requirements. ... Otherwise, the structure, union,
17651765
// or enumerated types are incompatible.
1766-
1767-
// Note: "the same tag" refers to the identifier for the structure; two
1768-
// structures without names are not compatible within a TU. In C23, if either
1769-
// declaration has no name, they're not equivalent. However, the paragraph
1770-
// after the bulleted list goes on to talk about compatibility of anonymous
1771-
// structure and union members, so this prohibition only applies to top-level
1772-
// declarations; if either declaration is not a member, they cannot be
1773-
// compatible.
1774-
if (Context.LangOpts.C23 && (!D1->getIdentifier() || !D2->getIdentifier()) &&
1775-
(!D1->getDeclContext()->isRecord() || !D2->getDeclContext()->isRecord()))
1776-
return false;
1777-
1778-
// Otherwise, check the names for equivalence.
17791766
if (!NameIsStructurallyEquivalent(*D1, *D2))
17801767
return false;
17811768

clang/test/C/C23/n3037.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,9 +407,36 @@ struct InnerUnnamedStruct {
407407
int i;
408408
} untagged;
409409
} inner_unnamed_tagged;
410-
411410
_Static_assert(0 == _Generic(inner_unnamed_tagged.untagged, struct { int i; } : 1, default : 0));
412411

412+
struct InnerUnnamedStruct_same {
413+
struct {
414+
int i;
415+
} untagged;
416+
};
417+
struct InnerUnnamedStruct_differentNaming {
418+
struct {
419+
int i;
420+
} untaggedDifferent;
421+
};
422+
struct InnerUnnamedStruct_differentShape {
423+
float x;
424+
struct {
425+
int i;
426+
} untagged;
427+
int y;
428+
};
429+
void compare_unnamed_struct_from_different_outer_type(
430+
struct InnerUnnamedStruct sameOuterType,
431+
struct InnerUnnamedStruct_same matchingType,
432+
struct InnerUnnamedStruct_differentNaming differentFieldName,
433+
struct InnerUnnamedStruct_differentShape differentType) {
434+
inner_unnamed_tagged.untagged = sameOuterType.untagged;
435+
inner_unnamed_tagged.untagged = matchingType.untagged; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}}
436+
inner_unnamed_tagged.untagged = differentFieldName.untaggedDifferent; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}}
437+
inner_unnamed_tagged.untagged = differentType.untagged; // both-error-re {{assigning to 'struct (unnamed struct at {{.*}})' from incompatible type 'struct (unnamed struct at {{.*}})'}}
438+
}
439+
413440
// Test the same thing with enumerations (test for unions is omitted because
414441
// unions and structures are both RecordDecl objects, whereas EnumDecl is not).
415442
enum { E_Untagged1 } nontag_enum; // both-note {{previous definition is here}}

0 commit comments

Comments
 (0)