diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -309,6 +309,9 @@ removed in the future once clang supports all such operations. - Added the ``-print-diagnostic-options`` option, which prints a list of warnings the compiler supports. +- Added the ``-Warray-parameter`` warning. It detects function redefinition, + where different definition involve argument type that decay to the same + pointer type from different array types. Deprecated Compiler Flags ------------------------- diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -31,6 +31,7 @@ def GNUAutoType : DiagGroup<"gnu-auto-type">; def ArrayBounds : DiagGroup<"array-bounds">; def ArrayBoundsPointerArithmetic : DiagGroup<"array-bounds-pointer-arithmetic">; +def ArrayParameter : DiagGroup<"array-parameter">; def AutoDisableVptrSanitizer : DiagGroup<"auto-disable-vptr-sanitizer">; def Availability : DiagGroup<"availability">; def Section : DiagGroup<"section">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9393,6 +9393,12 @@ def note_array_declared_here : Note< "array %0 declared here">; +def warn_inconsistent_array_form : Warning< + "argument '%0' of type '%1' with mismatched bound">, + InGroup; +def note_previous_declaration_as : Note< + "previously declared as %0 here">; + def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; def warn_printf_data_arg_not_used : Warning< diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -46,6 +46,7 @@ #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" #include #include #include @@ -3209,6 +3210,19 @@ if (!foundAny) newDecl->dropAttrs(); } +static bool EquivalentArrayTypes(QualType Old, QualType New) { + // type[] is equivalent to type * + if ((Old->isIncompleteArrayType() && New->isPointerType()) || + (New->isIncompleteArrayType() && Old->isPointerType())) + return true; + + // Don't try to compare VLA sizes + if (Old->isVariableArrayType() && New->isVariableArrayType()) + return true; + + return Old == New; +} + static void mergeParamDeclTypes(ParmVarDecl *NewParam, const ParmVarDecl *OldParam, Sema &S) { @@ -3234,6 +3248,22 @@ NewParam->setType(NewT); } } + const DecayedType *OldParamDT = + dyn_cast(OldParam->getType()); + const DecayedType *NewParamDT = + dyn_cast(NewParam->getType()); + if (OldParamDT && NewParamDT && + OldParamDT->getPointeeType() == NewParamDT->getPointeeType()) { + QualType OldParamOT = OldParamDT->getOriginalType(); + QualType NewParamOT = NewParamDT->getOriginalType(); + if (!EquivalentArrayTypes(OldParamOT, NewParamOT)) { + S.Diag(NewParam->getLocation(), diag::warn_inconsistent_array_form) + << NewParam->getName() + << NewParamOT->getCanonicalTypeInternal().getAsString(); + S.Diag(OldParam->getLocation(), diag::note_previous_declaration_as) + << OldParamOT->getCanonicalTypeInternal().getAsString(); + } + } } namespace { diff --git a/clang/test/Sema/array-parameter.c b/clang/test/Sema/array-parameter.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/array-parameter.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -Wno-unused -verify %s + +void f0(int a[]); +void f0(int *a); // no warning + +void f1(int a[]); // expected-note {{previously declared as int[] here}} +void f1(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}} + +void f2(int a[3]); // expected-note {{previously declared as int[3] here}} +void f2(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}} + +void f3(int a[const 2]); // expected-note {{previously declared as int[const 2] here}} +void f3(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}} + +void f4(int a[static 2]); // expected-note {{previously declared as int[static 2] here}} +void f4(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}} + +void f5(int a[restrict 2]); // expected-note {{previously declared as int[__restrict 2] here}} +void f5(int a[2]); // expected-warning {{argument 'a' of type 'int[2]' with mismatched bound}} + +void f6(int a[*]); // expected-note {{previously declared as int[*] here}} +void f6(int a[]); // expected-warning {{argument 'a' of type 'int[]' with mismatched bound}}