Skip to content

Commit 3ee89ca

Browse files
committed
[C] Allow __attribute__((nonstring)) on multidimensional arrays
This addresses post-commit review feedback from the Linux kernel folks and improves compatibility with the same feature in GCC
1 parent 3376071 commit 3ee89ca

File tree

2 files changed

+94
-3
lines changed

2 files changed

+94
-3
lines changed

clang/lib/Sema/SemaInit.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,21 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
261261
<< Str->getSourceRange();
262262
else if (StrLength - 1 == ArrayLen) {
263263
// If the entity being initialized has the nonstring attribute, then
264-
// silence the "missing nonstring" diagnostic.
265-
if (const ValueDecl *D = Entity.getDecl();
264+
// silence the "missing nonstring" diagnostic. If there's no entity,
265+
// check whether we're initializing an array of arrays; if so, walk the
266+
// parents to find an entity.
267+
auto FindCorrectEntity = [](const InitializedEntity &Entity) {
268+
const ValueDecl *Ret = nullptr;
269+
for (const InitializedEntity *E = &Entity; E; E = Entity.getParent()) {
270+
Ret = E->getDecl();
271+
if (Ret)
272+
break;
273+
if (!E->getType()->isArrayType())
274+
break;
275+
}
276+
return Ret;
277+
};
278+
if (const ValueDecl *D = FindCorrectEntity(Entity);
266279
!D || !D->hasAttr<NonStringAttr>())
267280
S.Diag(
268281
Str->getBeginLoc(),

clang/test/Sema/attr-nonstring.c

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,no-nonstring -Wextra %s
33
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-unterminated-string-initialization %s
44
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-compat %s
5-
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ %s
5+
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ -Wno-c99-designator %s
66
// RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wno-unterminated-string-initialization %s
77
// RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wc++-compat -Wextra -Wno-unterminated-string-initialization -Wno-c++-unterminated-string-initialization %s
88

@@ -39,3 +39,81 @@ __attribute__((nonstring)) int eek2; // expected-warning {{'nonstri
3939
// diagnostic when you overwrite more than just the null terminator.
4040
char too_big[3] = "this is too big"; // noncxx-warning {{initializer-string for char array is too long}} \
4141
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 16 (including the null terminating character)}}
42+
43+
// Show that this also applies to arrays of objects containing strings, too.
44+
const char md_array[][3] __attribute__((nonstring)) = { "BAR", "FOO", }; // compat-warning 2 {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
45+
cxx-error 2 {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
46+
47+
struct StructWithNSArray {
48+
__attribute__((nonstring)) char blech[3];
49+
};
50+
51+
struct StructWithNSArray s1[] = {
52+
{ "FOO" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
53+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
54+
{ "BAR" } // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
55+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
56+
};
57+
58+
struct T1 {
59+
struct StructWithNSArray s[2];
60+
};
61+
struct U1 {
62+
struct T1 t[2];
63+
};
64+
struct U1 u[] = {
65+
{
66+
.t[0] = {
67+
.s[0] = { "FOO" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
68+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
69+
.s[1] = { "BAR" } // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
70+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
71+
},
72+
.t[1] = {
73+
.s[0] = { "BIP" }, // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
74+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
75+
.s[1] = { "BOP" } // compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
76+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
77+
}
78+
}
79+
};
80+
81+
struct StructWithoutNSArray {
82+
char blech[3];
83+
};
84+
85+
struct StructWithoutNSArray s2[] = {
86+
{ "FOO" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
87+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
88+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
89+
{ "BAR" } // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
90+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
91+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
92+
};
93+
94+
struct T2 {
95+
struct StructWithoutNSArray s[2];
96+
};
97+
struct U2 {
98+
struct T2 t[2];
99+
};
100+
struct U2 u2[] = {
101+
{
102+
.t[0] = {
103+
.s[0] = { "FOO" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
104+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
105+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
106+
.s[1] = { "BAR" } // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
107+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
108+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
109+
},
110+
.t[1] = {
111+
.s[0] = { "BIP" }, // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
112+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
113+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
114+
.s[1] = { "BOP" } // no-nonstring-warning {{initializer-string for character array is too long, array size is 3 but initializer has size 4 (including the null terminating character); did you mean to use the 'nonstring' attribute?}} \
115+
compat-warning {{initializer-string for character array is too long for C++, array size is 3 but initializer has size 4 (including the null terminating character)}} \
116+
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
117+
}
118+
}
119+
};

0 commit comments

Comments
 (0)