[C] Warn on uninitialized const objects (#137166)
Unlike C++, C allows the definition of an uninitialized `const` object. If the object has static or thread storage duration, it is still zero-initialized, otherwise, the object is left uninitialized. In either case, the code is not compatible with C++. This adds a new diagnostic group, `-Wdefault-const-init-unsafe`, which is on by default and diagnoses any definition of a `const` object which remains uninitialized. It also adds another new diagnostic group, `-Wdefault-const-init` (which also enabled the `unsafe` variant) that diagnoses any definition of a `const` object (including ones which are zero-initialized). This diagnostic is off by default. Finally, it adds `-Wdefault-const-init` to `-Wc++-compat`. GCC diagnoses these situations under this flag. Fixes #19297
This commit is contained in:
@@ -140,6 +140,13 @@ C Language Changes
|
||||
- Clang now allows an ``inline`` specifier on a typedef declaration of a
|
||||
function type in Microsoft compatibility mode. #GH124869
|
||||
- Clang now allows ``restrict`` qualifier for array types with pointer elements (#GH92847).
|
||||
- Clang now diagnoses ``const``-qualified object definitions without an
|
||||
initializer. If the object is zero-initialized, it will be diagnosed under
|
||||
the new warning ``-Wdefault-const-init`` (which is grouped under
|
||||
``-Wc++-compat`` because this construct is not compatible with C++). If the
|
||||
object is left uninitialized, it will be diagnosed unsed the new warning
|
||||
``-Wdefault-const-init-unsafe`` (which is grouped under
|
||||
``-Wdefault-const-init``). #GH19297
|
||||
- Added ``-Wimplicit-void-ptr-cast``, grouped under ``-Wc++-compat``, which
|
||||
diagnoses implicit conversion from ``void *`` to another pointer type as
|
||||
being incompatible with C++. (#GH17792)
|
||||
|
||||
@@ -154,9 +154,11 @@ def BuiltinRequiresHeader : DiagGroup<"builtin-requires-header">;
|
||||
def C99Compat : DiagGroup<"c99-compat">;
|
||||
def C23Compat : DiagGroup<"c23-compat">;
|
||||
def : DiagGroup<"c2x-compat", [C23Compat]>;
|
||||
|
||||
def DefaultConstInitUnsafe : DiagGroup<"default-const-init-unsafe">;
|
||||
def DefaultConstInit : DiagGroup<"default-const-init", [DefaultConstInitUnsafe]>;
|
||||
def ImplicitVoidPtrCast : DiagGroup<"implicit-void-ptr-cast">;
|
||||
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast]>;
|
||||
def CXXCompat: DiagGroup<"c++-compat", [ImplicitVoidPtrCast, DefaultConstInit]>;
|
||||
|
||||
def ExternCCompat : DiagGroup<"extern-c-compat">;
|
||||
def KeywordCompat : DiagGroup<"keyword-compat">;
|
||||
def GNUCaseRange : DiagGroup<"gnu-case-range">;
|
||||
|
||||
@@ -8197,6 +8197,16 @@ def err_address_space_qualified_new : Error<
|
||||
def err_address_space_qualified_delete : Error<
|
||||
"'delete' cannot delete objects of type %0 in address space '%1'">;
|
||||
|
||||
def note_default_init_const_member : Note<
|
||||
"member %0 declared 'const' here">;
|
||||
def warn_default_init_const : Warning<
|
||||
"default initialization of an object of type %0%select{| with const member}1 "
|
||||
"is incompatible with C++">,
|
||||
InGroup<DefaultConstInit>, DefaultIgnore;
|
||||
def warn_default_init_const_unsafe : Warning<
|
||||
"default initialization of an object of type %0%select{| with const member}1 "
|
||||
"leaves the object uninitialized and is incompatible with C++">,
|
||||
InGroup<DefaultConstInitUnsafe>;
|
||||
def err_default_init_const : Error<
|
||||
"default initialization of an object of const type %0"
|
||||
"%select{| without a user-provided default constructor}1">;
|
||||
|
||||
@@ -2154,7 +2154,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
||||
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
||||
} else {
|
||||
// In C++0x, "for (T NS:a" might not be a typo for ::
|
||||
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
|
||||
bool MightBeForRangeStmt = getLangOpts().CPlusPlus || getLangOpts().ObjC;
|
||||
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
|
||||
ParsedAttributes DeclSpecAttrs(AttrFactory);
|
||||
DG = ParseSimpleDeclaration(
|
||||
|
||||
@@ -1448,6 +1448,18 @@ void Sema::ActOnEndOfTranslationUnit() {
|
||||
// No initialization is performed for a tentative definition.
|
||||
CheckCompleteVariableDeclaration(VD);
|
||||
|
||||
// In C, if the definition is const-qualified and has no initializer, it
|
||||
// is left uninitialized unless it has static or thread storage duration.
|
||||
QualType Type = VD->getType();
|
||||
if (!VD->isInvalidDecl() && !getLangOpts().CPlusPlus &&
|
||||
Type.isConstQualified() && !VD->getAnyInitializer()) {
|
||||
unsigned DiagID = diag::warn_default_init_const_unsafe;
|
||||
if (VD->getStorageDuration() == SD_Static ||
|
||||
VD->getStorageDuration() == SD_Thread)
|
||||
DiagID = diag::warn_default_init_const;
|
||||
Diag(VD->getLocation(), DiagID) << Type << /*not a field*/ 0;
|
||||
}
|
||||
|
||||
// Notify the consumer that we've completed a tentative definition.
|
||||
if (!VD->isInvalidDecl())
|
||||
Consumer.CompleteTentativeDefinition(VD);
|
||||
|
||||
@@ -14339,6 +14339,16 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In C, if the definition is const-qualified and has no initializer, it
|
||||
// is left uninitialized unless it has static or thread storage duration.
|
||||
if (!getLangOpts().CPlusPlus && Type.isConstQualified()) {
|
||||
unsigned DiagID = diag::warn_default_init_const_unsafe;
|
||||
if (Var->getStorageDuration() == SD_Static ||
|
||||
Var->getStorageDuration() == SD_Thread)
|
||||
DiagID = diag::warn_default_init_const;
|
||||
Diag(Var->getLocation(), DiagID) << Type << /*not a field*/ 0;
|
||||
}
|
||||
|
||||
// Check for jumps past the implicit initializer. C++0x
|
||||
// clarifies that this applies to a "variable with automatic
|
||||
// storage duration", not a "local variable".
|
||||
|
||||
@@ -6495,6 +6495,20 @@ static bool canPerformArrayCopy(const InitializedEntity &Entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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()) {
|
||||
QualType QT = FD->getType();
|
||||
if (QT.isConstQualified())
|
||||
return FD;
|
||||
if (const auto *RD = QT->getAsRecordDecl()) {
|
||||
if (const FieldDecl *FD = getConstField(RD))
|
||||
return FD;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InitializationSequence::InitializeFrom(Sema &S,
|
||||
const InitializedEntity &Entity,
|
||||
const InitializationKind &Kind,
|
||||
@@ -6562,13 +6576,28 @@ void InitializationSequence::InitializeFrom(Sema &S,
|
||||
|
||||
if (!S.getLangOpts().CPlusPlus &&
|
||||
Kind.getKind() == InitializationKind::IK_Default) {
|
||||
RecordDecl *Rec = DestType->getAsRecordDecl();
|
||||
if (Rec && Rec->hasUninitializedExplicitInitFields()) {
|
||||
if (RecordDecl *Rec = DestType->getAsRecordDecl()) {
|
||||
VarDecl *Var = dyn_cast_or_null<VarDecl>(Entity.getDecl());
|
||||
if (Var && !Initializer) {
|
||||
S.Diag(Var->getLocation(), diag::warn_field_requires_explicit_init)
|
||||
<< /* Var-in-Record */ 1 << Rec;
|
||||
emitUninitializedExplicitInitFields(S, Rec);
|
||||
if (Rec->hasUninitializedExplicitInitFields()) {
|
||||
if (Var && !Initializer) {
|
||||
S.Diag(Var->getLocation(), diag::warn_field_requires_explicit_init)
|
||||
<< /* Var-in-Record */ 1 << Rec;
|
||||
emitUninitializedExplicitInitFields(S, Rec);
|
||||
}
|
||||
}
|
||||
// If the record has any members which are const (recursively checked),
|
||||
// then we want to diagnose those as being uninitialized if there is no
|
||||
// initializer present.
|
||||
if (!Initializer) {
|
||||
if (const FieldDecl *FD = getConstField(Rec)) {
|
||||
unsigned DiagID = diag::warn_default_init_const_unsafe;
|
||||
if (Var->getStorageDuration() == SD_Static ||
|
||||
Var->getStorageDuration() == SD_Thread)
|
||||
DiagID = diag::warn_default_init_const;
|
||||
|
||||
S.Diag(Var->getLocation(), DiagID) << Var->getType() << /*member*/ 1;
|
||||
S.Diag(FD->getLocation(), diag::note_default_init_const_member) << FD;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ void test1(void) {
|
||||
void test2(void) {
|
||||
typedef int array[1];
|
||||
array reg_array;
|
||||
const array const_array;
|
||||
const array const_array = { 0 };
|
||||
|
||||
// An array and its elements are identically qualified. We have to test this
|
||||
// using pointers to the array and element, because the controlling
|
||||
@@ -50,7 +50,7 @@ void test2(void) {
|
||||
void test3(void) {
|
||||
// Validate that we pick the correct composite type for a conditional
|
||||
// operator in the presence of qualifiers.
|
||||
const int const_array[1];
|
||||
const int const_array[1] = { 0 };
|
||||
int array[1];
|
||||
|
||||
// FIXME: the type here should be `const int (*)[1]`, but for some reason,
|
||||
|
||||
@@ -289,7 +289,7 @@ void dr124(void) {
|
||||
*/
|
||||
void dr126(void) {
|
||||
typedef int *IP;
|
||||
const IP object; /* expected-note {{variable 'object' declared const here}} */
|
||||
const IP object = 0; /* expected-note {{variable 'object' declared const here}} */
|
||||
|
||||
/* The root of the DR is whether 'object' is a pointer to a const int, or a
|
||||
* const pointer to int.
|
||||
@@ -329,7 +329,7 @@ void dr129(void) {
|
||||
void dr131(void) {
|
||||
struct S {
|
||||
const int i; /* expected-note {{data member 'i' declared const here}} */
|
||||
} s1, s2;
|
||||
} s1 = { 0 }, s2 = { 0 };
|
||||
s1 = s2; /* expected-error {{cannot assign to variable 's1' with const-qualified data member 'i'}} */
|
||||
}
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ static void test(void) {
|
||||
short TInt eee; // expected-error{{expected ';' at end of declaration}}
|
||||
void ary[7] fff; // expected-error{{array has incomplete element type 'void'}} expected-error{{expected ';' at end of declaration}}
|
||||
typeof(void ary[7]) anIntError; // expected-error{{expected ')'}} expected-note {{to match this '('}} expected-error {{variable has incomplete type 'typeof(void)' (aka 'void')}}
|
||||
typeof(const int) aci;
|
||||
const typeof (*pi) aConstInt;
|
||||
typeof(const int) aci = 0;
|
||||
const typeof (*pi) aConstInt = 0;
|
||||
int xx;
|
||||
int *i;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@ void test2 (const struct {int a;} *x) {
|
||||
|
||||
typedef int arr[10];
|
||||
void test3(void) {
|
||||
const arr b; // expected-note {{variable 'b' declared const here}}
|
||||
const int b2[10]; // expected-note {{variable 'b2' declared const here}}
|
||||
const arr b = {}; // expected-note {{variable 'b' declared const here}}
|
||||
const int b2[10] = {}; // expected-note {{variable 'b2' declared const here}}
|
||||
b[4] = 1; // expected-error {{cannot assign to variable 'b' with const-qualified type 'const arr' (aka 'const int[10]')}}
|
||||
b2[4] = 1; // expected-error {{cannot assign to variable 'b2' with const-qualified type 'const int[10]'}}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
// RUN: %clang_cc1 %s -verify=expected,fp80,noi128 -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=i686-linux-gnu -std=c11
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=i686-linux-gnu -std=c11
|
||||
// RUN: %clang_cc1 %s -verify=expected,noi128 -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=i686-linux-android -std=c11
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=i686-linux-android -std=c11
|
||||
// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=powerpc64-linux-gnu -std=c11
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=powerpc64-linux-gnu -std=c11
|
||||
// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=powerpc64-linux-gnu -std=c11 \
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=powerpc64-linux-gnu -std=c11 \
|
||||
// RUN: -target-cpu pwr7
|
||||
// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=powerpc64le-linux-gnu -std=c11 \
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=powerpc64le-linux-gnu -std=c11 \
|
||||
// RUN: -target-cpu pwr8 -DPPC64_PWR8
|
||||
// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=powerpc64-unknown-aix -std=c11 \
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=powerpc64-unknown-aix -std=c11 \
|
||||
// RUN: -target-cpu pwr8
|
||||
// RUN: %clang_cc1 %s -verify -fgnuc-version=4.2.1 -ffreestanding \
|
||||
// RUN: -fsyntax-only -triple=powerpc64-unknown-aix -std=c11 \
|
||||
// RUN: -Wno-default-const-init-unsafe -fsyntax-only -triple=powerpc64-unknown-aix -std=c11 \
|
||||
// RUN: -mabi=quadword-atomics -target-cpu pwr8 -DPPC64_PWR8
|
||||
|
||||
// Basic parsing/Sema tests for __c11_atomic_*
|
||||
|
||||
@@ -126,7 +126,7 @@ void foo7(void)
|
||||
int (^JJ) (void) = ^{ return j; }; // OK
|
||||
int (^KK) (void) = ^{ return j+1; }; // OK
|
||||
|
||||
__block const int k;
|
||||
__block const int k = 0;
|
||||
const int cint = 100;
|
||||
|
||||
int (^MM) (void) = ^{ return k; };
|
||||
|
||||
@@ -69,7 +69,7 @@ unsigned invalid11(struct s *arg, int info_kind) {
|
||||
}
|
||||
|
||||
unsigned valid12(void) {
|
||||
const struct s t;
|
||||
const struct s t = {};
|
||||
return __builtin_preserve_type_info(t, 0) +
|
||||
__builtin_preserve_type_info(*(struct s *)0, 1);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ void test_builtin_elementwise_add_sat(int i, short s, double d, float4 v, int3 i
|
||||
_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
|
||||
ext = __builtin_elementwise_add_sat(ext, ext);
|
||||
|
||||
const int ci;
|
||||
const int ci = 0;
|
||||
i = __builtin_elementwise_add_sat(ci, i);
|
||||
i = __builtin_elementwise_add_sat(i, ci);
|
||||
i = __builtin_elementwise_add_sat(ci, ci);
|
||||
@@ -154,7 +154,7 @@ void test_builtin_elementwise_sub_sat(int i, short s, double d, float4 v, int3 i
|
||||
_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
|
||||
ext = __builtin_elementwise_sub_sat(ext, ext);
|
||||
|
||||
const int ci;
|
||||
const int ci = 0;
|
||||
i = __builtin_elementwise_sub_sat(ci, i);
|
||||
i = __builtin_elementwise_sub_sat(i, ci);
|
||||
i = __builtin_elementwise_sub_sat(ci, ci);
|
||||
@@ -214,7 +214,7 @@ void test_builtin_elementwise_max(int i, short s, double d, float4 v, int3 iv, u
|
||||
_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
|
||||
ext = __builtin_elementwise_max(ext, ext);
|
||||
|
||||
const int ci;
|
||||
const int ci = 0;
|
||||
i = __builtin_elementwise_max(ci, i);
|
||||
i = __builtin_elementwise_max(i, ci);
|
||||
i = __builtin_elementwise_max(ci, ci);
|
||||
@@ -274,7 +274,7 @@ void test_builtin_elementwise_min(int i, short s, double d, float4 v, int3 iv, u
|
||||
_BitInt(32) ext; // expected-warning {{'_BitInt' in C17 and earlier is a Clang extension}}
|
||||
ext = __builtin_elementwise_min(ext, ext);
|
||||
|
||||
const int ci;
|
||||
const int ci = 0;
|
||||
i = __builtin_elementwise_min(ci, i);
|
||||
i = __builtin_elementwise_min(i, ci);
|
||||
i = __builtin_elementwise_min(ci, ci);
|
||||
@@ -1070,7 +1070,7 @@ void test_builtin_elementwise_copysign(int i, short s, double d, float f, float4
|
||||
ext = __builtin_elementwise_copysign(ext, ext);
|
||||
// expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was '_BitInt(32)')}}
|
||||
|
||||
const float cf32;
|
||||
const float cf32 = 0.0f;
|
||||
f = __builtin_elementwise_copysign(cf32, f);
|
||||
f = __builtin_elementwise_copysign(f, cf32);
|
||||
f = __builtin_elementwise_copysign(cf32, f);
|
||||
|
||||
@@ -9,7 +9,7 @@ void test(void) {
|
||||
unsigned r;
|
||||
const char * c;
|
||||
float f;
|
||||
const unsigned q;
|
||||
const unsigned q = 0;
|
||||
|
||||
__builtin_add_overflow(); // expected-error {{too few arguments to function call, expected 3, have 0}}
|
||||
__builtin_add_overflow(1, 1, 1, 1); // expected-error {{too many arguments to function call, expected 3, have 4}}
|
||||
|
||||
@@ -52,7 +52,7 @@ size_t strnlen(const char *s, size_t maxlen) // expected-note {{'strnlen' has be
|
||||
|
||||
void test2(const char *s, int i) {
|
||||
// CHECK: define {{.*}}void @test2
|
||||
const char c[123];
|
||||
const char c[123] = { 0 };
|
||||
strnlen(s, i);
|
||||
// CHECK: call {{.*}}strnlen_real1
|
||||
strnlen(s, 999);
|
||||
|
||||
@@ -13,7 +13,7 @@ typedef unsigned char Boolean;
|
||||
extern int printf(__const char *__restrict __format, ...); // both-note{{'printf' declared here}}
|
||||
void func(void) {
|
||||
int32_t *vector[16];
|
||||
const char compDesc[16 + 1];
|
||||
const char compDesc[16 + 1] = { 0 };
|
||||
int32_t compCount = 0;
|
||||
if (_CFCalendarDecomposeAbsoluteTimeV(compDesc, vector, compCount)) { // expected-error {{call to undeclared function '_CFCalendarDecomposeAbsoluteTimeV'; ISO C99 and later do not support implicit function declarations}} \
|
||||
expected-note {{previous implicit declaration}} \
|
||||
|
||||
@@ -155,7 +155,7 @@ void incompatible_pointer_type_conversions() {
|
||||
}
|
||||
|
||||
void dropping_qualifiers_is_incompatible() {
|
||||
const char ccharbuf[1];
|
||||
const char ccharbuf[1] = {0};
|
||||
volatile char vcharbuf[1];
|
||||
|
||||
void foo(char *c) __attribute__((overloadable));
|
||||
|
||||
@@ -94,12 +94,12 @@ void func(int sel) {
|
||||
svint8_t bad_brace_init_int8_6 = {{local_int8, 0}}; // expected-warning {{too many braces around initializer}}
|
||||
|
||||
const svint8_t const_int8 = local_int8; // expected-note {{declared const here}}
|
||||
const svint8_t uninit_const_int8;
|
||||
const svint8_t uninit_const_int8; // expected-warning {{default initialization of an object of type 'const svint8_t' (aka 'const __SVInt8_t') leaves the object uninitialized and is incompatible with C++}};
|
||||
|
||||
volatile svint8_t volatile_int8;
|
||||
|
||||
const volatile svint8_t const_volatile_int8 = local_int8; // expected-note {{declared const here}}
|
||||
const volatile svint8_t uninit_const_volatile_int8;
|
||||
const volatile svint8_t uninit_const_volatile_int8; // expected-warning {{default initialization of an object of type 'const volatile svint8_t' (aka 'const volatile __SVInt8_t') leaves the object uninitialized and is incompatible with C++}}
|
||||
|
||||
_Atomic svint8_t atomic_int8; // expected-error {{_Atomic cannot be applied to sizeless type 'svint8_t'}}
|
||||
__restrict svint8_t restrict_int8; // expected-error {{requires a pointer or reference}}
|
||||
|
||||
@@ -16,7 +16,8 @@ void test2(float4 a, int4p result, int i) {
|
||||
typedef int a[5];
|
||||
void test3(void) {
|
||||
typedef const a b;
|
||||
b r; // expected-note {{variable 'r' declared const here}}
|
||||
b r; // expected-note {{variable 'r' declared const here}} \
|
||||
expected-warning {{default initialization of an object of type 'b' (aka 'const int[5]') leaves the object uninitialized and is incompatible with C++}}
|
||||
r[0] = 10; // expected-error {{cannot assign to variable 'r' with const-qualified type 'b' (aka 'const int[5]')}}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-apple-darwin9
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wno-default-const-init-unsafe -verify %s -triple x86_64-apple-darwin9
|
||||
|
||||
void f1(void) {
|
||||
const __builtin_va_list args2;
|
||||
|
||||
63
clang/test/Sema/warn-default-const-init.c
Normal file
63
clang/test/Sema/warn-default-const-init.c
Normal file
@@ -0,0 +1,63 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=c,unsafe -Wdefault-const-init %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=c,unsafe -Wc++-compat %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=unsafe %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=c -Wdefault-const-init -Wno-default-const-init-unsafe %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=good -Wno-default-const-init-unsafe %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
|
||||
// good-no-diagnostics
|
||||
|
||||
struct A { int i; };
|
||||
struct S{ const int i; }; // unsafe-note 2 {{member 'i' declared 'const' here}} \
|
||||
cxx-note 3 {{default constructor of 'S' is implicitly deleted because field 'i' of const-qualified type 'const int' would not be initialized}}
|
||||
struct T { struct S s; }; // cxx-note {{default constructor of 'T' is implicitly deleted because field 's' has a deleted default constructor}}
|
||||
struct U { struct S s; const int j; };
|
||||
struct V { int i; const struct A a; }; // unsafe-note {{member 'a' declared 'const' here}} \
|
||||
cxx-note {{default constructor of 'V' is implicitly deleted because field 'a' of const-qualified type 'const struct A' would not be initialized}}
|
||||
struct W { struct A a; const int j; }; // unsafe-note {{member 'j' declared 'const' here}} \
|
||||
cxx-note {{default constructor of 'W' is implicitly deleted because field 'j' of const-qualified type 'const int' would not be initialized}}
|
||||
|
||||
void f() {
|
||||
struct S s1; // unsafe-warning {{default initialization of an object of type 'struct S' with const member leaves the object uninitialized and is incompatible with C++}} \
|
||||
cxx-error {{call to implicitly-deleted default constructor of 'struct S'}}
|
||||
struct S s2 = { 0 };
|
||||
}
|
||||
void g() {
|
||||
struct T t1; // unsafe-warning {{default initialization of an object of type 'struct T' with const member leaves the object uninitialized and is incompatible with C++}} \
|
||||
cxx-error {{call to implicitly-deleted default constructor of 'struct T'}}
|
||||
struct T t2 = { { 0 } };
|
||||
}
|
||||
void h() {
|
||||
struct U u1 = { { 0 } };
|
||||
struct U u2 = { { 0 }, 0 };
|
||||
}
|
||||
void x() {
|
||||
struct V v1; // unsafe-warning {{default initialization of an object of type 'struct V' with const member leaves the object uninitialized and is incompatible with C++}} \
|
||||
cxx-error {{call to implicitly-deleted default constructor of 'struct V'}}
|
||||
struct V v2 = { 0 };
|
||||
struct V v3 = { 0, { 0 } };
|
||||
}
|
||||
void y() {
|
||||
struct W w1; // unsafe-warning {{default initialization of an object of type 'struct W' with const member leaves the object uninitialized and is incompatible with C++}} \
|
||||
cxx-error {{call to implicitly-deleted default constructor of 'struct W'}}
|
||||
struct W w2 = { 0 };
|
||||
struct W w3 = { { 0 }, 0 };
|
||||
}
|
||||
|
||||
// Test a tentative definition which does eventually get an initializer.
|
||||
extern const int i;
|
||||
const int i = 12;
|
||||
|
||||
static const int j; // c-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'}}
|
||||
const int k; // c-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'}}
|
||||
const struct S s; // c-warning {{default initialization of an object of type 'const struct S' is incompatible with C++}} \
|
||||
cxx-error {{call to implicitly-deleted default constructor of 'const struct S'}}
|
||||
|
||||
void func() {
|
||||
const int a; // unsafe-warning {{default initialization of an object of type 'const int' leaves the object uninitialized and is incompatible with C++}} \
|
||||
cxx-error {{default initialization of an object of const type 'const int'}}
|
||||
static const int b; // c-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'}}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ static void unused(void) { unused(); } // expected-warning{{not needed and will
|
||||
|
||||
static void cleanupMalloc(char * const * const allocation) { }
|
||||
void f13(void) {
|
||||
char * const __attribute__((cleanup(cleanupMalloc))) a;
|
||||
char * const __attribute__((cleanup(cleanupMalloc))) a = 0;
|
||||
(void)a;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify -Wno-objc-root-class %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -Wno-default-const-init-unsafe -verify -Wno-objc-root-class %s
|
||||
|
||||
typedef struct objc_object {
|
||||
Class isa;
|
||||
|
||||
@@ -14,7 +14,7 @@ typedef struct {int a;} ndrange_t;
|
||||
kernel void enqueue_kernel_tests(void) {
|
||||
queue_t default_queue;
|
||||
unsigned flags = 0;
|
||||
QUALS ndrange_t ndrange;
|
||||
QUALS ndrange_t ndrange = { 0 };
|
||||
clk_event_t evt;
|
||||
clk_event_t event_wait_list;
|
||||
clk_event_t event_wait_list2[] = {evt, evt};
|
||||
|
||||
@@ -13,7 +13,8 @@ void f1(void) {
|
||||
f0(bl1);
|
||||
f0(bl2);
|
||||
bl1 = bl2; // expected-error{{invalid operands to binary expression ('int (__generic ^const __private)(void)' and 'int (__generic ^const __private)(void)')}}
|
||||
int (^const bl3)(void); // expected-error{{invalid block variable declaration - must be initialized}}
|
||||
int (^const bl3)(void); // expected-error{{invalid block variable declaration - must be initialized}} \
|
||||
expected-warning {{default initialization of an object of type 'int (__generic ^const __private)(void)' leaves the object uninitialized and is incompatible with C++}}
|
||||
}
|
||||
|
||||
// A block with extern storage class is not allowed.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// or https://github.com/llvm/llvm-project/pull/71480
|
||||
|
||||
void test() {
|
||||
int v; const int x; // expected-note {{variable 'x' declared const here}}
|
||||
int v; const int x = 0; // expected-note {{variable 'x' declared const here}}
|
||||
#pragma omp atomic capture
|
||||
{
|
||||
v = x;
|
||||
|
||||
Reference in New Issue
Block a user