From ff013b61004b01043bdbebb6416c30ecb3d3d48c Mon Sep 17 00:00:00 2001
From: Corentin Jabot
Date: Fri, 8 Oct 2021 07:12:46 -0400
Subject: [PATCH] Extend init-statement to allow alias-declaration
Implement P2360R0 in C++23 mode and as an extension in older
languages mode.
---
clang/docs/ReleaseNotes.rst | 2 +
.../clang/Basic/DiagnosticParseKinds.td | 6 ++
clang/include/clang/Parse/Parser.h | 6 +-
clang/lib/Parse/ParseDeclCXX.cpp | 10 ++-
clang/lib/Parse/ParseExprCXX.cpp | 31 ++++++++-
clang/lib/Parse/ParseStmt.cpp | 65 ++++++++++---------
clang/lib/Parse/ParseTentative.cpp | 2 +
clang/test/Parser/cxx2b-init-statement.cpp | 29 +++++++++
clang/test/SemaCXX/cxx2b-init-statement.cpp | 28 ++++++++
clang/www/cxx_status.html | 2 +-
10 files changed, 146 insertions(+), 35 deletions(-)
create mode 100644 clang/test/Parser/cxx2b-init-statement.cpp
create mode 100644 clang/test/SemaCXX/cxx2b-init-statement.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9181f01be440..dc8f8a306824 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -134,6 +134,8 @@ C++20 Feature Support
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Implemented `P1938R3: if consteval `_.
+- Implemented `P2360R0: Extend init-statement to allow alias-declaration `_.
+
CUDA Language Changes in Clang
------------------------------
diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td
index cf649670f051..8ae264caddcb 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -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;
+def warn_cxx20_alias_in_init_statement : Warning<
+ "alias declaration in this context is incompatible with C++ standards before C++2b">,
+ DefaultIgnore, InGroup;
def warn_dangling_else : Warning<
"add explicit braces to avoid dangling else">,
InGroup;
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index f42e59ab6ddf..de25760017b5 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -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);
}
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 73b458e09a9c..f5a6ffcff9e9 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -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;
diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 5b7e15e1939c..4bdb73965bca 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -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);
}
diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp
index 523d619e37e7..9e259e15bd56 100644
--- a/clang/lib/Parse/ParseStmt.cpp
+++ b/clang/lib/Parse/ParseStmt.cpp
@@ -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);
diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 73fe5533ec66..a40376d23991 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -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();
diff --git a/clang/test/Parser/cxx2b-init-statement.cpp b/clang/test/Parser/cxx2b-init-statement.cpp
new file mode 100644
index 000000000000..8f99b46edeb6
--- /dev/null
+++ b/clang/test/Parser/cxx2b-init-statement.cpp
@@ -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;
+ }
+
+}
diff --git a/clang/test/SemaCXX/cxx2b-init-statement.cpp b/clang/test/SemaCXX/cxx2b-init-statement.cpp
new file mode 100644
index 000000000000..de7dfcb80bc3
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2b-init-statement.cpp
@@ -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);
+ }
+}
diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html
index 4a43c8ac0317..f6531ed01e49 100755
--- a/clang/www/cxx_status.html
+++ b/clang/www/cxx_status.html
@@ -1381,7 +1381,7 @@ C++20, informally referred to as C++2b.
Extend init-statement to allow alias-declaration |
P2360R0 |
- No |
+ Clang 14 |