Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
1 change: 0 additions & 1 deletion clang-tools-extra/clangd/IncludeFixer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ std::vector<Fix> IncludeFixer::fix(DiagnosticsEngine::Level DiagLevel,
case diag::err_array_incomplete_or_sizeless_type:
case diag::err_array_size_incomplete_type:
case diag::err_asm_incomplete_type:
case diag::err_assoc_type_incomplete:
case diag::err_bad_cast_incomplete:
case diag::err_call_function_incomplete_return:
case diag::err_call_incomplete_argument:
Expand Down
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ C Language Changes

C2y Feature Support
^^^^^^^^^^^^^^^^^^^
- Implement `WG14 N3409 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3409.pdf>`_
which removes UB around use of ``void`` expressions. In practice, this means
that ``_Generic`` selection associations may now have ``void`` type, but it
also removes UB with code like ``(void)(void)1;``.
- Implemented `WG14 N3411 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3411.pdf>`_
which allows a source file to not end with a newline character. This is still
reported as a conforming extension in earlier language modes.
Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10425,8 +10425,13 @@ def warn_type_safety_null_pointer_required : Warning<
"specified %0 type tag requires a null pointer">, InGroup<TypeSafety>;

// Generic selections.
def err_assoc_type_incomplete : Error<
"type %0 in generic association incomplete">;
def ext_assoc_type_incomplete : Extension<
"incomplete type %0 in a '_Generic' association is a C2y extension">,
InGroup<C2y>;
def warn_c2y_compat_assoc_type_incomplete : Warning<
"use of incomplete type %0 in a '_Generic' association is incompatible with "
"C standards before C2y">,
InGroup<CPre2yCompat>, DefaultIgnore;
def err_assoc_type_nonobject : Error<
"type %0 in generic association not an object type">;
def err_assoc_type_variably_modified : Error<
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1748,9 +1748,14 @@ ExprResult Sema::CreateGenericSelectionExpr(
//
// C11 6.5.1.1p2 "The type name in a generic association shall specify a
// complete object type other than a variably modified type."
// C2y removed the requirement that an expression form must
// use a complete type, though it's still as-if the type has undergone
// lvalue conversion. We support this as an extension in C23 and
// earlier because GCC does so.
unsigned D = 0;
if (ControllingExpr && Types[i]->getType()->isIncompleteType())
D = diag::err_assoc_type_incomplete;
D = LangOpts.C2y ? diag::warn_c2y_compat_assoc_type_incomplete
: diag::ext_assoc_type_incomplete;
else if (ControllingExpr && !Types[i]->getType()->isObjectType())
D = diag::err_assoc_type_nonobject;
else if (Types[i]->getType()->isVariablyModifiedType())
Expand Down
17 changes: 7 additions & 10 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2269,11 +2269,10 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
for (auto *DI : DS->decls()) {
if (VarDecl *VD = dyn_cast<VarDecl>(DI)) {
VarDeclSeen = true;
if (VD->isLocalVarDecl() && !VD->hasLocalStorage())
Diag(DI->getLocation(),
getLangOpts().C23
? diag::warn_c17_non_local_variable_decl_in_for
: diag::ext_c23_non_local_variable_decl_in_for);
if (VD->isLocalVarDecl() && !VD->hasLocalStorage()) {
Diag(DI->getLocation(), diag::err_non_local_variable_decl_in_for);
DI->setInvalidDecl();
}
} else if (!NonVarSeen) {
// Keep track of the first non-variable declaration we saw so that
// we can diagnose if we don't see any variable declarations. This
Expand All @@ -2285,9 +2284,7 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
// Diagnose if we saw a non-variable declaration but no variable
// declarations.
if (NonVarSeen && !VarDeclSeen)
Diag(NonVarSeen->getLocation(),
getLangOpts().C23 ? diag::warn_c17_non_variable_decl_in_for
: diag::ext_c23_non_variable_decl_in_for);
Diag(NonVarSeen->getLocation(), diag::err_non_variable_decl_in_for);
}
}

Expand Down Expand Up @@ -4052,9 +4049,9 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Diag(ReturnLoc, D) << CurDecl << isa<CXXDestructorDecl>(CurDecl)
<< RetValExp->getSourceRange();
}
// return (some void expression); is legal in C++.
// return (some void expression); is legal in C++ and C2y.
else if (D != diag::ext_return_has_void_expr ||
!getLangOpts().CPlusPlus) {
(!getLangOpts().CPlusPlus && !getLangOpts().C2y)) {
NamedDecl *CurDecl = getCurFunctionOrMethodDecl();

int FunctionKind = 0;
Expand Down
36 changes: 36 additions & 0 deletions clang/test/C/C2y/n3409.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// RUN: %clang_cc1 -verify -std=c2y -pedantic %s
// RUN: %clang_cc1 -verify=pre-c2y -std=c2y -Wpre-c2y-compat %s
// RUN: %clang_cc1 -verify=ext -std=c23 -pedantic %s
// expected-no-diagnostics

/* WG14 N3409: Clang 21
* Slay Some Earthly Demons X
*
* Removes the requirement that an expression with type void cannot be used in
* any way. This was making it UB to use a void expression in a _Generic
* selection expression for no good reason, as well as making it UB to cast a
* void expression to void, etc.
*/

extern void x;
void foo() {
// FIXME: this is technically an extension before C2y and should be diagnosed
// under -pedantic.
(void)(void)1;
// FIXME: same with this.
x;
_Generic(x, void: 1); /* pre-c2y-warning {{use of incomplete type 'void' in a '_Generic' association is incompatible with C standards before C2y}}
ext-warning {{incomplete type 'void' in a '_Generic' association is a C2y extension}}
*/
_Generic(x, typeof(x): 1); /* pre-c2y-warning {{use of incomplete type 'typeof (x)' (aka 'void') in a '_Generic' association is incompatible with C standards before C2y}}
ext-warning {{incomplete type 'typeof (x)' (aka 'void') in a '_Generic' association is a C2y extension}}
*/
(void)_Generic(void, default : 1); /* pre-c2y-warning {{passing a type argument as the first operand to '_Generic' is incompatible with C standards before C2y}}
ext-warning {{passing a type argument as the first operand to '_Generic' is a C2y extension}}
*/

// This is not sufficiently important of an extension to warrant a "not
// compatible with standards before C2y" warning, but it is an extension in
// C23 and earlier.
return x; // ext-warning {{void function 'foo' should not return void expression}}
}
2 changes: 1 addition & 1 deletion clang/test/Sema/generic-selection-type-extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static_assert(_Generic(ci, int : 1, const int : 0) == 1); // expected-warning {{
// but the expression operand form still rejects them.
static_assert(_Generic(struct incomplete, struct incomplete : 1, default : 0) == 1);
static_assert(_Generic(struct another_incomplete, struct incomplete : 1, default : 0) == 0);
static_assert(_Generic(1, struct also_incomplete : 1, default : 0) == 0); // expected-error {{type 'struct also_incomplete' in generic association incomplete}}
static_assert(_Generic(1, struct also_incomplete : 1, default : 0) == 0);

void foo(int);
static_assert(_Generic(__typeof__(foo), void(int) : 1, default : 0) == 1);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/Sema/generic-selection.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ void g(void);

void foo(int n) {
(void) _Generic(0, // ext-warning {{'_Generic' is a C11 extension}}
struct A: 0, // expected-error {{type 'struct A' in generic association incomplete}}
struct A: 0, // ext-warning {{incomplete type 'struct A' in a '_Generic' association is a C2y extension}}
void(): 0, // expected-error {{type 'void ()' in generic association not an object type}}
int[n]: 0); // expected-error {{type 'int[n]' in generic association is a variably modified type}}

Expand Down
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/generic-selection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ void func(struct S s) {
// is an elaborated type specifier followed by the association's value and
// it should work the same as in C.
(void)_Generic(s, struct S : 1);
(void)_Generic(s, struct T : 1);

// The rest of these cases test that we still produce a reasonable diagnostic
// when referencing an unknown type or trying to define a type in other ways.
(void)_Generic(s, struct T : 1); // expected-error {{type 'struct T' in generic association incomplete}}
(void)_Generic(s, struct U { int a; } : 1); // expected-error {{'U' cannot be defined in a type specifier}}
(void)_Generic(s, struct V : S); // expected-error {{'S' does not refer to a value}}
(void)_Generic(s, struct W : S { int b; } : 1); // expected-error {{expected '(' for function-style cast or type construction}}
Expand Down
Loading