[clang] [C2y] Add test coverage and documentation for WG14 N3342 (PR #115494)

via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 8 06:55:36 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Aaron Ballman (AaronBallman)

<details>
<summary>Changes</summary>

This paper made qualified function types implementation-defined. We have always supported this as an extension, so now we're documenting our behavior.

Note, we still warn about this by default even in C2y mode because a qualified function type is a sign of programmer confusion.

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


8 Files Affected:

- (modified) clang/docs/LanguageExtensions.rst (+17) 
- (modified) clang/docs/ReleaseNotes.rst (+5) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3-2) 
- (modified) clang/lib/Sema/SemaType.cpp (+6-3) 
- (added) clang/test/C/C2y/n3342.c (+29) 
- (modified) clang/test/Misc/warning-flags.c (+1-2) 
- (modified) clang/test/Sema/declspec.c (+2-2) 
- (modified) clang/www/c_status.html (+1-1) 


``````````diff
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index f7285352b9deb9..a051eb95898ecf 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -5974,3 +5974,20 @@ Clang guarantees the following behaviors:
   padding bits are initialized to zero.
 
 Currently, the above extension only applies to C source code, not C++.
+
+Qualified function types in C
+=============================
+Declaring a function with a qualified type in C is undefined behavior (C23 and
+earlier) or implementation-defined behavior (C2y). Clang allows a function type
+to be specified with the ``const`` and ``volatile`` qualifiers, but ignores the
+qualifications.
+
+.. code-block:: c
+
+   typedef int f(void);
+   const volatile f func; // Qualifier on function type has no effect.
+
+
+Note, Clang does not allow an ``_Atomic`` function type because
+of explicit constraints against atomically qualified (arrays and) function
+types.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d0c43ff11f7bae..d4bf05651a63eb 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -298,6 +298,11 @@ C2y Feature Support
   paper adopts Clang's existing practice, so there were no changes to compiler
   behavior.
 
+- Updated conformance for `N3342 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3342.pdf>`_
+  which made qualified function types implementation-defined rather than
+  undefined. Clang has always accepted ``const`` and ``volatile`` qualified
+  function types by ignoring the qualifiers.
+
 C23 Feature Support
 ^^^^^^^^^^^^^^^^^^^
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6a244c276facd6..ae95ea6d558cb0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6241,8 +6241,9 @@ def err_typecheck_negative_array_size : Error<"array size is negative">;
 def warn_typecheck_function_qualifiers_ignored : Warning<
   "'%0' qualifier on function type %1 has no effect">,
   InGroup<IgnoredQualifiers>;
-def warn_typecheck_function_qualifiers_unspecified : Warning<
-  "'%0' qualifier on function type %1 has unspecified behavior">;
+def ext_typecheck_function_qualifiers_unspecified : ExtWarn<
+  "'%0' qualifier on function type %1 has no effect and is a Clang extension">,
+  InGroup<IgnoredQualifiers>;
 def warn_typecheck_reference_qualifiers : Warning<
   "'%0' qualifier on reference type %1 has no effect">,
   InGroup<IgnoredReferenceQualifiers>;
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index e526a11973975d..515b9f689a248a 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1500,16 +1500,19 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
     // C99 6.7.3p8:
     //   If the specification of a function type includes any type qualifiers,
     //   the behavior is undefined.
+    // C2y changed this behavior to be implementation-defined. Clang defines
+    // the behavior in all cases to ignore the qualifier, as in C++.
     // C++11 [dcl.fct]p7:
     //   The effect of a cv-qualifier-seq in a function declarator is not the
     //   same as adding cv-qualification on top of the function type. In the
     //   latter case, the cv-qualifiers are ignored.
     if (Result->isFunctionType()) {
+      unsigned DiagId = diag::warn_typecheck_function_qualifiers_ignored;
+      if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().C2y)
+        DiagId = diag::ext_typecheck_function_qualifiers_unspecified;
       diagnoseAndRemoveTypeQualifiers(
           S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile,
-          S.getLangOpts().CPlusPlus
-              ? diag::warn_typecheck_function_qualifiers_ignored
-              : diag::warn_typecheck_function_qualifiers_unspecified);
+          DiagId);
       // No diagnostic for 'restrict' or '_Atomic' applied to a
       // function type; we'll diagnose those later, in BuildQualifiedType.
     }
diff --git a/clang/test/C/C2y/n3342.c b/clang/test/C/C2y/n3342.c
new file mode 100644
index 00000000000000..3c5282c7831f32
--- /dev/null
+++ b/clang/test/C/C2y/n3342.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -verify=expected,both -std=c2y -Wall -pedantic %s
+// RUN: %clang_cc1 -verify=clang,both -Wall -pedantic %s
+
+/* WG14 N3342: Yes
+ * Slay Some Earthly Demons IV
+ *
+ * Qualified function types are now implementation-defined instead of
+ * undefined. Clang strips the qualifiers.
+ */
+
+typedef int f(void);
+
+const f one;      /* expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect}}
+                     clang-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
+                   */
+volatile f two;   /* expected-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect}}
+                     clang-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
+                   */
+
+const volatile f three; /* expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect}}
+                           clang-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
+                           expected-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect}}
+                           clang-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
+                         */
+
+// Atomic types have an explicit constraint making it ill-formed.
+_Atomic f four;   // both-error {{_Atomic cannot be applied to function type 'f' (aka 'int (void)')}}
+
+// There's no point to testing 'restrict' because that requires a pointer type.
diff --git a/clang/test/Misc/warning-flags.c b/clang/test/Misc/warning-flags.c
index 80c01099140f79..1fd02440833359 100644
--- a/clang/test/Misc/warning-flags.c
+++ b/clang/test/Misc/warning-flags.c
@@ -18,7 +18,7 @@ This test serves two purposes:
 
 The list of warnings below should NEVER grow.  It should gradually shrink to 0.
 
-CHECK: Warnings without flags (62):
+CHECK: Warnings without flags (61):
 
 CHECK-NEXT:   ext_expected_semi_decl_list
 CHECK-NEXT:   ext_missing_whitespace_after_macro_name
@@ -76,7 +76,6 @@ CHECK-NEXT:   warn_register_objc_catch_parm
 CHECK-NEXT:   warn_related_result_type_compatibility_class
 CHECK-NEXT:   warn_related_result_type_compatibility_protocol
 CHECK-NEXT:   warn_template_export_unsupported
-CHECK-NEXT:   warn_typecheck_function_qualifiers
 CHECK-NEXT:   warn_undef_interface
 CHECK-NEXT:   warn_undef_interface_suggest
 CHECK-NEXT:   warn_undef_protocolref
diff --git a/clang/test/Sema/declspec.c b/clang/test/Sema/declspec.c
index 88ff83a2149067..ca3216bd2fafc4 100644
--- a/clang/test/Sema/declspec.c
+++ b/clang/test/Sema/declspec.c
@@ -16,9 +16,9 @@ int gv2;
 static void buggy(int *x) { }
 
 // Type qualifiers.
-typedef int f(void); 
+typedef int f(void);
 typedef f* fptr;
-const f* v1;         // expected-warning {{qualifier on function type 'f' (aka 'int (void)') has unspecified behavior}}
+const f* v1;         // expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
 __restrict__ f* v2;  // expected-error {{restrict requires a pointer or reference ('f' (aka 'int (void)') is invalid)}}
 __restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
 f *__restrict__ v4;   // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
diff --git a/clang/www/c_status.html b/clang/www/c_status.html
index 989a572ae70fb6..fa2411e674d768 100644
--- a/clang/www/c_status.html
+++ b/clang/www/c_status.html
@@ -196,7 +196,7 @@ <h2 id="c2y">C2y implementation status</h2>
     <tr>
       <td>Slay Some Earthly Demons IV</td>
       <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3342.pdf">N3342</a></td>
-      <td class="unknown" align="center">Unknown</td>
+      <td class="full" align="center">Yes</td>
     </tr>
     <tr>
       <td>Slay Some Earthly Demons VI</td>

``````````

</details>


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


More information about the cfe-commits mailing list