Skip to content

[C] Do not diagnose flexible array members with -Wdefault-const-init-field-unsafe #140578

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6513,6 +6513,15 @@ static bool canPerformArrayCopy(const InitializedEntity &Entity) {
static const FieldDecl *getConstField(const RecordDecl *RD) {
assert(!isa<CXXRecordDecl>(RD) && "Only expect to call this in C mode");
for (const FieldDecl *FD : RD->fields()) {
// If the field is a flexible array member, we don't want to consider it
// as a const field because there's no way to initialize the FAM anyway.
const ASTContext &Ctx = FD->getASTContext();
if (Decl::isFlexibleArrayMemberLike(
Ctx, FD, FD->getType(),
Ctx.getLangOpts().getStrictFlexArraysLevel(),
/*IgnoreTemplateOrMacroSubstitution=*/true))
continue;

QualType QT = FD->getType();
if (QT.isConstQualified())
return FD;
Expand Down
43 changes: 38 additions & 5 deletions clang/test/Sema/warn-default-const-init.c
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
// Both of these should enable everything.
// 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
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-var,unsafe-field,zero-init-var,zero-init-field -Wdefault-const-init %s
// 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
// 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

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

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

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

// Only zero init and unsafe field diagnostics
// RUN: %clang_cc1 -fsyntax-only -verify=zero-init-field,unsafe-field -Wno-default-const-init-var-unsafe -Wdefault-const-init-field %s
// 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

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

// Only unsafe field diagnostics, but with flexible arrays set to any kind of array
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe-field -Wno-default-const-init-var-unsafe -Wdefault-const-init-field-unsafe -fstrict-flex-arrays=0 %s

// C++ tests
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s

Expand Down Expand Up @@ -97,3 +100,33 @@ void func() {
static const int b; // zero-init-var-warning {{default initialization of an object of type 'const int' is incompatible with C++}} \
cxx-error {{default initialization of an object of const type 'const int'}}
}

// Test the behavior of flexible array members. Those cannot be initialized
// when a stack-allocated object of the structure type is created. We handle
// degenerate flexible arrays based on -fstrict-flex-arrays. Note that C++ does
// not have flexible array members at all, which is why the test is disabled
// there.
#ifndef __cplusplus
struct RealFAM {
int len;
const char fam[];
};

struct FakeFAM {
int len;
const char fam[0];
};

struct NotTreatedAsAFAM {
int len;
const char fam[1]; // unsafe-field-restricted-flex-note {{member 'fam' declared 'const' here}} \
unsafe-field-compat-note {{member 'fam' declared 'const' here}}
};

void test_fams() {
struct RealFAM One;
struct FakeFAM Two;
struct NotTreatedAsAFAM Three; // unsafe-field-restricted-flex-warning {{default initialization of an object of type 'struct NotTreatedAsAFAM' with const member leaves the object uninitialized}} \
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++}}
}
#endif // !defined(__cplusplus)