Skip to content

Commit cc5b772

Browse files
author
serge-sans-paille
committed
[clang] Introduce -Warray-parameter
This warning exist in GCC[0] and warns about re-declarations of functions involving arguments of array or pointer types of inconsistent kinds or forms. This is not the exact same implementation as GCC's : there's no warning level and that flag has no effect on -Warray-bounds. [0] https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/Warning-Options.html#index-Wno-array-parameter Differential Revision: https://reviews.llvm.org/D128449
1 parent adf1ffe commit cc5b772

File tree

7 files changed

+113
-0
lines changed

7 files changed

+113
-0
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,11 @@ New Compiler Flags
321321
removed in the future once clang supports all such operations.
322322
- Added the ``-print-diagnostic-options`` option, which prints a list of
323323
warnings the compiler supports.
324+
- Added the ``-Warray-parameter`` warning. It diagnoses differences between
325+
array parameters between function redeclarations (arrays of different extents,
326+
etc). This flag is related to the same flag in GCC, but is different in that
327+
it does not accept an explicitly- specified warning level and use of this flag
328+
has no effect on ``-Warray-bounds``.
324329

325330
Deprecated Compiler Flags
326331
-------------------------

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def GNUAnonymousStruct : DiagGroup<"gnu-anonymous-struct">;
3131
def GNUAutoType : DiagGroup<"gnu-auto-type">;
3232
def ArrayBounds : DiagGroup<"array-bounds">;
3333
def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">;
34+
def ArrayParameter : DiagGroup<"array-parameter">;
3435
def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">;
3536
def Availability : DiagGroup<"availability">;
3637
def Section : DiagGroup<"section">;
@@ -978,6 +979,7 @@ def Extra : DiagGroup<"extra", [
978979
]>;
979980

980981
def Most : DiagGroup<"most", [
982+
ArrayParameter,
981983
BoolOperation,
982984
CharSubscript,
983985
Comment,

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9400,6 +9400,12 @@ def warn_array_index_exceeds_max_addressable_bounds : Warning<
94009400
def note_array_declared_here : Note<
94019401
"array %0 declared here">;
94029402

9403+
def warn_inconsistent_array_form : Warning<
9404+
"argument %0 of type %1 with mismatched bound">,
9405+
InGroup<ArrayParameter>, DefaultIgnore;
9406+
def note_previous_declaration_as : Note<
9407+
"previously declared as %0 here">;
9408+
94039409
def warn_printf_insufficient_data_args : Warning<
94049410
"more '%%' conversions than data arguments">, InGroup<FormatInsufficientArgs>;
94059411
def warn_printf_data_arg_not_used : Warning<

clang/lib/Sema/SemaDecl.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3207,6 +3207,39 @@ static void mergeParamDeclAttributes(ParmVarDecl *newDecl,
32073207
if (!foundAny) newDecl->dropAttrs();
32083208
}
32093209

3210+
static bool EquivalentArrayTypes(QualType Old, QualType New,
3211+
const ASTContext &Ctx) {
3212+
3213+
auto NoSizeInfo = [&Ctx](QualType Ty) {
3214+
if (Ty->isIncompleteArrayType() || Ty->isPointerType())
3215+
return true;
3216+
if (const auto *VAT = Ctx.getAsVariableArrayType(Ty))
3217+
return VAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star;
3218+
return false;
3219+
};
3220+
3221+
// `type[]` is equivalent to `type *` and `type[*]`.
3222+
if (NoSizeInfo(Old) && NoSizeInfo(New))
3223+
return true;
3224+
3225+
// Don't try to compare VLA sizes, unless one of them has the star modifier.
3226+
if (Old->isVariableArrayType() && New->isVariableArrayType()) {
3227+
const auto *OldVAT = Ctx.getAsVariableArrayType(Old);
3228+
const auto *NewVAT = Ctx.getAsVariableArrayType(New);
3229+
if ((OldVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star) ^
3230+
(NewVAT->getSizeModifier() == ArrayType::ArraySizeModifier::Star))
3231+
return false;
3232+
return true;
3233+
}
3234+
3235+
// Only compare size, ignore Size modifiers and CVR.
3236+
if (Old->isConstantArrayType() && New->isConstantArrayType())
3237+
return Ctx.getAsConstantArrayType(Old)->getSize() ==
3238+
Ctx.getAsConstantArrayType(New)->getSize();
3239+
3240+
return Old == New;
3241+
}
3242+
32103243
static void mergeParamDeclTypes(ParmVarDecl *NewParam,
32113244
const ParmVarDecl *OldParam,
32123245
Sema &S) {
@@ -3232,6 +3265,19 @@ static void mergeParamDeclTypes(ParmVarDecl *NewParam,
32323265
NewParam->setType(NewT);
32333266
}
32343267
}
3268+
const auto *OldParamDT = dyn_cast<DecayedType>(OldParam->getType());
3269+
const auto *NewParamDT = dyn_cast<DecayedType>(NewParam->getType());
3270+
if (OldParamDT && NewParamDT &&
3271+
OldParamDT->getPointeeType() == NewParamDT->getPointeeType()) {
3272+
QualType OldParamOT = OldParamDT->getOriginalType();
3273+
QualType NewParamOT = NewParamDT->getOriginalType();
3274+
if (!EquivalentArrayTypes(OldParamOT, NewParamOT, S.getASTContext())) {
3275+
S.Diag(NewParam->getLocation(), diag::warn_inconsistent_array_form)
3276+
<< NewParam << NewParamOT;
3277+
S.Diag(OldParam->getLocation(), diag::note_previous_declaration_as)
3278+
<< OldParamOT;
3279+
}
3280+
}
32353281
}
32363282

32373283
namespace {

clang/test/Misc/warning-wall.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ RUN: FileCheck --input-file=%t %s
33

44
CHECK:-Wall
55
CHECK-NEXT: -Wmost
6+
CHECK-NEXT: -Warray-parameter
67
CHECK-NEXT: -Wbool-operation
78
CHECK-NEXT: -Wbitwise-instead-of-logical
89
CHECK-NEXT: -Wchar-subscripts

clang/test/Sema/array-parameter.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -Warray-parameter -verify %s
2+
void f0(int a[]);
3+
void f0(int *a); // no warning
4+
5+
void f1(int a[]); // expected-note {{previously declared as 'int[]' here}}
6+
void f1(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}}
7+
8+
void f2(int a[3]); // expected-note {{previously declared as 'int[3]' here}}
9+
void f2(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}}
10+
11+
void f3(int a[const 2]);
12+
void f3(int a[2]); // no warning
13+
14+
void f4(int a[static 2]);
15+
void f4(int a[2]); // no warning
16+
17+
void f5(int a[restrict 2]);
18+
void f5(int a[2]); // no warning
19+
20+
void f6(int a[volatile 2]);
21+
void f6(int a[2]); // no warning
22+
23+
void f7(int a[*]);
24+
void f7(int a[]); // no warning
25+
26+
void f8(int n, int a[*]); // expected-note {{previously declared as 'int[*]' here}}
27+
void f8(int n, int a[n]); // expected-warning {{argument 'a' of type 'int[n]' with mismatched bound}}
28+
29+
void f9(int *a);
30+
void f9(int a[2]);
31+
void f9(int a[]); // expected-warning {{argument 'a' of type 'int[]' with mismatched bound}}
32+
// expected-note@-2 {{previously declared as 'int[2]' here}}
33+
void f9(int a[2]) // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}}
34+
// expected-note@-3 {{previously declared as 'int[]' here}}
35+
{}

clang/test/Sema/array-parameter.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -Warray-parameter -verify %s
2+
3+
template <int N>
4+
void func(int i[10]); // expected-note {{previously declared as 'int[10]' here}}
5+
6+
template <int N>
7+
void func(int i[N]); // expected-warning {{argument 'i' of type 'int[N]' with mismatched bound}}
8+
9+
template <int N>
10+
void func(int (&Val)[N]);
11+
12+
template <>
13+
void func<10>(int (&Val)[10]) {
14+
}
15+
16+
static constexpr int Extent = 10;
17+
void funk(int i[10]);
18+
void funk(int i[Extent]); // no-warning

0 commit comments

Comments
 (0)