Skip to content

Commit 3c84e4a

Browse files
committed
[C11] Improve the diagnostic when accessing a member of an atomic struct
Member access for an atomic structure or union is unconditional undefined behavior (C11 6.5.2.3p5). However, we would issue a confusing error message about the base expression not being a structure or union type. GCC issues a warning for this case. Clang now warns as well, but the warning is defaulted to an error because the actual access is still unsafe. This fixes Issue 54563.
1 parent 95eac47 commit 3c84e4a

File tree

4 files changed

+50
-1
lines changed

4 files changed

+50
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ Bug Fixes
8585
- Assignment expressions in C11 and later mode now properly strip the _Atomic
8686
qualifier when determining the type of the assignment expression. Fixes
8787
`Issue 48742 <https://github.com/llvm/llvm-project/issues/48742>`_.
88+
- Improved the diagnostic when accessing a member of an atomic structure or
89+
union object in C; was previously an unhelpful error, but now issues a
90+
`-Watomic-access` warning which defaults to an error. Fixes
91+
`Issue 54563 <https://github.com/llvm/llvm-project/issues/54563>`_.
8892
- Unevaluated lambdas in dependant contexts no longer result in clang crashing.
8993
This fixes Issues `50376 <https://github.com/llvm/llvm-project/issues/50376>`_,
9094
`51414 <https://github.com/llvm/llvm-project/issues/51414>`_,

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6439,6 +6439,9 @@ def err_atomic_specifier_bad_type
64396439
"%select{incomplete |array |function |reference |atomic |qualified "
64406440
"|sizeless ||integer }0type "
64416441
"%1 %select{|||||||which is not trivially copyable|}0">;
6442+
def warn_atomic_member_access : Warning<
6443+
"accessing a member of an atomic structure or union is undefined behavior">,
6444+
InGroup<DiagGroup<"atomic-access">>, DefaultError;
64426445

64436446
// Expressions.
64446447
def ext_sizeof_alignof_function_type : Extension<

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,20 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
12921292
}
12931293
}
12941294

1295+
// If the base type is an atomic type, this access is undefined behavior per
1296+
// C11 6.5.2.3p5. Instead of giving a typecheck error, we'll warn the user
1297+
// about the UB and recover by converting the atomic lvalue into a non-atomic
1298+
// lvalue. Because this is inherently unsafe as an atomic operation, the
1299+
// warning defaults to an error.
1300+
if (const auto *ATy = BaseType->getAs<AtomicType>()) {
1301+
S.Diag(OpLoc, diag::warn_atomic_member_access);
1302+
BaseType = ATy->getValueType().getUnqualifiedType();
1303+
BaseExpr = ImplicitCastExpr::Create(
1304+
S.Context, IsArrow ? S.Context.getPointerType(BaseType) : BaseType,
1305+
CK_AtomicToNonAtomic, BaseExpr.get(), nullptr,
1306+
BaseExpr.get()->getValueKind(), FPOptionsOverride());
1307+
}
1308+
12951309
// Handle field access to simple records.
12961310
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
12971311
TypoExpr *TE = nullptr;

clang/test/Sema/atomic-expr.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %clang_cc1 %s -verify -fsyntax-only
2-
// expected-no-diagnostics
2+
// RUN: %clang_cc1 %s -verify=off -fsyntax-only -Wno-atomic-access
3+
// off-no-diagnostics
34

45
_Atomic(unsigned int) data1;
56
int _Atomic data2;
@@ -75,3 +76,30 @@ void func_15(void) {
7576
_Static_assert(__builtin_types_compatible_p(__typeof__(x = 2), int), "incorrect");
7677
_Static_assert(__builtin_types_compatible_p(__typeof__(x += 2), int), "incorrect");
7778
}
79+
80+
// Ensure that member access of an atomic structure or union type is properly
81+
// diagnosed as being undefined behavior; Issue 54563.
82+
void func_16(void) {
83+
// LHS member access.
84+
_Atomic struct { int val; } x, *xp;
85+
x.val = 12; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
86+
xp->val = 12; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
87+
88+
_Atomic union {
89+
int ival;
90+
float fval;
91+
} y, *yp;
92+
y.ival = 12; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
93+
yp->fval = 1.2f; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
94+
95+
// RHS member access.
96+
int xval = x.val; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
97+
xval = xp->val; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
98+
int yval = y.val; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
99+
yval = yp->val; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
100+
101+
// Using the type specifier instead of the type qualifier.
102+
_Atomic(struct { int val; }) z;
103+
z.val = 12; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
104+
int zval = z.val; // expected-error {{accessing a member of an atomic structure or union is undefined behavior}}
105+
}

0 commit comments

Comments
 (0)