[clang] [clang] support Wold-style-declaration as gcc (PR #78837)

via cfe-commits cfe-commits at lists.llvm.org
Sat Jan 20 01:25:52 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: None (SihangZhu)

<details>
<summary>Changes</summary>

Storage-class specifiers like static are not the first things in a declaration. According to the C Standard, this usage is obsolescent. This patch add a diagnose to warn it.
This is a counterpart of gcc's Wold-style-declaration.

---
Full diff: https://github.com/llvm/llvm-project/pull/78837.diff


4 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticCommonKinds.td (+2) 
- (modified) clang/include/clang/Basic/DiagnosticGroups.td (+2) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+11) 
- (added) clang/test/Parser/old-style-declaration.c (+33) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 5544dc88004d9a..0d29316767e950 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -84,6 +84,8 @@ def err_param_redefinition : Error<"redefinition of parameter %0">;
 def warn_method_param_redefinition : Warning<"redefinition of method parameter %0">;
 def warn_method_param_declaration : Warning<"redeclaration of method parameter %0">,
   InGroup<DuplicateArgDecl>, DefaultIgnore;
+def warn_old_style_declaration: Warning <"'%0' is not at beginning of declaration">,
+  InGroup<OldStyleDeclaration>, DefaultIgnore;
 def err_invalid_storage_class_in_func_decl : Error<
   "invalid storage class specifier in function declarator">;
 def err_expected_namespace_name : Error<"expected namespace name">;
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 6765721ae7002c..ebe751a9947971 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -578,6 +578,7 @@ def ObjCPointerIntrospect : DiagGroup<"deprecated-objc-pointer-introspection", [
 def ObjCMultipleMethodNames : DiagGroup<"objc-multiple-method-names">;
 def ObjCFlexibleArray : DiagGroup<"objc-flexible-array">;
 def ObjCBoxing : DiagGroup<"objc-boxing">;
+def OldStyleDeclaration : DiagGroup<"old-style-declaration">;
 def CompletionHandler : DiagGroup<"completion-handler">;
 def CalledOnceParameter : DiagGroup<"called-once-parameter", [CompletionHandler]>;
 def OpenCLUnsupportedRGBA: DiagGroup<"opencl-unsupported-rgba">;
@@ -1026,6 +1027,7 @@ def Extra : DiagGroup<"extra", [
     EmptyInitStatement,
     StringConcatation,
     FUseLdPath,
+    OldStyleDeclaration,
   ]>;
 
 def Most : DiagGroup<"most", [
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 356e7851ec639c..ab1555ebc19088 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3348,6 +3348,7 @@ void Parser::ParseDeclarationSpecifiers(
   while (true) {
     bool isInvalid = false;
     bool isStorageClass = false;
+    bool isFunctionSpecifier = false;
     const char *PrevSpec = nullptr;
     unsigned DiagID = 0;
 
@@ -4092,6 +4093,7 @@ void Parser::ParseDeclarationSpecifiers(
     // function-specifier
     case tok::kw_inline:
       isInvalid = DS.setFunctionSpecInline(Loc, PrevSpec, DiagID);
+      isFunctionSpecifier = true;
       break;
     case tok::kw_virtual:
       // C++ for OpenCL does not allow virtual function qualifier, to avoid
@@ -4104,6 +4106,7 @@ void Parser::ParseDeclarationSpecifiers(
         isInvalid = true;
       } else {
         isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
+        isFunctionSpecifier = true;
       }
       break;
     case tok::kw_explicit: {
@@ -4140,12 +4143,14 @@ void Parser::ParseDeclarationSpecifiers(
       }
       isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
                                              ExplicitSpec, CloseParenLoc);
+      isFunctionSpecifier = true;
       break;
     }
     case tok::kw__Noreturn:
       if (!getLangOpts().C11)
         Diag(Tok, diag::ext_c11_feature) << Tok.getName();
       isInvalid = DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
+      isFunctionSpecifier = true;
       break;
 
     // alignment-specifier
@@ -4552,6 +4557,12 @@ void Parser::ParseDeclarationSpecifiers(
       continue;
     }
 
+    unsigned Specs = DS.getParsedSpecifiers();
+    if (!getLangOpts().CPlusPlus && (isFunctionSpecifier || isStorageClass)) {
+      if (Specs & DeclSpec::PQ_TypeQualifier || DS.hasTypeSpecifier())
+        Diag(Tok, diag::warn_old_style_declaration) << Tok.getName();
+    }
+
     DS.SetRangeEnd(ConsumedEnd.isValid() ? ConsumedEnd : Tok.getLocation());
 
     // If the specifier wasn't legal, issue a diagnostic.
diff --git a/clang/test/Parser/old-style-declaration.c b/clang/test/Parser/old-style-declaration.c
new file mode 100644
index 00000000000000..e7ccea32bfa957
--- /dev/null
+++ b/clang/test/Parser/old-style-declaration.c
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -Wold-style-declaration %s
+// RUN: %clang_cc1 -fsyntax-only -verify -Wextra %s
+
+static int x0;
+int __attribute__ ((aligned (16))) static x1; // expected-warning {{'static' is not at beginning of declaration}}
+
+extern int x2;
+int extern x3; // expected-warning {{'extern' is not at beginning of declaration}}
+
+typedef int x4;
+int typedef x5; // expected-warning {{'typedef' is not at beginning of declaration}}
+
+void g (int);
+
+void
+f (void)
+{
+  auto int x6 = 0;
+  int auto x7 = 0; // expected-warning {{'auto' is not at beginning of declaration}}
+  register int x8 = 0;
+  int register x9 = 0; // expected-warning {{'register' is not at beginning of declaration}}
+  g (x6 + x7 + x8 + x9);
+}
+
+const static int x10; // expected-warning {{'static' is not at beginning of declaration}}
+
+/* Attributes are OK before storage class specifiers, since some
+   attributes are like such specifiers themselves.  */
+
+__attribute__((format(printf, 1, 2))) static void h (const char *, ...);
+__attribute__((format(printf, 1, 2))) void static i (const char *, ...); // expected-warning {{'static' is not at beginning of declaration}}
+
+static __thread int var = 5; // not-expected-warning {{'__thread' is not at beginning of declaration}}
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/78837


More information about the cfe-commits mailing list