Skip to content

Commit c555c8d

Browse files
authored
[C] Do not diagnose flexible array members with -Wdefault-const-init-field-unsafe (#140578)
This addresses post-commit review feedback from someone who discovered that we diagnosed code like the following: ``` struct S { int len; const char fam[]; } s; ``` despite it being invalid to initialize the flexible array member. Note, this applies to flexible array members and zero-sized arrays at the end of a structure (an old-style flexible array member), but it does not apply to one-sized arrays at the end of a structure because those do occupy storage that can be initialized.
1 parent 0ccd57e commit c555c8d

File tree

2 files changed

+47
-5
lines changed

2 files changed

+47
-5
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6513,6 +6513,15 @@ static bool canPerformArrayCopy(const InitializedEntity &Entity) {
65136513
static const FieldDecl *getConstField(const RecordDecl *RD) {
65146514
assert(!isa<CXXRecordDecl>(RD) && "Only expect to call this in C mode");
65156515
for (const FieldDecl *FD : RD->fields()) {
6516+
// If the field is a flexible array member, we don't want to consider it
6517+
// as a const field because there's no way to initialize the FAM anyway.
6518+
const ASTContext &Ctx = FD->getASTContext();
6519+
if (Decl::isFlexibleArrayMemberLike(
6520+
Ctx, FD, FD->getType(),
6521+
Ctx.getLangOpts().getStrictFlexArraysLevel(),
6522+
/*IgnoreTemplateOrMacroSubstitution=*/true))
6523+
continue;
6524+
65166525
QualType QT = FD->getType();
65176526
if (QT.isConstQualified())
65186527
return FD;

clang/test/Sema/warn-default-const-init.c

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
11
// Both of these should enable everything.
2-
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var-compat,unsafe-field-compat,zero-init-var,zero-init-field -Wc++-compat -Wno-tentative-definition-compat %s
3-
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field -Wdefault-const-init %s
2+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var-compat,unsafe-field-compat,zero-init-var,zero-init-field -Wc++-compat -Wno-tentative-definition-compat -fstrict-flex-arrays=2 %s
3+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field,unsafe-field-restricted-flex -Wdefault-const-init -fstrict-flex-arrays=2 %s
44

55
// This should enable nothing.
66
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wno-default-const-init-unsafe %s
77

88
// Only unsafe field and variable diagnostics
9-
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field %s
10-
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field -Wdefault-const-init-unsafe %s
9+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,unsafe-field-restricted-flex -fstrict-flex-arrays=2 %s
10+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,unsafe-field-restricted-flex -Wdefault-const-init-unsafe -fstrict-flex-arrays=2 %s
1111

1212
// Only zero init field and variable diagnostics
1313
// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-var,zero-init-field -Wdefault-const-init -Wno-default-const-init-unsafe %s
1414

1515
// Only zero init and unsafe field diagnostics
16-
// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-field,unsafe-field -Wno-default-const-init-var-unsafe -Wdefault-const-init-field %s
16+
// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-field,unsafe-field,unsafe-field-restricted-flex -Wno-default-const-init-var-unsafe -Wdefault-const-init-field -fstrict-flex-arrays=2 %s
1717

1818
// Only zero init and unsafe variable diagnostics
1919
// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-var,unsafe-var -Wno-default-const-init-field-unsafe -Wdefault-const-init-var %s
2020

21+
// Only unsafe field diagnostics, but with flexible arrays set to any kind of array
22+
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-field -Wno-default-const-init-var-unsafe -Wdefault-const-init-field-unsafe -fstrict-flex-arrays=0 %s
23+
2124
// C++ tests
2225
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
2326

@@ -97,3 +100,33 @@ void func() {
97100
static const int b; // zero-init-var-warning {{default initialization of an object of type 'const int' is incompatible with C++}} \
98101
cxx-error {{default initialization of an object of const type 'const int'}}
99102
}
103+
104+
// Test the behavior of flexible array members. Those cannot be initialized
105+
// when a stack-allocated object of the structure type is created. We handle
106+
// degenerate flexible arrays based on -fstrict-flex-arrays. Note that C++ does
107+
// not have flexible array members at all, which is why the test is disabled
108+
// there.
109+
#ifndef __cplusplus
110+
struct RealFAM {
111+
int len;
112+
const char fam[];
113+
};
114+
115+
struct FakeFAM {
116+
int len;
117+
const char fam[0];
118+
};
119+
120+
struct NotTreatedAsAFAM {
121+
int len;
122+
const char fam[1]; // unsafe-field-restricted-flex-note {{member 'fam' declared 'const' here}} \
123+
unsafe-field-compat-note {{member 'fam' declared 'const' here}}
124+
};
125+
126+
void test_fams() {
127+
struct RealFAM One;
128+
struct FakeFAM Two;
129+
struct NotTreatedAsAFAM Three; // unsafe-field-restricted-flex-warning {{default initialization of an object of type 'struct NotTreatedAsAFAM' with const member leaves the object uninitialized}} \
130+
unsafe-field-compat-warning {{default initialization of an object of type 'struct NotTreatedAsAFAM' with const member leaves the object uninitialized and is incompatible with C++}}
131+
}
132+
#endif // !defined(__cplusplus)

0 commit comments

Comments
 (0)