This is an archive of the discontinued LLVM Phabricator instance.

Sema: Don't erroneously reject `void{}`
Needs ReviewPublic

Authored by aaronpuchert on Nov 13 2021, 6:19 PM.

Details

Reviewers
rsmith
Summary

This is explicitly allowed via [expr.type.conv], if the initialization
list is empty.

Diff Detail

Event Timeline

aaronpuchert requested review of this revision.Nov 13 2021, 6:19 PM
aaronpuchert created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptNov 13 2021, 6:19 PM
Herald added a subscriber: cfe-commits. · View Herald Transcript

CC @Tyker for the changes to SemaCXX/attr-annotate.cpp.

clang/include/clang/Basic/DiagnosticSemaKinds.td
5848–5849

Might also consider it a narrowing conversion. But I can't find the standard specifically calling it that.

clang/test/CXX/expr/expr.post/expr.type.conv/p2.cpp
12

With parantheses this is (correctly) allowed:

If the initializer is a parenthesized single expression, the type conversion expression is equivalent to the corresponding cast expression.

[expr.static.cast]p6:

Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression ([expr.prop]).

Not sure if we need a test for that.

rsmith added a comment.Jan 7 2022, 3:14 PM

This is CWG issue 2351. Please add a corresponding test to tests/CXX/drs/dr23xx.cpp.

clang/lib/Sema/SemaInit.cpp
1311–1319

Hm, this seems like the wrong place for this check, given the wording -- the language rule is specific to functional casts, and shouldn't apply to initialization of void-typed objects in general -- but perhaps it's the best place we have (and I think we deal with the void() case here in SemaInit too). Please at least make sure that we still properly reject things like:

void f() {
  return {};
}

We also need to decide whether to accept the compound-literal form of this:

void g() {
  (void){};
}

GCC trunk does, but I'm not sure whether that's intentional or an oversight. We certainly shouldn't accept that (without a diagnostic, at least) in C.

shafik added a subscriber: shafik.Sep 21 2023, 12:44 PM

It looks like this is almost there, can we get it over the line?

Herald added a project: Restricted Project. · View Herald TranscriptSep 21 2023, 12:44 PM

Yeah, we should get this over the line. I'm still not quite sure where to put the check. Reading @rsmith's comment again, SemaInit might perhaps be acceptable for now, except that I should add the additional tests (in case we don't have them already).

I think we also need D113837, because otherwise void is being used as a placeholder. In any event, I should at least rebase the patches and check if they still work.

clang/lib/Sema/SemaInit.cpp
1311–1319

Hm, this seems like the wrong place for this check, given the wording -- the language rule is specific to functional casts, and shouldn't apply to initialization of void-typed objects in general -- but perhaps it's the best place we have (and I think we deal with the void() case here in SemaInit too).

So we should unconditionally allow it here and check later in CastOperation::CheckCXXCStyleCast? It handles void target types already, but only for [expr.static.cast]p6:

Any expression can be explicitly converted to type cv void, in which case it becomes a discarded-value expression ([expr.prop]).

Indeed we don't create a CXXFunctionalCastExpr for void() but a CXXScalarValueInitExpr (though probably for legacy reasons). But it should be the proper place, I agree.

Please at least make sure that we still properly reject things like:

void f() {
  return {};
}

That fails as before with

<stdin>:2:3: error: void function 'f' must not return a value
  return {};
  ^      ~~

We also need to decide whether to accept the compound-literal form of this:

void g() {
  (void){};
}

That is rejected in C and C++ with

<stdin>:2:3: error: variable has incomplete type 'void'
  (void){};
  ^~~~~~~~