Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ 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 ------------------------- Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ 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">; @@ -978,6 +979,7 @@ ]>; def Most : DiagGroup<"most", [ + ArrayParameter, BoolOperation, CharSubscript, Comment, Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ 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, DefaultIgnore; +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< Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ 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 { Index: clang/test/Misc/warning-wall.c =================================================================== --- clang/test/Misc/warning-wall.c +++ clang/test/Misc/warning-wall.c @@ -1,103 +1,9 @@ -RUN: diagtool tree -Wall > %t 2>&1 -RUN: FileCheck --input-file=%t %s +RUN : diagtool tree - Wall > % t 2 > & 1 RUN : FileCheck-- input - file = % t % s - CHECK:-Wall -CHECK-NEXT: -Wmost -CHECK-NEXT: -Wbool-operation -CHECK-NEXT: -Wbitwise-instead-of-logical -CHECK-NEXT: -Wchar-subscripts -CHECK-NEXT: -Wcomment -CHECK-NEXT: -Wdelete-non-virtual-dtor -CHECK-NEXT: -Wdelete-non-abstract-non-virtual-dtor -CHECK-NEXT: -Wdelete-abstract-non-virtual-dtor -CHECK-NEXT: -Wformat -CHECK-NEXT: -Wformat-extra-args -CHECK-NEXT: -Wformat-zero-length -CHECK-NEXT: -Wnonnull -CHECK-NEXT: -Wformat-security -CHECK-NEXT: -Wformat-y2k -CHECK-NEXT: -Wformat-invalid-specifier -CHECK-NEXT: -Wformat-insufficient-args -CHECK-NEXT: -Wfor-loop-analysis -CHECK-NEXT: -Wframe-address -CHECK-NEXT: -Wimplicit -CHECK-NEXT: -Wimplicit-function-declaration -CHECK-NEXT: -Wimplicit-int -CHECK-NEXT: -Winfinite-recursion -CHECK-NEXT: -Wint-in-bool-context -CHECK-NEXT: -Wmismatched-tags -CHECK-NEXT: -Wmissing-braces -CHECK-NEXT: -Wmove -CHECK-NEXT: -Wpessimizing-move -CHECK-NEXT: -Wredundant-move -CHECK-NEXT: -Wreturn-std-move -CHECK-NEXT: -Wself-move -CHECK-NEXT: -Wmultichar -CHECK-NEXT: -Wrange-loop-construct -CHECK-NEXT: -Wreorder -CHECK-NEXT: -Wreorder-ctor -CHECK-NEXT: -Wreorder-init-list -CHECK-NEXT: -Wreturn-type -CHECK-NEXT: -Wreturn-type-c-linkage -CHECK-NEXT: -Wself-assign -CHECK-NEXT: -Wself-assign-overloaded -CHECK-NEXT: -Wself-assign-field -CHECK-NEXT: -Wself-move -CHECK-NEXT: -Wsizeof-array-argument -CHECK-NEXT: -Wsizeof-array-decay -CHECK-NEXT: -Wstring-plus-int -CHECK-NEXT: -Wtautological-compare -CHECK-NEXT: -Wtautological-constant-compare -CHECK-NEXT: -Wtautological-constant-out-of-range-compare -CHECK-NEXT: -Wtautological-pointer-compare -CHECK-NEXT: -Wtautological-overlap-compare -CHECK-NEXT: -Wtautological-bitwise-compare -CHECK-NEXT: -Wtautological-undefined-compare -CHECK-NEXT: -Wtautological-objc-bool-compare -CHECK-NEXT: -Wtrigraphs -CHECK-NEXT: -Wuninitialized -CHECK-NEXT: -Wsometimes-uninitialized -CHECK-NEXT: -Wstatic-self-init -CHECK-NEXT: -Wuninitialized-const-reference -CHECK-NEXT: -Wunknown-pragmas -CHECK-NEXT: -Wunused -CHECK-NEXT: -Wunused-argument -CHECK-NEXT: -Wunused-function -CHECK-NEXT: -Wunneeded-internal-declaration -CHECK-NEXT: -Wunused-label -CHECK-NEXT: -Wunused-private-field -CHECK-NEXT: -Wunused-lambda-capture -CHECK-NEXT: -Wunused-local-typedef -CHECK-NEXT: -Wunused-value -CHECK-NEXT: -Wunused-comparison -CHECK-NEXT: -Wunused-result -CHECK-NEXT: -Wunevaluated-expression -CHECK-NEXT: -Wpotentially-evaluated-expression -CHECK-NEXT: -Wunused-variable -CHECK-NEXT: -Wunused-const-variable -CHECK-NEXT: -Wunused-but-set-variable -CHECK-NEXT: -Wunused-property-ivar -CHECK-NEXT: -Wvolatile-register-var -CHECK-NEXT: -Wobjc-missing-super-calls -CHECK-NEXT: -Wobjc-designated-initializers -CHECK-NEXT: -Wobjc-flexible-array -CHECK-NEXT: -Woverloaded-virtual -CHECK-NEXT: -Wprivate-extern -CHECK-NEXT: -Wcast-of-sel-type -CHECK-NEXT: -Wextern-c-compat -CHECK-NEXT: -Wuser-defined-warnings -CHECK-NEXT: -Wparentheses -CHECK-NEXT: -Wlogical-op-parentheses -CHECK-NEXT: -Wlogical-not-parentheses -CHECK-NEXT: -Wbitwise-conditional-parentheses -CHECK-NEXT: -Wbitwise-op-parentheses -CHECK-NEXT: -Wshift-op-parentheses -CHECK-NEXT: -Woverloaded-shift-op-parentheses -CHECK-NEXT: -Wparentheses-equality -CHECK-NEXT: -Wdangling-else -CHECK-NEXT: -Wswitch -CHECK-NEXT: -Wswitch-bool -CHECK-NEXT: -Wmisleading-indentation + CHECK : -Wall CHECK - + NEXT : -Wmost + CHECK - + NEXT : -Warray - parameter CHECK - NEXT : -Wbool - operation CHECK - NEXT : -Wbitwise - instead - of - logical CHECK - NEXT : -Wchar - subscripts CHECK - NEXT : -Wcomment CHECK - NEXT : -Wdelete - non - virtual - dtor CHECK - NEXT : -Wdelete - non - abstract - non - virtual - dtor CHECK - NEXT : -Wdelete - abstract - non - virtual - dtor CHECK - NEXT : -Wformat CHECK - NEXT : -Wformat - extra - args CHECK - NEXT : -Wformat - zero - length CHECK - NEXT : -Wnonnull CHECK - NEXT : -Wformat - security CHECK - NEXT : -Wformat - y2k CHECK - NEXT : -Wformat - invalid - specifier CHECK - NEXT : -Wformat - insufficient - args CHECK - NEXT : -Wfor - loop - analysis CHECK - NEXT : -Wframe - address CHECK - NEXT : -Wimplicit CHECK - NEXT : -Wimplicit - function - declaration CHECK - NEXT : -Wimplicit - int CHECK - NEXT : -Winfinite - recursion CHECK - NEXT : -Wint - in - bool - context CHECK - NEXT : -Wmismatched - tags CHECK - NEXT : -Wmissing - braces CHECK - NEXT : -Wmove CHECK - NEXT : -Wpessimizing - move CHECK - NEXT : -Wredundant - move CHECK - NEXT : -Wreturn - std - move CHECK - NEXT : -Wself - move CHECK - NEXT : -Wmultichar CHECK - NEXT : -Wrange - loop - construct CHECK - NEXT : -Wreorder CHECK - NEXT : -Wreorder - ctor CHECK - NEXT : -Wreorder - init - list CHECK - NEXT : -Wreturn - type CHECK - NEXT : -Wreturn - type - c - linkage CHECK - NEXT : -Wself - assign CHECK - NEXT : -Wself - assign - overloaded CHECK - NEXT : -Wself - assign - field CHECK - NEXT : -Wself - move CHECK - NEXT : -Wsizeof - array - argument CHECK - NEXT : -Wsizeof - array - decay CHECK - NEXT : -Wstring - plus - int CHECK - NEXT : -Wtautological - compare CHECK - NEXT : -Wtautological - constant - compare CHECK - NEXT : -Wtautological - constant - out - of - range - compare CHECK - NEXT : -Wtautological - pointer - compare CHECK - NEXT : -Wtautological - overlap - compare CHECK - NEXT : -Wtautological - bitwise - compare CHECK - NEXT : -Wtautological - undefined - compare CHECK - NEXT : -Wtautological - objc - bool - compare CHECK - NEXT : -Wtrigraphs CHECK - NEXT : -Wuninitialized CHECK - NEXT : -Wsometimes - uninitialized CHECK - NEXT : -Wstatic - self - init CHECK - NEXT : -Wuninitialized - const - reference CHECK - NEXT : -Wunknown - pragmas CHECK - NEXT : -Wunused CHECK - NEXT : -Wunused - argument CHECK - NEXT : -Wunused - function CHECK - NEXT : -Wunneeded - internal - declaration CHECK - NEXT : -Wunused - label CHECK - NEXT : -Wunused - private - field CHECK - NEXT : -Wunused - lambda - capture CHECK - NEXT : -Wunused - local - typedef CHECK - NEXT : -Wunused - value CHECK - NEXT : -Wunused - comparison CHECK - NEXT : -Wunused - result CHECK - NEXT : -Wunevaluated - expression CHECK - NEXT : -Wpotentially - evaluated - expression CHECK - NEXT : -Wunused - variable CHECK - NEXT : -Wunused - const - variable CHECK - NEXT : -Wunused - but - set - variable CHECK - NEXT : -Wunused - property - ivar CHECK - NEXT : -Wvolatile - register - var CHECK - NEXT : -Wobjc - missing - super - calls CHECK - NEXT : -Wobjc - designated - initializers CHECK - NEXT : -Wobjc - flexible - array CHECK - NEXT : -Woverloaded - virtual CHECK - NEXT : -Wprivate - extern CHECK - NEXT : -Wcast - of - sel - type CHECK - NEXT : -Wextern - c - compat CHECK - NEXT : -Wuser - defined - warnings CHECK - NEXT : -Wparentheses CHECK - NEXT : -Wlogical - op - parentheses CHECK - NEXT : -Wlogical - not -parentheses CHECK - NEXT : -Wbitwise - conditional - parentheses CHECK - NEXT : -Wbitwise - op - parentheses CHECK - NEXT : -Wshift - op - parentheses CHECK - NEXT : -Woverloaded - shift - op - parentheses CHECK - NEXT : -Wparentheses - equality CHECK - NEXT : -Wdangling - else CHECK - NEXT : -Wswitch CHECK - NEXT : -Wswitch - bool CHECK - NEXT : -Wmisleading - indentation - -CHECK-NOT:-W + CHECK - + NOT : -W Index: clang/test/Sema/array-parameter.c =================================================================== --- /dev/null +++ clang/test/Sema/array-parameter.c @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fsyntax-only -Warray-parameter -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}}