[C] Allow __attribute__((nonstring)) on multidimensional arrays (#138133)
This addresses post-commit review feedback from the Linux kernel folks and improves compatibility with the same feature in GCC
This commit is contained in:
@@ -261,8 +261,22 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
|
||||
<< Str->getSourceRange();
|
||||
else if (StrLength - 1 == ArrayLen) {
|
||||
// If the entity being initialized has the nonstring attribute, then
|
||||
// silence the "missing nonstring" diagnostic.
|
||||
if (const ValueDecl *D = Entity.getDecl();
|
||||
// silence the "missing nonstring" diagnostic. If there's no entity,
|
||||
// check whether we're initializing an array of arrays; if so, walk the
|
||||
// parents to find an entity.
|
||||
auto FindCorrectEntity =
|
||||
[](const InitializedEntity *Entity) -> const ValueDecl * {
|
||||
while (Entity) {
|
||||
if (const ValueDecl *VD = Entity->getDecl())
|
||||
return VD;
|
||||
if (!Entity->getType()->isArrayType())
|
||||
return nullptr;
|
||||
Entity = Entity->getParent();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
if (const ValueDecl *D = FindCorrectEntity(&Entity);
|
||||
!D || !D->hasAttr<NonStringAttr>())
|
||||
S.Diag(
|
||||
Str->getBeginLoc(),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,no-nonstring -Wextra %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-unterminated-string-initialization %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=noncxx,expected,compat -Wc++-compat %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx -x c++ -Wno-c99-designator %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wno-unterminated-string-initialization %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,noncxx -Wc++-compat -Wextra -Wno-unterminated-string-initialization -Wno-c++-unterminated-string-initialization %s
|
||||
|
||||
@@ -39,3 +39,193 @@ __attribute__((nonstring)) int eek2; // expected-warning {{'nonstri
|
||||
// diagnostic when you overwrite more than just the null terminator.
|
||||
char too_big[3] = "this is too big"; // noncxx-warning {{initializer-string for char array is too long}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 16 (including the null terminating character)}}
|
||||
|
||||
// Show that this also applies to arrays of objects containing strings, too.
|
||||
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)}} \
|
||||
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)}}
|
||||
|
||||
struct StructWithArrays {
|
||||
char string[3];
|
||||
__attribute__((nonstring)) char nonstring[3];
|
||||
};
|
||||
|
||||
struct StructWithArrays s1[] = {
|
||||
{
|
||||
"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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
{
|
||||
"BAZ", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
};
|
||||
|
||||
struct Inner {
|
||||
struct StructWithArrays s[2];
|
||||
};
|
||||
struct Outer {
|
||||
struct Inner i[2];
|
||||
};
|
||||
|
||||
struct Outer o1[] = { // Array of Outer
|
||||
{ // Outer
|
||||
{ // Array of Inner
|
||||
{ // Inner
|
||||
{ // Array of StructWithArrays
|
||||
{ // StructWithArrays
|
||||
"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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
{ // StructWithArrays
|
||||
"BAZ", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"BAT" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
} // End array of StructWithArrays
|
||||
}, // End Inner
|
||||
{ // Inner
|
||||
{ // Array of StructWithArrays
|
||||
{ // StructWithArrays
|
||||
"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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
{ // StructWithArrays
|
||||
"BAP", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"BUP" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
} // End array of StructWithArrays
|
||||
} // End Inner
|
||||
} // End array of Inner
|
||||
}, // End Outer
|
||||
{ // Outer
|
||||
{ // Array of Inner
|
||||
{ // Inner
|
||||
{ // Array of StructWithArrays
|
||||
{ // StructWithArrays
|
||||
"ABC", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"CAB" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
{ // StructWithArrays
|
||||
"BAC", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"CBA" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
} // End array of StructWithArrays
|
||||
}, // End Inner
|
||||
{ // Inner
|
||||
{ // Array of StructWithArrays
|
||||
{ // StructWithArrays
|
||||
"XYZ", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"YZX" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
{ // StructWithArrays
|
||||
"ZYX", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"ZXY" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
} // End array of StructWithArrays
|
||||
} // End Inner
|
||||
} // End array of Inner
|
||||
}, // End Outer
|
||||
};
|
||||
|
||||
// Do the same test as above, but using designated initializers and a more
|
||||
// simple layout of the initialization.
|
||||
|
||||
struct Outer o2[] = {
|
||||
[0] = {
|
||||
.i[0] = {
|
||||
.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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
.s[1] = {
|
||||
"BAZ", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"BAT" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
},
|
||||
.i[1] = {
|
||||
.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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
.s[1] = {
|
||||
"BAP", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"BUP" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
}
|
||||
},
|
||||
[1] = {
|
||||
.i[0] = {
|
||||
.s[0] = {
|
||||
"ABC", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"CAB" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
.s[1] = {
|
||||
"BAC", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"CBA" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
},
|
||||
.i[1] = {
|
||||
.s[0] = {
|
||||
"XYZ", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"YZX" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
},
|
||||
.s[1] = {
|
||||
"ZYX", // 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?}} \
|
||||
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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
"ZXY" // 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)}} \
|
||||
cxx-error {{initializer-string for char array is too long, array size is 3 but initializer has size 4 (including the null terminating character)}}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user