https://github.com/AaronBallman created https://github.com/llvm/llvm-project/pull/115494
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. >From f82110a6443620049db0f0ac1f459e6bde86c260 Mon Sep 17 00:00:00 2001 From: Aaron Ballman <aa...@aaronballman.com> Date: Fri, 8 Nov 2024 09:52:40 -0500 Subject: [PATCH] [C2y] Add test coverage and documentation for WG14 N3342 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. --- clang/docs/LanguageExtensions.rst | 17 +++++++++++ clang/docs/ReleaseNotes.rst | 5 ++++ .../clang/Basic/DiagnosticSemaKinds.td | 5 ++-- clang/lib/Sema/SemaType.cpp | 9 ++++-- clang/test/C/C2y/n3342.c | 29 +++++++++++++++++++ clang/test/Misc/warning-flags.c | 3 +- clang/test/Sema/declspec.c | 4 +-- clang/www/c_status.html | 2 +- 8 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 clang/test/C/C2y/n3342.c 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> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits