[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