Skip to content

Commit 4027400

Browse files
authored
[C2y] Add test coverage and documentation for WG14 N3342 (#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.
1 parent 92a9bcc commit 4027400

File tree

8 files changed

+64
-10
lines changed

8 files changed

+64
-10
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5974,3 +5974,20 @@ Clang guarantees the following behaviors:
59745974
padding bits are initialized to zero.
59755975
59765976
Currently, the above extension only applies to C source code, not C++.
5977+
5978+
Qualified function types in C
5979+
=============================
5980+
Declaring a function with a qualified type in C is undefined behavior (C23 and
5981+
earlier) or implementation-defined behavior (C2y). Clang allows a function type
5982+
to be specified with the ``const`` and ``volatile`` qualifiers, but ignores the
5983+
qualifications.
5984+
5985+
.. code-block:: c
5986+
5987+
typedef int f(void);
5988+
const volatile f func; // Qualifier on function type has no effect.
5989+
5990+
5991+
Note, Clang does not allow an ``_Atomic`` function type because
5992+
of explicit constraints against atomically qualified (arrays and) function
5993+
types.

clang/docs/ReleaseNotes.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,11 @@ C2y Feature Support
298298
paper adopts Clang's existing practice, so there were no changes to compiler
299299
behavior.
300300

301+
- Updated conformance for `N3342 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3342.pdf>`_
302+
which made qualified function types implementation-defined rather than
303+
undefined. Clang has always accepted ``const`` and ``volatile`` qualified
304+
function types by ignoring the qualifiers.
305+
301306
C23 Feature Support
302307
^^^^^^^^^^^^^^^^^^^
303308

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6241,8 +6241,9 @@ def err_typecheck_negative_array_size : Error<"array size is negative">;
62416241
def warn_typecheck_function_qualifiers_ignored : Warning<
62426242
"'%0' qualifier on function type %1 has no effect">,
62436243
InGroup<IgnoredQualifiers>;
6244-
def warn_typecheck_function_qualifiers_unspecified : Warning<
6245-
"'%0' qualifier on function type %1 has unspecified behavior">;
6244+
def ext_typecheck_function_qualifiers_unspecified : ExtWarn<
6245+
"'%0' qualifier on function type %1 has no effect and is a Clang extension">,
6246+
InGroup<IgnoredQualifiers>;
62466247
def warn_typecheck_reference_qualifiers : Warning<
62476248
"'%0' qualifier on reference type %1 has no effect">,
62486249
InGroup<IgnoredReferenceQualifiers>;

clang/lib/Sema/SemaType.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1500,16 +1500,19 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
15001500
// C99 6.7.3p8:
15011501
// If the specification of a function type includes any type qualifiers,
15021502
// the behavior is undefined.
1503+
// C2y changed this behavior to be implementation-defined. Clang defines
1504+
// the behavior in all cases to ignore the qualifier, as in C++.
15031505
// C++11 [dcl.fct]p7:
15041506
// The effect of a cv-qualifier-seq in a function declarator is not the
15051507
// same as adding cv-qualification on top of the function type. In the
15061508
// latter case, the cv-qualifiers are ignored.
15071509
if (Result->isFunctionType()) {
1510+
unsigned DiagId = diag::warn_typecheck_function_qualifiers_ignored;
1511+
if (!S.getLangOpts().CPlusPlus && !S.getLangOpts().C2y)
1512+
DiagId = diag::ext_typecheck_function_qualifiers_unspecified;
15081513
diagnoseAndRemoveTypeQualifiers(
15091514
S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile,
1510-
S.getLangOpts().CPlusPlus
1511-
? diag::warn_typecheck_function_qualifiers_ignored
1512-
: diag::warn_typecheck_function_qualifiers_unspecified);
1515+
DiagId);
15131516
// No diagnostic for 'restrict' or '_Atomic' applied to a
15141517
// function type; we'll diagnose those later, in BuildQualifiedType.
15151518
}

clang/test/C/C2y/n3342.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -verify=expected,both -std=c2y -Wall -pedantic %s
2+
// RUN: %clang_cc1 -verify=clang,both -Wall -pedantic %s
3+
4+
/* WG14 N3342: Yes
5+
* Slay Some Earthly Demons IV
6+
*
7+
* Qualified function types are now implementation-defined instead of
8+
* undefined. Clang strips the qualifiers.
9+
*/
10+
11+
typedef int f(void);
12+
13+
const f one; /* expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect}}
14+
clang-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
15+
*/
16+
volatile f two; /* expected-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect}}
17+
clang-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
18+
*/
19+
20+
const volatile f three; /* expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect}}
21+
clang-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
22+
expected-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect}}
23+
clang-warning {{'volatile' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
24+
*/
25+
26+
// Atomic types have an explicit constraint making it ill-formed.
27+
_Atomic f four; // both-error {{_Atomic cannot be applied to function type 'f' (aka 'int (void)')}}
28+
29+
// There's no point to testing 'restrict' because that requires a pointer type.

clang/test/Misc/warning-flags.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This test serves two purposes:
1818

1919
The list of warnings below should NEVER grow. It should gradually shrink to 0.
2020

21-
CHECK: Warnings without flags (62):
21+
CHECK: Warnings without flags (61):
2222

2323
CHECK-NEXT: ext_expected_semi_decl_list
2424
CHECK-NEXT: ext_missing_whitespace_after_macro_name
@@ -76,7 +76,6 @@ CHECK-NEXT: warn_register_objc_catch_parm
7676
CHECK-NEXT: warn_related_result_type_compatibility_class
7777
CHECK-NEXT: warn_related_result_type_compatibility_protocol
7878
CHECK-NEXT: warn_template_export_unsupported
79-
CHECK-NEXT: warn_typecheck_function_qualifiers
8079
CHECK-NEXT: warn_undef_interface
8180
CHECK-NEXT: warn_undef_interface_suggest
8281
CHECK-NEXT: warn_undef_protocolref

clang/test/Sema/declspec.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ int gv2;
1616
static void buggy(int *x) { }
1717

1818
// Type qualifiers.
19-
typedef int f(void);
19+
typedef int f(void);
2020
typedef f* fptr;
21-
const f* v1; // expected-warning {{qualifier on function type 'f' (aka 'int (void)') has unspecified behavior}}
21+
const f* v1; // expected-warning {{'const' qualifier on function type 'f' (aka 'int (void)') has no effect and is a Clang extension}}
2222
__restrict__ f* v2; // expected-error {{restrict requires a pointer or reference ('f' (aka 'int (void)') is invalid)}}
2323
__restrict__ fptr v3; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}
2424
f *__restrict__ v4; // expected-error {{pointer to function type 'f' (aka 'int (void)') may not be 'restrict' qualified}}

clang/www/c_status.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ <h2 id="c2y">C2y implementation status</h2>
196196
<tr>
197197
<td>Slay Some Earthly Demons IV</td>
198198
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3342.pdf">N3342</a></td>
199-
<td class="unknown" align="center">Unknown</td>
199+
<td class="full" align="center">Yes</td>
200200
</tr>
201201
<tr>
202202
<td>Slay Some Earthly Demons VI</td>

0 commit comments

Comments
 (0)