https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/140578
>From 625662da41256345c4609835754c3a61018b54ca Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Mon, 19 May 2025 13:09:03 -0400 Subject: [PATCH 1/2] [C] Do not diagnose flexible array members with -Wdefault-const-init-field-unsafe 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. --- clang/lib/Sema/SemaInit.cpp | 8 ++++++ clang/test/Sema/warn-default-const-init.c | 30 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 9ee8603ff7811..e17e68966dc00 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6513,6 +6513,14 @@ 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. + if (Decl::isFlexibleArrayMemberLike( + FD->getASTContext(), FD, FD->getType(), + LangOptions::StrictFlexArraysLevelKind::ZeroOrIncomplete, + /*IgnoreTemplateOrMacroSubstitution=*/true)) + continue; + QualType QT = FD->getType(); if (QT.isConstQualified()) return FD; diff --git a/clang/test/Sema/warn-default-const-init.c b/clang/test/Sema/warn-default-const-init.c index e788d72899685..e6ff0aa783e23 100644 --- a/clang/test/Sema/warn-default-const-init.c +++ b/clang/test/Sema/warn-default-const-init.c @@ -85,3 +85,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 similarly, but only if the array does not +// actually specify any storage. 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-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-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) >From 2637a020d818a205d3be933f73f1449a0870faf0 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Tue, 20 May 2025 08:22:19 -0400 Subject: [PATCH 2/2] Base behavior on -fstrict-flex-arrays --- clang/lib/Sema/SemaInit.cpp | 5 +++-- clang/test/Sema/warn-default-const-init.c | 23 +++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e17e68966dc00..ddadfa0ac3490 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6515,9 +6515,10 @@ static const FieldDecl *getConstField(const RecordDecl *RD) { 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( - FD->getASTContext(), FD, FD->getType(), - LangOptions::StrictFlexArraysLevelKind::ZeroOrIncomplete, + Ctx, FD, FD->getType(), + Ctx.getLangOpts().getStrictFlexArraysLevel(), /*IgnoreTemplateOrMacroSubstitution=*/true)) continue; diff --git a/clang/test/Sema/warn-default-const-init.c b/clang/test/Sema/warn-default-const-init.c index e6ff0aa783e23..a70a0ccb6ebc6 100644 --- a/clang/test/Sema/warn-default-const-init.c +++ b/clang/test/Sema/warn-default-const-init.c @@ -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 @@ -88,9 +91,9 @@ void func() { // 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 similarly, but only if the array does not -// actually specify any storage. Note that C++ does not have flexible array -// members at all, which is why the test is disabled there. +// 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; @@ -104,14 +107,14 @@ struct FakeFAM { struct NotTreatedAsAFAM { int len; - const char fam[1]; // unsafe-field-note {{member 'fam' declared 'const' here}} \ + 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-warning {{default initialization of an object of type 'struct NotTreatedAsAFAM' with const member leaves the object uninitialized}} \ + 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) _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits