[clang] 33d3fc4 - [C89/C2x] Diagnose calls to a function without a prototype but passes arguments

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 15 06:09:02 PDT 2022


Author: Aaron Ballman
Date: 2022-04-15T09:08:54-04:00
New Revision: 33d3fc4466479285121cbb1a62db249454da0bda

URL: https://github.com/llvm/llvm-project/commit/33d3fc4466479285121cbb1a62db249454da0bda
DIFF: https://github.com/llvm/llvm-project/commit/33d3fc4466479285121cbb1a62db249454da0bda.diff

LOG: [C89/C2x] Diagnose calls to a function without a prototype but passes arguments

This catches places where a function without a prototype is
accidentally used, potentially passing an incorrect number of
arguments, and is a follow-up to the work done in
https://reviews.llvm.org/D122895 and described in the RFC
(https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c).
The diagnostic is grouped under the new -Wdeprecated-non-prototypes
warning group and is enabled by default.

The diagnostic is disabled if the function being called was implicitly
declared (the user already gets an on-by-default warning about the
creation of the implicit function declaration, so no need to warn them
twice on the same line). Additionally, the diagnostic is disabled if
the declaration of the function without a prototype was in a location
where the user explicitly disabled deprecation warnings for functions
without prototypes (this allows the provider of the API a way to
disable the diagnostic at call sites because the lack of prototype is
intentional).

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Sema/SemaExpr.cpp
    clang/test/Analysis/nullability.c
    clang/test/Analysis/svalbuilder-float-cast.c
    clang/test/Sema/warn-deprecated-non-prototype.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 91fc57dfac595..f5d3793225bfb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -142,8 +142,12 @@ Improvements to Clang's diagnostics
   diagnostic remains off by default but is now enabled via ``-pedantic`` due to
   it being a deprecation warning. ``-Wdeprecated-non-prototype`` will diagnose
   cases where the deprecated declarations or definitions of a function without
-  a prototype will change behavior in C2x. This diagnostic is grouped under the
-  ``-Wstrict-prototypes`` warning group, but is enabled by default.
+  a prototype will change behavior in C2x. Additionally, it will diagnose calls
+  which pass arguments to a function without a prototype. This warning is
+  enabled only when the ``-Wdeprecated-non-prototype`` option is enabled at the
+  function declaration site, which allows a developer to disable the diagnostic
+  for all callers at the point of declaration. This diagnostic is grouped under
+  the ``-Wstrict-prototypes`` warning group, but is enabled by default.
 - Clang now appropriately issues an error in C when a definition of a function
   without a prototype and with no arguments is an invalid redeclaration of a
   function with a prototype. e.g., ``void f(int); void f() {}`` is now properly

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 7ffd12317167e..6547002b378f2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5554,6 +5554,10 @@ def warn_missing_sentinel : Warning <
   InGroup<Sentinel>;
 def note_sentinel_here : Note<
   "%select{function|method|block}0 has been explicitly marked sentinel here">;
+def warn_strict_uses_without_prototype : Warning<
+  "passing arguments to %select{a function|%1}0 without a prototype is "
+  "deprecated in all versions of C and is not supported in C2x">,
+  InGroup<DeprecatedNonPrototype>;
 def warn_missing_prototype : Warning<
   "no previous prototype for function %0">,
   InGroup<DiagGroup<"missing-prototypes">>, DefaultIgnore;

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index db5ab0058843f..37e54a8603f15 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7076,6 +7076,23 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
         Proto = FDecl->getType()->getAs<FunctionProtoType>();
     }
 
+    // If we still haven't found a prototype to use but there are arguments to
+    // the call, diagnose this as calling a function without a prototype.
+    // However, if we found a function declaration, check to see if
+    // -Wdeprecated-non-prototype was disabled where the function was declared.
+    // If so, we will silence the diagnostic here on the assumption that this
+    // interface is intentional and the user knows what they're doing. We will
+    // also silence the diagnostic if there is a function declaration but it
+    // was implicitly defined (the user already gets diagnostics about the
+    // creation of the implicit function declaration, so the additional warning
+    // is not helpful).
+    if (!Proto && !Args.empty() &&
+        (!FDecl || (!FDecl->isImplicit() &&
+                    !Diags.isIgnored(diag::warn_strict_uses_without_prototype,
+                                     FDecl->getLocation()))))
+      Diag(LParenLoc, diag::warn_strict_uses_without_prototype)
+          << (FDecl != nullptr) << FDecl;
+
     // Promote the arguments (C99 6.5.2.2p6).
     for (unsigned i = 0, e = Args.size(); i != e; i++) {
       Expr *Arg = Args[i];

diff  --git a/clang/test/Analysis/nullability.c b/clang/test/Analysis/nullability.c
index e0836c6798bb2..fbc03c864ad83 100644
--- a/clang/test/Analysis/nullability.c
+++ b/clang/test/Analysis/nullability.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability -Wno-deprecated-non-prototype -verify %s
 
 void it_takes_two(int a, int b);
 void function_pointer_arity_mismatch() {

diff  --git a/clang/test/Analysis/svalbuilder-float-cast.c b/clang/test/Analysis/svalbuilder-float-cast.c
index 07b28f88594b7..0ca9cecf35436 100644
--- a/clang/test/Analysis/svalbuilder-float-cast.c
+++ b/clang/test/Analysis/svalbuilder-float-cast.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker debug.ExprInspection -Wno-deprecated-non-prototype -verify %s
 void clang_analyzer_denote(int, const char *);
 void clang_analyzer_express(int);
 

diff  --git a/clang/test/Sema/warn-deprecated-non-prototype.c b/clang/test/Sema/warn-deprecated-non-prototype.c
index 33fe734e94197..78d4b0d418fbe 100644
--- a/clang/test/Sema/warn-deprecated-non-prototype.c
+++ b/clang/test/Sema/warn-deprecated-non-prototype.c
@@ -36,7 +36,7 @@ void sheesh(a) int a; {} // both-warning {{a function declaration without a prot
 void another(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
 
 int main(void) {
-  another(1, 2); // OK for now
+  another(1, 2);  // both-warning {{passing arguments to 'another' without a prototype is deprecated in all versions of C and is not supported in C2x}}
 }
 
 void order1();        // expected-warning {{a function declaration without a prototype is deprecated in all versions of C and is not supported in C2x}} \
@@ -71,3 +71,47 @@ void test(fmt)        // both-warning {{a function declaration without a prototy
 void blapp(int); // both-note {{previous declaration is here}}
 void blapp() { } // both-error {{conflicting types for 'blapp'}} \
                  // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+
+// Disable -Wdeprecated-non-prototype
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-non-prototype"
+void depr_non_prot(); // strict-warning {{a function declaration without a prototype is deprecated in all versions of C}}
+#pragma GCC diagnostic pop
+// Reenable it.
+
+// Disable -Wstrict-prototypes
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+void strict_prot(); // OK
+#pragma GCC diagnostic pop
+// Reenable it.
+
+void calls(void) {
+  // Ensure that we diagnose calls to functions without a prototype, but only
+  // if they pass arguments.
+  never_defined(); // OK
+  never_defined(1); // both-warning {{passing arguments to 'never_defined' without a prototype is deprecated in all versions of C and is not supported in C2x}}
+
+  // Ensure that calls to builtins without a traditional prototype are not
+  // diagnosed.
+  (void)__builtin_isless(1.0, 1.0); // OK
+
+  // Calling a function whose prototype was provided by a function with an
+  // identifier list is still fine.
+  func(1, 2); // OK
+
+  // Ensure that a call through a function pointer is still diagnosed properly.
+  fp f;
+  f(); // OK
+  f(1, 2); // both-warning {{passing arguments to a function without a prototype is deprecated in all versions of C and is not supported in C2x}}
+
+  // Ensure that we don't diagnose when the diagnostic group is disabled.
+  depr_non_prot(1); // OK
+  strict_prot(1); // OK
+
+  // Ensure we don't issue diagnostics if the function without a prototype was
+  // later given a prototype by a definintion. Also ensure we don't duplicate
+  // diagnostics if such a call is incorrect.
+  func(1, 2); // OK
+  func(1, 2, 3); // both-warning {{too many arguments in call to 'func'}}
+}


        


More information about the cfe-commits mailing list