From cc526e346debbaf1d2d32a59230288a4e98294c7 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu Date: Tue, 17 Jan 2023 11:31:24 +0800 Subject: [PATCH] [C++20] [Coroutines] Disable to take the address of labels in coroutines Closing https://github.com/llvm/llvm-project/issues/56436 We can't support the GNU address of label extension in coroutines well in current architecture. Since the coroutines are going to split into pieces in the middle end so the address of labels are ambiguous that time. To avoid any further misunderstanding, we try to emit an error here. Differential Revision: https://reviews.llvm.org/D131938 --- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 + clang/include/clang/Sema/ScopeInfo.h | 3 + clang/lib/Sema/ScopeInfo.cpp | 1 + clang/lib/Sema/SemaCoroutine.cpp | 6 ++ clang/lib/Sema/SemaExpr.cpp | 9 ++- clang/test/SemaCXX/addr-label-in-coroutines.cpp | 70 ++++++++++++++++++++++++ 7 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 clang/test/SemaCXX/addr-label-in-coroutines.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3bbab95..de038fe 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -452,6 +452,8 @@ Improvements to Clang's diagnostics - Add ``-Wreturn-local-addr``, a GCC alias for ``-Wreturn-stack-address``. - Clang now suppresses ``-Wlogical-op-parentheses`` on ``(x && a || b)`` and ``(a || b && x)`` only when ``x`` is a string literal. +- Clang will now reject the GNU extension address of label in coroutines explicitly. + This fixes `Issue 56436 `_. Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 02afb098..50050e1 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11360,6 +11360,9 @@ def warn_non_aligned_allocation_function : Warning < def err_conflicting_aligned_options : Error < "conflicting option '-fcoro-aligned-allocation' and '-fno-aligned-allocation'" >; +def err_coro_invalid_addr_of_label : Error< + "the GNU address of label extension is not allowed in coroutines." +>; } // end of coroutines issue category let CategoryName = "Documentation Issue" in { diff --git a/clang/include/clang/Sema/ScopeInfo.h b/clang/include/clang/Sema/ScopeInfo.h index 363fbf4..65fa18f 100644 --- a/clang/include/clang/Sema/ScopeInfo.h +++ b/clang/include/clang/Sema/ScopeInfo.h @@ -233,6 +233,9 @@ public: /// modified in the function. llvm::SmallPtrSet ModifiedNonNullParams; + /// The set of GNU address of label extension "&&label". + llvm::SmallVector AddrLabels; + public: /// Represents a simple identification of a weak object. /// diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index f4dda9f..e313052 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() { ModifiedNonNullParams.clear(); Blocks.clear(); ByrefBlockVars.clear(); + AddrLabels.clear(); } static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) { diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 4cedd53..79c08ad 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -1125,6 +1125,12 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { Diag(Fn->FirstCoroutineStmtLoc, diag::note_declared_coroutine_here) << Fn->getFirstCoroutineStmtKeyword(); } + + // Coroutines will get splitted into pieces. The GNU address of label + // extension wouldn't be meaningful in coroutines. + for (AddrLabelExpr *ALE : Fn->AddrLabels) + Diag(ALE->getBeginLoc(), diag::err_coro_invalid_addr_of_label); + CoroutineStmtBuilder Builder(*this, *FD, *Fn, Body); if (Builder.isInvalid() || !Builder.buildStatements()) return FD->setInvalidDecl(); diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index d90c284..be3a6bd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -16105,8 +16105,13 @@ ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl) { TheDecl->markUsed(Context); // Create the AST node. The address of a label always has type 'void*'. - return new (Context) AddrLabelExpr(OpLoc, LabLoc, TheDecl, - Context.getPointerType(Context.VoidTy)); + auto *Res = new (Context) AddrLabelExpr( + OpLoc, LabLoc, TheDecl, Context.getPointerType(Context.VoidTy)); + + if (getCurFunction()) + getCurFunction()->AddrLabels.push_back(Res); + + return Res; } void Sema::ActOnStartStmtExpr() { diff --git a/clang/test/SemaCXX/addr-label-in-coroutines.cpp b/clang/test/SemaCXX/addr-label-in-coroutines.cpp new file mode 100644 index 0000000..e37ee64 --- /dev/null +++ b/clang/test/SemaCXX/addr-label-in-coroutines.cpp @@ -0,0 +1,70 @@ +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s + +#include "Inputs/std-coroutine.h" + +struct resumable { + struct promise_type { + resumable get_return_object() { return {}; } + auto initial_suspend() { return std::suspend_always(); } + auto final_suspend() noexcept { return std::suspend_always(); } + void unhandled_exception() {} + void return_void(){}; + }; +}; + +resumable f1(int &out, int *inst) { + static void* dispatch_table[] = {&&inc, // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + &&suspend, // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + &&stop}; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + #define DISPATCH() goto *dispatch_table[*inst++] +inc: + out++; + DISPATCH(); + +suspend: + co_await std::suspend_always{}; + DISPATCH(); + +stop: + co_return; +} + +resumable f2(int &out, int *inst) { + void* dispatch_table[] = {nullptr, nullptr, nullptr}; + dispatch_table[0] = &&inc; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + dispatch_table[1] = &&suspend; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + dispatch_table[2] = &&stop; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + #define DISPATCH() goto *dispatch_table[*inst++] +inc: + out++; + DISPATCH(); + +suspend: + co_await std::suspend_always{}; + DISPATCH(); + +stop: + co_return; +} + +resumable f3(int &out, int *inst) { + void* dispatch_table[] = {nullptr, nullptr, nullptr}; + [&]() -> resumable { + dispatch_table[0] = &&inc; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + dispatch_table[1] = &&suspend; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + dispatch_table[2] = &&stop; // expected-error {{the GNU address of label extension is not allowed in coroutines.}} + #define DISPATCH() goto *dispatch_table[*inst++] + inc: + out++; + DISPATCH(); + + suspend: + co_await std::suspend_always{}; + DISPATCH(); + + stop: + co_return; + }(); + + co_return; +} -- 2.7.4