forked from OSchip/llvm-project
Extend init-statement to allow alias-declaration
Implement P2360R0 in C++23 mode and as an extension in older languages mode.
This commit is contained in:
parent
d68b59f3eb
commit
ff013b6100
|
@ -134,6 +134,8 @@ C++20 Feature Support
|
|||
C++2b Feature Support
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
- Implemented `P1938R3: if consteval <https://wg21.link/P1938R3>`_.
|
||||
- Implemented `P2360R0: Extend init-statement to allow alias-declaration <https://wg21.link/P2360R0>`_.
|
||||
|
||||
|
||||
CUDA Language Changes in Clang
|
||||
------------------------------
|
||||
|
|
|
@ -549,6 +549,12 @@ def err_expected_init_in_condition_lparen : Error<
|
|||
"variable declaration in condition cannot have a parenthesized initializer">;
|
||||
def err_extraneous_rparen_in_condition : Error<
|
||||
"extraneous ')' after condition, expected a statement">;
|
||||
def ext_alias_in_init_statement : ExtWarn<
|
||||
"alias declaration in this context is a C++2b extension">,
|
||||
InGroup<CXX2b>;
|
||||
def warn_cxx20_alias_in_init_statement : Warning<
|
||||
"alias declaration in this context is incompatible with C++ standards before C++2b">,
|
||||
DefaultIgnore, InGroup<CXXPre2bCompat>;
|
||||
def warn_dangling_else : Warning<
|
||||
"add explicit braces to avoid dangling else">,
|
||||
InGroup<DanglingElse>;
|
||||
|
|
|
@ -1977,6 +1977,9 @@ private:
|
|||
Sema::ConditionKind CK,
|
||||
ForRangeInfo *FRI = nullptr,
|
||||
bool EnterForConditionScope = false);
|
||||
DeclGroupPtrTy
|
||||
ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
|
||||
ParsedAttributesWithRange &Attrs);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Coroutines
|
||||
|
@ -2396,7 +2399,8 @@ private:
|
|||
if (getLangOpts().OpenMP)
|
||||
Actions.startOpenMPLoop();
|
||||
if (getLangOpts().CPlusPlus)
|
||||
return isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true);
|
||||
return Tok.is(tok::kw_using) ||
|
||||
isCXXSimpleDeclaration(/*AllowForRangeDecl=*/true);
|
||||
return isDeclarationSpecifier(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -678,7 +678,10 @@ Parser::ParseUsingDeclaration(
|
|||
SourceLocation UsingLoc, SourceLocation &DeclEnd,
|
||||
ParsedAttributesWithRange &PrefixAttrs, AccessSpecifier AS) {
|
||||
SourceLocation UELoc;
|
||||
if (TryConsumeToken(tok::kw_enum, UELoc)) {
|
||||
bool InInitStatement = Context == DeclaratorContext::SelectionInit ||
|
||||
Context == DeclaratorContext::ForInit;
|
||||
|
||||
if (TryConsumeToken(tok::kw_enum, UELoc) && !InInitStatement) {
|
||||
// C++20 using-enum
|
||||
Diag(UELoc, getLangOpts().CPlusPlus20
|
||||
? diag::warn_cxx17_compat_using_enum_declaration
|
||||
|
@ -714,6 +717,9 @@ Parser::ParseUsingDeclaration(
|
|||
ParsedAttributesWithRange MisplacedAttrs(AttrFactory);
|
||||
MaybeParseCXX11Attributes(MisplacedAttrs);
|
||||
|
||||
if (InInitStatement && Tok.isNot(tok::identifier))
|
||||
return nullptr;
|
||||
|
||||
UsingDeclarator D;
|
||||
bool InvalidDeclarator = ParseUsingDeclarator(Context, D);
|
||||
|
||||
|
@ -732,7 +738,7 @@ Parser::ParseUsingDeclaration(
|
|||
}
|
||||
|
||||
// Maybe this is an alias-declaration.
|
||||
if (Tok.is(tok::equal)) {
|
||||
if (Tok.is(tok::equal) || InInitStatement) {
|
||||
if (InvalidDeclarator) {
|
||||
SkipUntil(tok::semi);
|
||||
return nullptr;
|
||||
|
|
|
@ -1910,6 +1910,28 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
|
|||
}
|
||||
}
|
||||
|
||||
Parser::DeclGroupPtrTy
|
||||
Parser::ParseAliasDeclarationInInitStatement(DeclaratorContext Context,
|
||||
ParsedAttributesWithRange &Attrs) {
|
||||
assert(Tok.is(tok::kw_using) && "Expected using");
|
||||
assert((Context == DeclaratorContext::ForInit ||
|
||||
Context == DeclaratorContext::SelectionInit) &&
|
||||
"Unexpected Declarator Context");
|
||||
DeclGroupPtrTy DG;
|
||||
SourceLocation DeclStart = ConsumeToken(), DeclEnd;
|
||||
|
||||
DG = ParseUsingDeclaration(Context, {}, DeclStart, DeclEnd, Attrs, AS_none);
|
||||
if (!DG)
|
||||
return DG;
|
||||
|
||||
Diag(DeclStart, !getLangOpts().CPlusPlus2b
|
||||
? diag::ext_alias_in_init_statement
|
||||
: diag::warn_cxx20_alias_in_init_statement)
|
||||
<< SourceRange(DeclStart, DeclEnd);
|
||||
|
||||
return DG;
|
||||
}
|
||||
|
||||
/// ParseCXXCondition - if/switch/while condition expression.
|
||||
///
|
||||
/// condition:
|
||||
|
@ -2017,9 +2039,14 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt,
|
|||
|
||||
case ConditionOrInitStatement::InitStmtDecl: {
|
||||
WarnOnInit();
|
||||
DeclGroupPtrTy DG;
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DeclGroupPtrTy DG = ParseSimpleDeclaration(
|
||||
DeclaratorContext::SelectionInit, DeclEnd, attrs, /*RequireSemi=*/true);
|
||||
if (Tok.is(tok::kw_using))
|
||||
DG = ParseAliasDeclarationInInitStatement(
|
||||
DeclaratorContext::SelectionInit, attrs);
|
||||
else
|
||||
DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd,
|
||||
attrs, /*RequireSemi=*/true);
|
||||
*InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd);
|
||||
return ParseCXXCondition(nullptr, Loc, CK);
|
||||
}
|
||||
|
|
|
@ -1823,6 +1823,7 @@ bool Parser::isForRangeIdentifier() {
|
|||
/// [C++] for-init-statement:
|
||||
/// [C++] expression-statement
|
||||
/// [C++] simple-declaration
|
||||
/// [C++2b] alias-declaration
|
||||
///
|
||||
/// [C++0x] for-range-declaration:
|
||||
/// [C++0x] attribute-specifier-seq[opt] type-specifier-seq declarator
|
||||
|
@ -1928,36 +1929,42 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) {
|
|||
Diag(Tok, diag::ext_c99_variable_decl_in_for_loop);
|
||||
Diag(Tok, diag::warn_gcc_variable_decl_in_for_loop);
|
||||
}
|
||||
|
||||
// In C++0x, "for (T NS:a" might not be a typo for ::
|
||||
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
|
||||
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
|
||||
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DeclGroupPtrTy DG = ParseSimpleDeclaration(
|
||||
DeclaratorContext::ForInit, DeclEnd, attrs, false,
|
||||
MightBeForRangeStmt ? &ForRangeInfo : nullptr);
|
||||
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
||||
if (ForRangeInfo.ParsedForRangeDecl()) {
|
||||
Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11 ?
|
||||
diag::warn_cxx98_compat_for_range : diag::ext_for_range);
|
||||
ForRangeInfo.LoopVar = FirstPart;
|
||||
FirstPart = StmtResult();
|
||||
} else if (Tok.is(tok::semi)) { // for (int x = 4;
|
||||
ConsumeToken();
|
||||
} else if ((ForEach = isTokIdentifier_in())) {
|
||||
Actions.ActOnForEachDeclStmt(DG);
|
||||
// ObjC: for (id x in expr)
|
||||
ConsumeToken(); // consume 'in'
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
|
||||
return StmtError();
|
||||
}
|
||||
Collection = ParseExpression();
|
||||
DeclGroupPtrTy DG;
|
||||
if (Tok.is(tok::kw_using)) {
|
||||
DG = ParseAliasDeclarationInInitStatement(DeclaratorContext::ForInit,
|
||||
attrs);
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_semi_for);
|
||||
// In C++0x, "for (T NS:a" might not be a typo for ::
|
||||
bool MightBeForRangeStmt = getLangOpts().CPlusPlus;
|
||||
ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt);
|
||||
|
||||
SourceLocation DeclStart = Tok.getLocation(), DeclEnd;
|
||||
DG = ParseSimpleDeclaration(
|
||||
DeclaratorContext::ForInit, DeclEnd, attrs, false,
|
||||
MightBeForRangeStmt ? &ForRangeInfo : nullptr);
|
||||
FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation());
|
||||
if (ForRangeInfo.ParsedForRangeDecl()) {
|
||||
Diag(ForRangeInfo.ColonLoc, getLangOpts().CPlusPlus11
|
||||
? diag::warn_cxx98_compat_for_range
|
||||
: diag::ext_for_range);
|
||||
ForRangeInfo.LoopVar = FirstPart;
|
||||
FirstPart = StmtResult();
|
||||
} else if (Tok.is(tok::semi)) { // for (int x = 4;
|
||||
ConsumeToken();
|
||||
} else if ((ForEach = isTokIdentifier_in())) {
|
||||
Actions.ActOnForEachDeclStmt(DG);
|
||||
// ObjC: for (id x in expr)
|
||||
ConsumeToken(); // consume 'in'
|
||||
|
||||
if (Tok.is(tok::code_completion)) {
|
||||
cutOffParsing();
|
||||
Actions.CodeCompleteObjCForCollection(getCurScope(), DG);
|
||||
return StmtError();
|
||||
}
|
||||
Collection = ParseExpression();
|
||||
} else {
|
||||
Diag(Tok, diag::err_expected_semi_for);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ProhibitAttributes(attrs);
|
||||
|
|
|
@ -483,6 +483,8 @@ Parser::isCXXConditionDeclarationOrInitStatement(bool CanBeInitStatement,
|
|||
ConditionDeclarationOrInitStatementState State(*this, CanBeInitStatement,
|
||||
CanBeForRangeDecl);
|
||||
|
||||
if (CanBeInitStatement && Tok.is(tok::kw_using))
|
||||
return ConditionOrInitStatement::InitStmtDecl;
|
||||
if (State.update(isCXXDeclarationSpecifier()))
|
||||
return State.result();
|
||||
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify=expected -std=c++2b -Wall %s
|
||||
// RUN: %clang_cc1 -fsyntax-only -verify=expected,expected-cxx20 -std=c++20 -Wall %s
|
||||
|
||||
namespace ns {
|
||||
int i;
|
||||
enum class e {};
|
||||
}
|
||||
void f() {
|
||||
|
||||
for (using foo = int;true;); //expected-cxx20-warning {{alias declaration in this context is a C++2b extension}}
|
||||
|
||||
switch(using foo = int; 0) { //expected-cxx20-warning {{alias declaration in this context is a C++2b extension}}
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
if(using foo = int; false) {} //expected-cxx20-warning {{alias declaration in this context is a C++2b extension}}
|
||||
|
||||
|
||||
if (using enum ns::e; false){} // expected-error {{expected '='}}
|
||||
|
||||
for (using ns::i; true;); // expected-error {{expected '='}}
|
||||
|
||||
if (using ns::i; false){} // expected-error {{expected '='}}
|
||||
|
||||
switch(using ns::i; 0) { // expected-error {{expected '='}}
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// RUN: %clang_cc1 -verify -std=c++2b -Wall -Wshadow %s
|
||||
|
||||
void f() {
|
||||
|
||||
for (using foo = int;true;) {} //expected-warning {{unused type alias 'foo'}}
|
||||
|
||||
switch(using foo = int; 0) { //expected-warning {{unused type alias 'foo'}}
|
||||
case 0: break;
|
||||
}
|
||||
|
||||
if(using foo = int; false) {} // expected-warning {{unused type alias 'foo'}}
|
||||
|
||||
int x; // expected-warning {{unused variable 'x'}}
|
||||
if(using x = int; true) {} // expected-warning {{unused type alias 'x'}}
|
||||
|
||||
using y = int; // expected-warning {{unused type alias 'y'}} \
|
||||
// expected-note 2{{previous declaration is here}}
|
||||
|
||||
if(using y = double; true) {} // expected-warning {{unused type alias 'y'}} \
|
||||
// expected-warning {{declaration shadows a type alias in function 'f'}}
|
||||
|
||||
for(using y = double; true;) { // expected-warning {{declaration shadows a type alias in function 'f'}}
|
||||
y foo = 0;
|
||||
(void)foo;
|
||||
constexpr y var = 0;
|
||||
static_assert(var == 0);
|
||||
}
|
||||
}
|
|
@ -1381,7 +1381,7 @@ C++20, informally referred to as C++2b.</p>
|
|||
<tr>
|
||||
<td>Extend init-statement to allow alias-declaration</td>
|
||||
<td><a href="https://wg21.link/P2360R0">P2360R0</a></td>
|
||||
<td class="none" align="center">No</td>
|
||||
<td class="unreleased" align="center">Clang 14</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
|
Loading…
Reference in New Issue