Skip to content

Commit 28c9452

Browse files
comexcor3ntin
andauthored
[clang] Fix side effects resolving overloads of builtin functions (#138651) (#154034)
When parsing `__builtin_addressof(Value)`, where `Value` is a constexpr variable of primitive type, we will run through `rewriteBuiltinFunctionDecl`. `rewriteBuiltinFunctionDecl` is meant to handle a special case which is not applicable here. (It only applies when a builtin function's type has a parameter with pointer type, which is not true for `__builtin_addressof`, not even if the actual argument is a pointer.) Therefore, `rewriteBuiltinFunctionDecl` returns `nullptr` and things go on as usual. But `rewriteBuiltinFunctionDecl` accidentally has a side effect. It calls `DefaultFunctionArrayLvalueConversion` -> `DefaultLvalueConversion` -> `CheckLValueToRValueConversionOperand` -> `rebuildPotentialResultsAsNonOdrUsed` -> `MarkNotOdrUsed`, which removes the expression from `S.MaybeODRUseExprs`. This would be correct if `Value` were actually going through an lvalue-to-rvalue conversion, because it's a constant expression: https://eel.is/c++draft/basic.def.odr#5.2.2.2 But in this case the conversion is only hypothetical, as part of `rewriteBuiltinFunctionDecl`'s pseudo-overload-resolution logic. Fix the side effect by pushing an `ExpressionEvaluationContext`, like we do for real overload resolution. Similarly, push a `SFINAETrap` to suppress diagnostics emitted during `DefaultFunctionArrayLvalueConversion`. This fixes a false-positive compile error when applying `__builtin_addressof` to certain volatile union variables, and fixes a duplicated compile error when applying `__builtin_get_vtable_pointer` to an overloaded function name. --------- Co-authored-by: Corentin Jabot <[email protected]>
1 parent 36d5390 commit 28c9452

File tree

5 files changed

+46
-24
lines changed

5 files changed

+46
-24
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ Bug Fixes to C++ Support
350350
authentication enabled. (#GH152601)
351351
- Fix the check for narrowing int-to-float conversions, so that they are detected in
352352
cases where converting the float back to an integer is undefined behaviour (#GH157067).
353+
- Fix an assertion failure when a ``constexpr`` variable is only referenced through
354+
``__builtin_addressof``, and related issues with builtin arguments. (#GH154034)
353355

354356
Bug Fixes to AST Handling
355357
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6313,30 +6313,38 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
63136313
unsigned i = 0;
63146314
SmallVector<QualType, 8> OverloadParams;
63156315

6316-
for (QualType ParamType : FT->param_types()) {
6316+
{
6317+
// The lvalue conversions in this loop are only for type resolution and
6318+
// don't actually occur.
6319+
EnterExpressionEvaluationContext Unevaluated(
6320+
*Sema, Sema::ExpressionEvaluationContext::Unevaluated);
6321+
Sema::SFINAETrap Trap(*Sema, /*ForValidityCheck=*/true);
63176322

6318-
// Convert array arguments to pointer to simplify type lookup.
6319-
ExprResult ArgRes =
6320-
Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]);
6321-
if (ArgRes.isInvalid())
6322-
return nullptr;
6323-
Expr *Arg = ArgRes.get();
6324-
QualType ArgType = Arg->getType();
6325-
if (!ParamType->isPointerType() ||
6326-
ParamType->getPointeeType().hasAddressSpace() ||
6327-
!ArgType->isPointerType() ||
6328-
!ArgType->getPointeeType().hasAddressSpace() ||
6329-
isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) {
6330-
OverloadParams.push_back(ParamType);
6331-
continue;
6332-
}
6323+
for (QualType ParamType : FT->param_types()) {
63336324

6334-
QualType PointeeType = ParamType->getPointeeType();
6335-
NeedsNewDecl = true;
6336-
LangAS AS = ArgType->getPointeeType().getAddressSpace();
6325+
// Convert array arguments to pointer to simplify type lookup.
6326+
ExprResult ArgRes =
6327+
Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]);
6328+
if (ArgRes.isInvalid())
6329+
return nullptr;
6330+
Expr *Arg = ArgRes.get();
6331+
QualType ArgType = Arg->getType();
6332+
if (!ParamType->isPointerType() ||
6333+
ParamType->getPointeeType().hasAddressSpace() ||
6334+
!ArgType->isPointerType() ||
6335+
!ArgType->getPointeeType().hasAddressSpace() ||
6336+
isPtrSizeAddressSpace(ArgType->getPointeeType().getAddressSpace())) {
6337+
OverloadParams.push_back(ParamType);
6338+
continue;
6339+
}
63376340

6338-
PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
6339-
OverloadParams.push_back(Context.getPointerType(PointeeType));
6341+
QualType PointeeType = ParamType->getPointeeType();
6342+
NeedsNewDecl = true;
6343+
LangAS AS = ArgType->getPointeeType().getAddressSpace();
6344+
6345+
PointeeType = Context.getAddrSpaceQualType(PointeeType, AS);
6346+
OverloadParams.push_back(Context.getPointerType(PointeeType));
6347+
}
63406348
}
63416349

63426350
if (!NeedsNewDecl)

clang/test/SemaCXX/builtin-get-vtable-pointer.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ struct PolymorphicTemplate {
6666
};
6767

6868
void test_function(int); // expected-note{{possible target for call}}
69-
// expected-note@-1{{possible target for call}}
7069
void test_function(double); // expected-note{{possible target for call}}
71-
// expected-note@-1{{possible target for call}}
7270

7371
void getVTablePointer() {
7472
ForwardDeclaration *fd = nullptr;
@@ -89,7 +87,6 @@ void getVTablePointer() {
8987
__builtin_get_vtable_pointer(np_array); // expected-error{{__builtin_get_vtable_pointer requires an argument of polymorphic class pointer type, but 'NonPolymorphic' has no virtual methods}}
9088
__builtin_get_vtable_pointer(&np_array); // expected-error{{__builtin_get_vtable_pointer requires an argument of class pointer type, but 'NonPolymorphic (*)[1]' was provided}}
9189
__builtin_get_vtable_pointer(test_function); // expected-error{{reference to overloaded function could not be resolved; did you mean to call it?}}
92-
// expected-error@-1{{reference to overloaded function could not be resolved; did you mean to call it?}}
9390
Foo<double> Food;
9491
Foo<int> Fooi;
9592
__builtin_get_vtable_pointer(Food); // expected-error{{__builtin_get_vtable_pointer requires an argument of class pointer type, but 'Foo<double>' was provided}}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %clang_cc1 -std=c++20 %s -emit-obj -o /dev/null
2+
3+
const int* test_odr_used() {
4+
// This previously crashed due to Value improperly being removed from
5+
// MaybeODRUseExprs.
6+
static constexpr int Value = 0;
7+
return __builtin_addressof(Value);
8+
}

clang/test/SemaObjC/non-trivial-c-union.m

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,10 @@ void testVolatileLValueToRValue(volatile U0 *a) {
8787
void unionInSystemHeader0(U0_SystemHeader);
8888

8989
void unionInSystemHeader1(U1_SystemHeader); // expected-error {{cannot use type 'U1_SystemHeader' for a function/method parameter since it is a union that is non-trivial to destruct}} expected-error {{cannot use type 'U1_SystemHeader' for a function/method parameter since it is a union that is non-trivial to copy}}
90+
91+
void testAddressof(void) {
92+
extern volatile U0 t0;
93+
// These don't dereference so they shouldn't cause an error.
94+
(void)&t0;
95+
(void)__builtin_addressof(t0);
96+
}

0 commit comments

Comments
 (0)