[C++20] [Coroutines] Disable to take the address of labels in coroutines
authorChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 17 Jan 2023 03:31:24 +0000 (11:31 +0800)
committerChuanqi Xu <yedeng.yd@linux.alibaba.com>
Tue, 17 Jan 2023 03:35:32 +0000 (11:35 +0800)
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
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/ScopeInfo.h
clang/lib/Sema/ScopeInfo.cpp
clang/lib/Sema/SemaCoroutine.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/SemaCXX/addr-label-in-coroutines.cpp [new file with mode: 0644]

index 3bbab95..de038fe 100644 (file)
@@ -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 <https://github.com/llvm/llvm-project/issues/56436>`_.
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------
index 02afb09..50050e1 100644 (file)
@@ -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 {
index 363fbf4..65fa18f 100644 (file)
@@ -233,6 +233,9 @@ public:
   /// modified in the function.
   llvm::SmallPtrSet<const ParmVarDecl *, 8> ModifiedNonNullParams;
 
+  /// The set of GNU address of label extension "&&label".
+  llvm::SmallVector<AddrLabelExpr *, 4> AddrLabels;
+
 public:
   /// Represents a simple identification of a weak object.
   ///
index f4dda9f..e313052 100644 (file)
@@ -56,6 +56,7 @@ void FunctionScopeInfo::Clear() {
   ModifiedNonNullParams.clear();
   Blocks.clear();
   ByrefBlockVars.clear();
+  AddrLabels.clear();
 }
 
 static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) {
index 4cedd53..79c08ad 100644 (file)
@@ -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();
index d90c284..be3a6bd 100644 (file)
@@ -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 (file)
index 0000000..e37ee64
--- /dev/null
@@ -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;
+}