[clang] [clang][Sema] Fix type of an statement expression ending with an atomic type (PR #119711)

Alejandro Álvarez Ayllón via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 12 07:25:59 PST 2024


https://github.com/alejandro-alvarez-sonarsource created https://github.com/llvm/llvm-project/pull/119711

When a statement expression's last statement is an atomic variable, GCC and Clang disagree on the type of the expression. This can be made apparent using `typeof` and forcing a diagnostic message:

```cpp
_Atomic int a = 0;
typeof(({a;})) x = "0";
```

* GCC complains about initializing `int` with `char*`
* Clang complains about initializing `_Atomic(int)` with a `char[2]`

Due to the type of the statement expression being deduced to be atomic, we end with three implicit casts inside the `StmtExpr` on the AST:

* `LValueToRValue` -> `AtomicToNonAtomic`  ->  `NonAtomicToAtomic`

In some situations, this can end on an assertion inside `IntExprEvaluator`, as reported in #106576.

With this patch, we now have two implicit casts, since the type of the statement expression is deduced to be non-atomic:

* `LValueToRValue` -> `AtomicToNonAtomic`

This is consistent with the C standard (6.7.2.4, p4)

>  The properties associated with atomic types are meaningful only for expressions that are lvalues.

But a statement expression is an rvalue.

`IntExprEvaluator` assumptions are now satisfied and there is no assertion error.
Additionally, the `typeof` trick mentioned above shows that the type is consistently deduced between GCC and Clang.

Fixes #106576

>From d398fa13c2fa141954c79ca68a59c6ac506b393f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?=
 <alejandro.alvarez at sonarsource.com>
Date: Wed, 11 Dec 2024 15:43:58 +0100
Subject: [PATCH 1/3] Add regression test

---
 clang/test/Sema/gh106576.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 clang/test/Sema/gh106576.c

diff --git a/clang/test/Sema/gh106576.c b/clang/test/Sema/gh106576.c
new file mode 100644
index 00000000000000..792977dea14132
--- /dev/null
+++ b/clang/test/Sema/gh106576.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+typedef _Atomic char atomic_char;
+
+typedef _Atomic char atomic_char;
+
+atomic_char counter;
+
+char load_plus_one(void) {
+  return ({counter;}) + 1; // no crash
+}
+
+char type_of_stmt_expr(void) {
+  typeof(({counter;})) y = ""; // expected-error-re {{incompatible pointer to integer conversion initializing 'typeof (({{{.*}}}))' (aka 'char') with an expression of type 'char[1]'}}
+  return y;
+}

>From 296aa35fe32449067c69d2b40031af0dd6822a07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?=
 <alejandro.alvarez at sonarsource.com>
Date: Thu, 12 Dec 2024 15:08:56 +0100
Subject: [PATCH 2/3] Tentative fix

---
 clang/lib/Sema/SemaExpr.cpp | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 20bf6f7f6f28ff..165447efb345c5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -15861,10 +15861,19 @@ ExprResult Sema::ActOnStmtExprResult(ExprResult ER) {
   if (Cast && Cast->getCastKind() == CK_ARCConsumeObject)
     return Cast->getSubExpr();
 
+  auto Ty = E->getType().getUnqualifiedType();
+
+  // If the type is an atomic, the statement type is the underlying type.
+  if (const AtomicType *AT = Ty->getAs<AtomicType>()) {
+    Ty = AT->getValueType().getUnqualifiedType();
+    return ImplicitCastExpr::Create(Context, Ty, CK_AtomicToNonAtomic, E,
+                                    /*base path*/ nullptr, VK_PRValue,
+                                    FPOptionsOverride());
+  }
+
   // FIXME: Provide a better location for the initialization.
   return PerformCopyInitialization(
-      InitializedEntity::InitializeStmtExprResult(
-          E->getBeginLoc(), E->getType().getUnqualifiedType()),
+      InitializedEntity::InitializeStmtExprResult(E->getBeginLoc(), Ty),
       SourceLocation(), E);
 }
 

>From d13e1090c641314aae8eef50f1b0fb5c0ec67e39 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alejandro=20=C3=81lvarez=20Ayll=C3=B3n?=
 <alejandro.alvarez at sonarsource.com>
Date: Thu, 12 Dec 2024 15:30:07 +0100
Subject: [PATCH 3/3] Use PerformImplicitConversion

---
 clang/lib/Sema/SemaExpr.cpp | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 165447efb345c5..45ae97807c2032 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -15866,9 +15866,7 @@ ExprResult Sema::ActOnStmtExprResult(ExprResult ER) {
   // If the type is an atomic, the statement type is the underlying type.
   if (const AtomicType *AT = Ty->getAs<AtomicType>()) {
     Ty = AT->getValueType().getUnqualifiedType();
-    return ImplicitCastExpr::Create(Context, Ty, CK_AtomicToNonAtomic, E,
-                                    /*base path*/ nullptr, VK_PRValue,
-                                    FPOptionsOverride());
+    return PerformImplicitConversion(E, Ty, AssignmentAction::Casting);
   }
 
   // FIXME: Provide a better location for the initialization.



More information about the cfe-commits mailing list