Skip to content

Commit fc30901

Browse files
committed
Extend support for std::move etc to also cover std::as_const and
std::addressof, plus the libstdc++-specific std::__addressof. This brings us to parity with the corresponding GCC behavior. Remove STDBUILTIN macro that ended up not being used.
1 parent 9e7eef9 commit fc30901

File tree

12 files changed

+117
-35
lines changed

12 files changed

+117
-35
lines changed

clang/include/clang/Basic/Builtins.def

+9-10
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,7 @@
103103
// V:N: -> requires vectors of at least N bits to be legal
104104
// C<N,M_0,...,M_k> -> callback behavior: argument N is called with argument
105105
// M_0, ..., M_k as payload
106-
// z -> this is a C++ standard library function in (possibly-versioned)
107-
// namespace std; implied by STDBUILTIN
106+
// z -> this is a function in (possibly-versioned) namespace std
108107
// FIXME: gcc has nonnull
109108

110109
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -115,10 +114,6 @@
115114
# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
116115
#endif
117116

118-
#if defined(BUILTIN) && !defined(STDBUILTIN)
119-
# define STDBUILTIN(ID, TYPE, ATTRS, HEADER) LIBBUILTIN(ID, TYPE, "zf" ATTRS, HEADER, CXX_LANG)
120-
#endif
121-
122117
// Standard libc/libm functions:
123118
BUILTIN(__builtin_atan2 , "ddd" , "Fne")
124119
BUILTIN(__builtin_atan2f, "fff" , "Fne")
@@ -1551,10 +1546,14 @@ LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
15511546
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
15521547
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
15531548

1554-
// C++11
1555-
STDBUILTIN(move, "v&v&", "ncTh", "utility")
1556-
STDBUILTIN(move_if_noexcept, "v&v&", "ncTh", "utility")
1557-
STDBUILTIN(forward, "v&v&", "ncTh", "utility")
1549+
// C++ standard library builtins in namespace 'std'.
1550+
LIBBUILTIN(addressof, "v*v&", "zfncTh", "memory", CXX_LANG)
1551+
// Synonym for addressof used internally by libstdc++.
1552+
LANGBUILTIN(__addressof, "v*v&", "zfncT", CXX_LANG)
1553+
LIBBUILTIN(as_const, "v&v&", "zfncTh", "utility", CXX_LANG)
1554+
LIBBUILTIN(forward, "v&v&", "zfncTh", "utility", CXX_LANG)
1555+
LIBBUILTIN(move, "v&v&", "zfncTh", "utility", CXX_LANG)
1556+
LIBBUILTIN(move_if_noexcept, "v&v&", "zfncTh", "utility", CXX_LANG)
15581557

15591558
// Annotation function
15601559
BUILTIN(__builtin_annotation, "v.", "tn")

clang/include/clang/Basic/DiagnosticSemaKinds.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -6587,7 +6587,7 @@ def warn_self_move : Warning<
65876587
InGroup<SelfMove>, DefaultIgnore;
65886588

65896589
def err_builtin_move_forward_unsupported : Error<
6590-
"unsupported signature for '%select{std::move|std::forward}0'">;
6590+
"unsupported signature for %q0">;
65916591
def err_use_of_unaddressable_function : Error<
65926592
"taking address of non-addressable standard library function">;
65936593
// FIXME: This should also be in -Wc++23-compat once we have it.

clang/lib/AST/ExprConstant.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -8295,9 +8295,10 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
82958295

82968296
bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
82978297
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
8298+
case Builtin::BIas_const:
8299+
case Builtin::BIforward:
82988300
case Builtin::BImove:
82998301
case Builtin::BImove_if_noexcept:
8300-
case Builtin::BIforward:
83018302
if (cast<FunctionDecl>(E->getCalleeDecl())->isConstexpr())
83028303
return Visit(E->getArg(0));
83038304
break;
@@ -9084,6 +9085,8 @@ static bool isOneByteCharacterType(QualType T) {
90849085
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
90859086
unsigned BuiltinOp) {
90869087
switch (BuiltinOp) {
9088+
case Builtin::BIaddressof:
9089+
case Builtin::BI__addressof:
90879090
case Builtin::BI__builtin_addressof:
90889091
return evaluateLValue(E->getArg(0), Result);
90899092
case Builtin::BI__builtin_assume_aligned: {

clang/lib/Analysis/BodyFarm.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -713,9 +713,10 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
713713

714714
if (unsigned BuiltinID = D->getBuiltinID()) {
715715
switch (BuiltinID) {
716+
case Builtin::BIas_const:
717+
case Builtin::BIforward:
716718
case Builtin::BImove:
717719
case Builtin::BImove_if_noexcept:
718-
case Builtin::BIforward:
719720
FF = create_std_move_forward;
720721
break;
721722
default:

clang/lib/CodeGen/CGBuiltin.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -4566,6 +4566,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
45664566

45674567
return RValue::get(Carry);
45684568
}
4569+
case Builtin::BIaddressof:
4570+
case Builtin::BI__addressof:
45694571
case Builtin::BI__builtin_addressof:
45704572
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
45714573
case Builtin::BI__builtin_function_start:
@@ -4729,6 +4731,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
47294731
case Builtin::BImove:
47304732
case Builtin::BImove_if_noexcept:
47314733
case Builtin::BIforward:
4734+
case Builtin::BIas_const:
47324735
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
47334736
case Builtin::BI__GetExceptionInfo: {
47344737
if (llvm::GlobalVariable *GV =

clang/lib/Sema/SemaChecking.cpp

+18-4
Original file line numberDiff line numberDiff line change
@@ -2130,18 +2130,32 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
21302130

21312131
TheCall->setType(Context.VoidPtrTy);
21322132
break;
2133+
case Builtin::BIaddressof:
2134+
case Builtin::BI__addressof:
2135+
case Builtin::BIforward:
21332136
case Builtin::BImove:
21342137
case Builtin::BImove_if_noexcept:
2135-
case Builtin::BIforward:
2138+
case Builtin::BIas_const: {
2139+
// These are all expected to be of the form
2140+
// T &/&&/* f(U &/&&)
2141+
// where T and U only differ in qualification.
21362142
if (checkArgCount(*this, TheCall, 1))
21372143
return ExprError();
2138-
if (!Context.hasSameUnqualifiedType(TheCall->getType(),
2139-
TheCall->getArg(0)->getType())) {
2144+
QualType Param = FDecl->getParamDecl(0)->getType();
2145+
QualType Result = FDecl->getReturnType();
2146+
bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
2147+
BuiltinID == Builtin::BI__addressof;
2148+
if (!(Param->isReferenceType() &&
2149+
(ReturnsPointer ? Result->isPointerType()
2150+
: Result->isReferenceType()) &&
2151+
Context.hasSameUnqualifiedType(Param->getPointeeType(),
2152+
Result->getPointeeType()))) {
21402153
Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
2141-
<< (BuiltinID == Builtin::BIforward);
2154+
<< FDecl;
21422155
return ExprError();
21432156
}
21442157
break;
2158+
}
21452159
// OpenCL v2.0, s6.13.16 - Pipe functions
21462160
case Builtin::BIread_pipe:
21472161
case Builtin::BIwrite_pipe:

clang/lib/Sema/SemaDecl.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -9277,9 +9277,12 @@ static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD,
92779277
// No type checking whatsoever.
92789278
return Ctx.getTargetInfo().getCXXABI().isMicrosoft();
92799279

9280+
case Builtin::BIaddressof:
9281+
case Builtin::BI__addressof:
9282+
case Builtin::BIforward:
92809283
case Builtin::BImove:
92819284
case Builtin::BImove_if_noexcept:
9282-
case Builtin::BIforward: {
9285+
case Builtin::BIas_const: {
92839286
// Ensure that we don't treat the algorithm
92849287
// OutputIt std::move(InputIt, InputIt, OutputIt)
92859288
// as the builtin std::move.

clang/test/Analysis/inner-pointer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ void func_addressof() {
379379
const char *c;
380380
std::string s;
381381
c = s.c_str();
382-
addressof(s);
382+
(void)addressof(s);
383383
consume(c); // no-warning
384384
}
385385

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,45 @@
1-
// RUN: %clang_cc1 -no-opaque-pointers -triple=x86_64-linux-gnu -emit-llvm -o - -std=c++17 %s | FileCheck %s --implicit-check-not=@_ZSt4move
1+
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - -std=c++17 %s | FileCheck %s --implicit-check-not=@_ZSt4move
22

33
namespace std {
44
template<typename T> constexpr T &&move(T &val) { return static_cast<T&&>(val); }
55
template<typename T> constexpr T &&move_if_noexcept(T &val);
66
template<typename T> constexpr T &&forward(T &val);
7+
template<typename T> constexpr const T &as_const(T &val);
78

89
// Not the builtin.
910
template<typename T, typename U> T move(U source, U source_end, T dest);
1011
}
1112

1213
class T {};
1314
extern "C" void take(T &&);
15+
extern "C" void take_lval(const T &);
1416

1517
T a;
1618

1719
// Check emission of a constant-evaluated call.
18-
// CHECK-DAG: @move_a = constant %[[T:.*]]* @a
20+
// CHECK-DAG: @move_a = constant ptr @a
1921
T &&move_a = std::move(a);
20-
// CHECK-DAG: @move_if_noexcept_a = constant %[[T]]* @a
22+
// CHECK-DAG: @move_if_noexcept_a = constant ptr @a
2123
T &&move_if_noexcept_a = std::move_if_noexcept(a);
22-
// CHECK-DAG: @forward_a = constant %[[T]]* @a
24+
// CHECK-DAG: @forward_a = constant ptr @a
2325
T &forward_a = std::forward<T&>(a);
2426

2527
// Check emission of a non-constant call.
2628
// CHECK-LABEL: define {{.*}} void @test
2729
extern "C" void test(T &t) {
28-
// CHECK: store %[[T]]* %{{.*}}, %[[T]]** %[[T_REF:[^,]*]]
29-
// CHECK: %0 = load %[[T]]*, %[[T]]** %[[T_REF]]
30-
// CHECK: call void @take(%[[T]]* {{.*}} %0)
30+
// CHECK: store ptr %{{.*}}, ptr %[[T_REF:[^,]*]]
31+
// CHECK: %0 = load ptr, ptr %[[T_REF]]
32+
// CHECK: call void @take(ptr {{.*}} %0)
3133
take(std::move(t));
32-
// CHECK: %1 = load %[[T]]*, %[[T]]** %[[T_REF]]
33-
// CHECK: call void @take(%[[T]]* {{.*}} %1)
34+
// CHECK: %1 = load ptr, ptr %[[T_REF]]
35+
// CHECK: call void @take(ptr {{.*}} %1)
3436
take(std::move_if_noexcept(t));
35-
// CHECK: %2 = load %[[T]]*, %[[T]]** %[[T_REF]]
36-
// CHECK: call void @take(%[[T]]* {{.*}} %2)
37+
// CHECK: %2 = load ptr, ptr %[[T_REF]]
38+
// CHECK: call void @take(ptr {{.*}} %2)
3739
take(std::forward<T&&>(t));
40+
// CHECK: %3 = load ptr, ptr %[[T_REF]]
41+
// CHECK: call void @take_lval(ptr {{.*}} %3)
42+
take_lval(std::as_const<T&&>(t));
3843

3944
// CHECK: call {{.*}} @_ZSt4moveI1TS0_ET_T0_S2_S1_
4045
std::move(t, t, t);
@@ -49,4 +54,4 @@ extern "C" void *use_address() {
4954
return (void*)&std::move<int>;
5055
}
5156

52-
// CHECK: define {{.*}} i32* @_ZSt4moveIiEOT_RS0_(i32*
57+
// CHECK: define {{.*}} ptr @_ZSt4moveIiEOT_RS0_(ptr

clang/test/CodeGenCXX/builtins.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ S *addressof(bool b, S &s, S &t) {
3030
return __builtin_addressof(b ? s : t);
3131
}
3232

33+
namespace std { template<typename T> T *addressof(T &); }
34+
35+
// CHECK: define {{.*}} @_Z13std_addressofbR1SS0_(
36+
S *std_addressof(bool b, S &s, S &t) {
37+
// CHECK: %[[LVALUE:.*]] = phi
38+
// CHECK: ret {{.*}}* %[[LVALUE]]
39+
return std::addressof(b ? s : t);
40+
}
41+
42+
namespace std { template<typename T> T *__addressof(T &); }
43+
44+
// CHECK: define {{.*}} @_Z15std___addressofbR1SS0_(
45+
S *std___addressof(bool b, S &s, S &t) {
46+
// CHECK: %[[LVALUE:.*]] = phi
47+
// CHECK: ret {{.*}}* %[[LVALUE]]
48+
return std::__addressof(b ? s : t);
49+
}
50+
3351
extern "C" int __builtin_abs(int); // #1
3452
long __builtin_abs(long); // #2
3553
extern "C" int __builtin_abs(int); // #3

clang/test/SemaCXX/builtin-std-move.cpp

+39-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,21 @@ namespace std {
3535
// expected-error@-1 {{no member named 'moveable' in 'C'}}
3636
return static_cast<T&&>(x);
3737
}
38+
39+
template<typename T> CONSTEXPR const T &as_const(T &x) {
40+
static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
41+
return x;
42+
}
43+
44+
template<typename T> CONSTEXPR T *addressof(T &x) {
45+
static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
46+
return __builtin_addressof(x);
47+
}
48+
49+
template<typename T> CONSTEXPR T *__addressof(T &x) {
50+
static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
51+
return __builtin_addressof(x);
52+
}
3853
}
3954

4055
// Note: this doesn't have a 'moveable' member. Instantiation of the above
@@ -45,9 +60,13 @@ constexpr bool f(A a) { // #f
4560
A &&move_if_noexcept = std::move_if_noexcept(a);
4661
A &&forward1 = std::forward<A>(a);
4762
A &forward2 = std::forward<A&>(a);
63+
const A &as_const = std::as_const(a);
64+
A *addressof = std::addressof(a);
65+
A *addressof2 = std::__addressof(a);
4866
return &move == &a && &move_if_noexcept == &a &&
4967
&forward1 == &a && &forward2 == &a &&
50-
std::move(a, a) == 5;
68+
&as_const == &a && addressof == &a &&
69+
addressof2 == &a && std::move(a, a) == 5;
5170
}
5271

5372
#ifndef NO_CONSTEXPR
@@ -61,11 +80,14 @@ struct B {};
6180
B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}}
6281
B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}}
6382
B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}}
83+
const B &(*pAsConst)(B&) = &std::as_const; // #4 expected-note {{instantiation of}}
84+
B *(*pAddressof)(B&) = &std::addressof; // #5 expected-note {{instantiation of}}
85+
B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #6 expected-note {{instantiation of}}
6486
int (*pUnrelatedMove)(B, B) = std::move;
6587

6688
struct C {};
67-
C &&(&rMove)(C&) = std::move; // #4 expected-note {{instantiation of}}
68-
C &&(&rForward)(C&) = std::forward<C>; // #5 expected-note {{instantiation of}}
89+
C &&(&rMove)(C&) = std::move; // #7 expected-note {{instantiation of}}
90+
C &&(&rForward)(C&) = std::forward<C>; // #8 expected-note {{instantiation of}}
6991
int (&rUnrelatedMove)(B, B) = std::move;
7092

7193
#if __cplusplus <= 201703L
@@ -74,17 +96,31 @@ int (&rUnrelatedMove)(B, B) = std::move;
7496
// expected-warning@#3 {{non-addressable}}
7597
// expected-warning@#4 {{non-addressable}}
7698
// expected-warning@#5 {{non-addressable}}
99+
// expected-warning@#6 {{non-addressable}}
100+
// expected-warning@#7 {{non-addressable}}
101+
// expected-warning@#8 {{non-addressable}}
77102
#else
78103
// expected-error@#1 {{non-addressable}}
79104
// expected-error@#2 {{non-addressable}}
80105
// expected-error@#3 {{non-addressable}}
81106
// expected-error@#4 {{non-addressable}}
82107
// expected-error@#5 {{non-addressable}}
108+
// expected-error@#6 {{non-addressable}}
109+
// expected-error@#7 {{non-addressable}}
110+
// expected-error@#8 {{non-addressable}}
83111
#endif
84112

85113
void attribute_const() {
86114
int n;
87115
std::move(n); // expected-warning {{ignoring return value}}
88116
std::move_if_noexcept(n); // expected-warning {{ignoring return value}}
89117
std::forward<int>(n); // expected-warning {{ignoring return value}}
118+
std::addressof(n); // expected-warning {{ignoring return value}}
119+
std::__addressof(n); // expected-warning {{ignoring return value}}
120+
std::as_const(n); // expected-warning {{ignoring return value}}
121+
}
122+
123+
namespace std {
124+
template<typename T> int move(T);
90125
}
126+
int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}

clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1444,7 +1444,7 @@ TEST(ExprMutationAnalyzerTest, UnevaluatedContext) {
14441444
TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
14451445
const std::string Reproducer =
14461446
"namespace std {"
1447-
"template <class T> T forward(T & A) { return static_cast<T&&>(A); }"
1447+
"template <class T> T &forward(T &A) { return static_cast<T&&>(A); }"
14481448
"template <class T> struct __bind {"
14491449
" T f;"
14501450
" template <class V> __bind(T v, V &&) : f(forward(v)) {}"

0 commit comments

Comments
 (0)