Allow parameter names to be elided in a function definition in C.
authorAaron Ballman <aaron@aaronballman.com>
Tue, 7 Apr 2020 18:42:29 +0000 (14:42 -0400)
committerAaron Ballman <aaron@aaronballman.com>
Tue, 7 Apr 2020 18:43:38 +0000 (14:43 -0400)
WG14 has adopted N2480 (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2480.pdf)
into C2x at the meetings last week, allowing parameter names of a function
definition to be elided. This patch relaxes the error so that C++ and C2x do not
diagnose this situation, and modes before C2x will allow it as an extension.

This also adds the same feature to ObjC blocks under the assumption that ObjC
wishes to follow the C standard in this regard.

clang/include/clang/Basic/DiagnosticGroups.td
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/Sema/block-args.c
clang/test/Sema/c89.c
clang/test/Sema/function.c

index 1175476..87444e5 100644 (file)
@@ -985,6 +985,9 @@ def C11 : DiagGroup<"c11-extensions">;
 // A warning group for warnings about using C99 features as extensions.
 def C99 : DiagGroup<"c99-extensions", [C99Designator]>;
 
+// A warning group for warnings about using C2x features as extensions.
+def C2x : DiagGroup<"c2x-extensions">;
+
 // A warning group for warnings about GCC extensions.
 def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
                             GNUAutoType,
index 148f23f..35a7a05 100644 (file)
@@ -275,7 +275,9 @@ def err_bad_parameter_name : Error<
   "%0 cannot be the name of a parameter">;
 def err_bad_parameter_name_template_id : Error<
   "parameter name cannot have template arguments">;
-def err_parameter_name_omitted : Error<"parameter name omitted">;
+def ext_parameter_name_omitted_c2x : ExtWarn<
+  "omitting the parameter name in a function definition is a C2x extension">,
+  InGroup<C2x>;
 def err_anyx86_interrupt_attribute : Error<
   "%select{x86|x86-64}0 'interrupt' attribute only applies to functions that "
   "have %select{a 'void' return type|"
index 736a887..dc51476 100644 (file)
@@ -12883,11 +12883,12 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
 
     // C99 6.9.1p5: If the declarator includes a parameter type list, the
     // declaration of each parameter shall include an identifier.
-    if (CheckParameterNames &&
-        Param->getIdentifier() == nullptr &&
-        !Param->isImplicit() &&
-        !getLangOpts().CPlusPlus)
-      Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+    if (CheckParameterNames && Param->getIdentifier() == nullptr &&
+        !Param->isImplicit() && !getLangOpts().CPlusPlus) {
+      // Diagnose this as an extension in C17 and earlier.
+      if (!getLangOpts().C2x)
+        Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x);
+    }
 
     // C99 6.7.5.3p12:
     //   If the function declarator is not part of a definition of that
index a4f9c22..c52c6fb 100644 (file)
@@ -14646,11 +14646,12 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
   if (ExplicitSignature) {
     for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) {
       ParmVarDecl *Param = ExplicitSignature.getParam(I);
-      if (Param->getIdentifier() == nullptr &&
-          !Param->isImplicit() &&
-          !Param->isInvalidDecl() &&
-          !getLangOpts().CPlusPlus)
-        Diag(Param->getLocation(), diag::err_parameter_name_omitted);
+      if (Param->getIdentifier() == nullptr && !Param->isImplicit() &&
+          !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) {
+        // Diagnose this as an extension in C17 and earlier.
+        if (!getLangOpts().C2x)
+          Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x);
+      }
       Params.push_back(Param);
     }
 
index 69cf047..99e3220 100644 (file)
@@ -31,8 +31,8 @@ int main(int argc, char** argv) {
 
 // radar 7528255
 void f0() {
-  ^(int, double d, char) {}(1, 1.34, 'a'); // expected-error {{parameter name omitted}} \
-                                          // expected-error {{parameter name omitted}}
+  ^(int, double d, char) {}(1, 1.34, 'a'); // expected-warning {{omitting the parameter name in a function definition is a C2x extension}} \
+                                           // expected-warning {{omitting the parameter name in a function definition is a C2x extension}}
 }
 
 // rdar://problem/8962770
index c9e81f1..89eda93 100644 (file)
@@ -45,7 +45,7 @@ void test8(int, x);  /* expected-warning {{declaration specifier missing, defaul
 
 typedef int sometype;
 int a(sometype, y) {return 0;}  /* expected-warning {{declaration specifier missing, defaulting to 'int'}} \
-                                   expected-error {{parameter name omitted}}*/
+                                   expected-warning {{omitting the parameter name in a function definition is a C2x extension}}*/
 
 
 
index 26be614..69262bb 100644 (file)
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -pedantic
+// RUN: %clang_cc1 %s -fsyntax-only -verify -verify=c2x -pedantic
+// RUN: %clang_cc1 %s -fsyntax-only -std=c2x -verify -pedantic
 
 // PR1892, PR11354
 void f(double a[restrict][5]) { __typeof(a) x = 10; } // expected-warning {{(aka 'double (*restrict)[5]')}}
@@ -30,7 +31,7 @@ void t10(){}
 void t11(){t10(1);} // expected-warning{{too many arguments}}
 
 // PR3208
-void t12(int) {}  // expected-error{{parameter name omitted}}
+void t12(int) {}  // c2x-warning{{omitting the parameter name in a function definition is a C2x extension}}
 
 // PR2790
 void t13() {
@@ -80,7 +81,8 @@ typedef void fn_t(void);
 fn_t t17;
 
 // PR4049
-unknown_type t18(void*) {   // expected-error {{unknown type name 'unknown_type'}} expected-error{{parameter name omitted}}
+unknown_type t18(void*) {   // expected-error {{unknown type name 'unknown_type'}} \
+                            // c2x-warning {{omitting the parameter name in a function definition is a C2x extension}}
 }
 
 unknown_type t19(int* P) {   // expected-error {{unknown type name 'unknown_type'}}