diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 810cac889b98f..0ed1ac495f3e8 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6513,6 +6513,15 @@ static bool canPerformArrayCopy(const InitializedEntity &Entity) { static const FieldDecl *getConstField(const RecordDecl *RD) { assert(!isa(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; diff --git a/clang/test/Sema/warn-default-const-init.c b/clang/test/Sema/warn-default-const-init.c index 76b85abb6ade2..bb3367b01fba5 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 @@ -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)