Skip to content

[C2y] Add test coverage and documentation for WG14 N3342 #115494

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
5 changes: 5 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
^^^^^^^^^^^^^^^^^^^

Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
Expand Down
29 changes: 29 additions & 0 deletions clang/test/C/C2y/n3342.c
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 1 addition & 2 deletions clang/test/Misc/warning-flags.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions clang/test/Sema/declspec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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}}
Expand Down
2 changes: 1 addition & 1 deletion clang/www/c_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Loading