[clang] fc30901 - Extend support for std::move etc to also cover std::as_const and
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 15 16:31:58 PDT 2022
Author: Richard Smith
Date: 2022-04-15T16:31:39-07:00
New Revision: fc3090109643af8d2da9822d0f99c84742b9c877
URL: https://github.com/llvm/llvm-project/commit/fc3090109643af8d2da9822d0f99c84742b9c877
DIFF: https://github.com/llvm/llvm-project/commit/fc3090109643af8d2da9822d0f99c84742b9c877.diff
LOG: 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.
Added:
Modified:
clang/include/clang/Basic/Builtins.def
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/AST/ExprConstant.cpp
clang/lib/Analysis/BodyFarm.cpp
clang/lib/CodeGen/CGBuiltin.cpp
clang/lib/Sema/SemaChecking.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/Analysis/inner-pointer.cpp
clang/test/CodeGenCXX/builtin-std-move.cpp
clang/test/CodeGenCXX/builtins.cpp
clang/test/SemaCXX/builtin-std-move.cpp
clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def
index c853229f13970..c22957e14de7d 100644
--- a/clang/include/clang/Basic/Builtins.def
+++ b/clang/include/clang/Basic/Builtins.def
@@ -103,8 +103,7 @@
// V:N: -> requires vectors of at least N bits to be legal
// C<N,M_0,...,M_k> -> callback behavior: argument N is called with argument
// M_0, ..., M_k as payload
-// z -> this is a C++ standard library function in (possibly-versioned)
-// namespace std; implied by STDBUILTIN
+// z -> this is a function in (possibly-versioned) namespace std
// FIXME: gcc has nonnull
#if defined(BUILTIN) && !defined(LIBBUILTIN)
@@ -115,10 +114,6 @@
# define LANGBUILTIN(ID, TYPE, ATTRS, BUILTIN_LANG) BUILTIN(ID, TYPE, ATTRS)
#endif
-#if defined(BUILTIN) && !defined(STDBUILTIN)
-# define STDBUILTIN(ID, TYPE, ATTRS, HEADER) LIBBUILTIN(ID, TYPE, "zf" ATTRS, HEADER, CXX_LANG)
-#endif
-
// Standard libc/libm functions:
BUILTIN(__builtin_atan2 , "ddd" , "Fne")
BUILTIN(__builtin_atan2f, "fff" , "Fne")
@@ -1551,10 +1546,14 @@ LIBBUILTIN(_Block_object_assign, "vv*vC*iC", "f", "Blocks.h", ALL_LANGUAGES)
LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
// FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
-// C++11
-STDBUILTIN(move, "v&v&", "ncTh", "utility")
-STDBUILTIN(move_if_noexcept, "v&v&", "ncTh", "utility")
-STDBUILTIN(forward, "v&v&", "ncTh", "utility")
+// C++ standard library builtins in namespace 'std'.
+LIBBUILTIN(addressof, "v*v&", "zfncTh", "memory", CXX_LANG)
+// Synonym for addressof used internally by libstdc++.
+LANGBUILTIN(__addressof, "v*v&", "zfncT", CXX_LANG)
+LIBBUILTIN(as_const, "v&v&", "zfncTh", "utility", CXX_LANG)
+LIBBUILTIN(forward, "v&v&", "zfncTh", "utility", CXX_LANG)
+LIBBUILTIN(move, "v&v&", "zfncTh", "utility", CXX_LANG)
+LIBBUILTIN(move_if_noexcept, "v&v&", "zfncTh", "utility", CXX_LANG)
// Annotation function
BUILTIN(__builtin_annotation, "v.", "tn")
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cebd24302f1d1..f71f576f9ff47 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6587,7 +6587,7 @@ def warn_self_move : Warning<
InGroup<SelfMove>, DefaultIgnore;
def err_builtin_move_forward_unsupported : Error<
- "unsupported signature for '%select{std::move|std::forward}0'">;
+ "unsupported signature for %q0">;
def err_use_of_unaddressable_function : Error<
"taking address of non-addressable standard library function">;
// FIXME: This should also be in -Wc++23-compat once we have it.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index ce007edca0fc6..410fc8285bb65 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -8295,9 +8295,10 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
bool LValueExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (unsigned BuiltinOp = E->getBuiltinCallee()) {
+ case Builtin::BIas_const:
+ case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
- case Builtin::BIforward:
if (cast<FunctionDecl>(E->getCalleeDecl())->isConstexpr())
return Visit(E->getArg(0));
break;
@@ -9084,6 +9085,8 @@ static bool isOneByteCharacterType(QualType T) {
bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
unsigned BuiltinOp) {
switch (BuiltinOp) {
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
return evaluateLValue(E->getArg(0), Result);
case Builtin::BI__builtin_assume_aligned: {
diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp
index e8c2d4421c618..95bed548c567a 100644
--- a/clang/lib/Analysis/BodyFarm.cpp
+++ b/clang/lib/Analysis/BodyFarm.cpp
@@ -713,9 +713,10 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) {
if (unsigned BuiltinID = D->getBuiltinID()) {
switch (BuiltinID) {
+ case Builtin::BIas_const:
+ case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
- case Builtin::BIforward:
FF = create_std_move_forward;
break;
default:
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index dc4b104201632..640879f92493e 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -4566,6 +4566,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return RValue::get(Carry);
}
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
case Builtin::BI__builtin_addressof:
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
case Builtin::BI__builtin_function_start:
@@ -4729,6 +4731,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
case Builtin::BIforward:
+ case Builtin::BIas_const:
return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this));
case Builtin::BI__GetExceptionInfo: {
if (llvm::GlobalVariable *GV =
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 870f1331069f2..cd069d5664571 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2130,18 +2130,32 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.VoidPtrTy);
break;
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
- case Builtin::BIforward:
+ case Builtin::BIas_const: {
+ // These are all expected to be of the form
+ // T &/&&/* f(U &/&&)
+ // where T and U only
diff er in qualification.
if (checkArgCount(*this, TheCall, 1))
return ExprError();
- if (!Context.hasSameUnqualifiedType(TheCall->getType(),
- TheCall->getArg(0)->getType())) {
+ QualType Param = FDecl->getParamDecl(0)->getType();
+ QualType Result = FDecl->getReturnType();
+ bool ReturnsPointer = BuiltinID == Builtin::BIaddressof ||
+ BuiltinID == Builtin::BI__addressof;
+ if (!(Param->isReferenceType() &&
+ (ReturnsPointer ? Result->isPointerType()
+ : Result->isReferenceType()) &&
+ Context.hasSameUnqualifiedType(Param->getPointeeType(),
+ Result->getPointeeType()))) {
Diag(TheCall->getBeginLoc(), diag::err_builtin_move_forward_unsupported)
- << (BuiltinID == Builtin::BIforward);
+ << FDecl;
return ExprError();
}
break;
+ }
// OpenCL v2.0, s6.13.16 - Pipe functions
case Builtin::BIread_pipe:
case Builtin::BIwrite_pipe:
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index cacd08a62a320..937478416f6d7 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9277,9 +9277,12 @@ static bool isStdBuiltin(ASTContext &Ctx, FunctionDecl *FD,
// No type checking whatsoever.
return Ctx.getTargetInfo().getCXXABI().isMicrosoft();
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BIforward:
case Builtin::BImove:
case Builtin::BImove_if_noexcept:
- case Builtin::BIforward: {
+ case Builtin::BIas_const: {
// Ensure that we don't treat the algorithm
// OutputIt std::move(InputIt, InputIt, OutputIt)
// as the builtin std::move.
diff --git a/clang/test/Analysis/inner-pointer.cpp b/clang/test/Analysis/inner-pointer.cpp
index 920a1fe8dcc9d..5db17a952f90b 100644
--- a/clang/test/Analysis/inner-pointer.cpp
+++ b/clang/test/Analysis/inner-pointer.cpp
@@ -379,7 +379,7 @@ void func_addressof() {
const char *c;
std::string s;
c = s.c_str();
- addressof(s);
+ (void)addressof(s);
consume(c); // no-warning
}
diff --git a/clang/test/CodeGenCXX/builtin-std-move.cpp b/clang/test/CodeGenCXX/builtin-std-move.cpp
index 51498002cd987..9df4beea72bec 100644
--- a/clang/test/CodeGenCXX/builtin-std-move.cpp
+++ b/clang/test/CodeGenCXX/builtin-std-move.cpp
@@ -1,9 +1,10 @@
-// RUN: %clang_cc1 -no-opaque-pointers -triple=x86_64-linux-gnu -emit-llvm -o - -std=c++17 %s | FileCheck %s --implicit-check-not=@_ZSt4move
+// RUN: %clang_cc1 -triple=x86_64-linux-gnu -emit-llvm -o - -std=c++17 %s | FileCheck %s --implicit-check-not=@_ZSt4move
namespace std {
template<typename T> constexpr T &&move(T &val) { return static_cast<T&&>(val); }
template<typename T> constexpr T &&move_if_noexcept(T &val);
template<typename T> constexpr T &&forward(T &val);
+ template<typename T> constexpr const T &as_const(T &val);
// Not the builtin.
template<typename T, typename U> T move(U source, U source_end, T dest);
@@ -11,30 +12,34 @@ namespace std {
class T {};
extern "C" void take(T &&);
+extern "C" void take_lval(const T &);
T a;
// Check emission of a constant-evaluated call.
-// CHECK-DAG: @move_a = constant %[[T:.*]]* @a
+// CHECK-DAG: @move_a = constant ptr @a
T &&move_a = std::move(a);
-// CHECK-DAG: @move_if_noexcept_a = constant %[[T]]* @a
+// CHECK-DAG: @move_if_noexcept_a = constant ptr @a
T &&move_if_noexcept_a = std::move_if_noexcept(a);
-// CHECK-DAG: @forward_a = constant %[[T]]* @a
+// CHECK-DAG: @forward_a = constant ptr @a
T &forward_a = std::forward<T&>(a);
// Check emission of a non-constant call.
// CHECK-LABEL: define {{.*}} void @test
extern "C" void test(T &t) {
- // CHECK: store %[[T]]* %{{.*}}, %[[T]]** %[[T_REF:[^,]*]]
- // CHECK: %0 = load %[[T]]*, %[[T]]** %[[T_REF]]
- // CHECK: call void @take(%[[T]]* {{.*}} %0)
+ // CHECK: store ptr %{{.*}}, ptr %[[T_REF:[^,]*]]
+ // CHECK: %0 = load ptr, ptr %[[T_REF]]
+ // CHECK: call void @take(ptr {{.*}} %0)
take(std::move(t));
- // CHECK: %1 = load %[[T]]*, %[[T]]** %[[T_REF]]
- // CHECK: call void @take(%[[T]]* {{.*}} %1)
+ // CHECK: %1 = load ptr, ptr %[[T_REF]]
+ // CHECK: call void @take(ptr {{.*}} %1)
take(std::move_if_noexcept(t));
- // CHECK: %2 = load %[[T]]*, %[[T]]** %[[T_REF]]
- // CHECK: call void @take(%[[T]]* {{.*}} %2)
+ // CHECK: %2 = load ptr, ptr %[[T_REF]]
+ // CHECK: call void @take(ptr {{.*}} %2)
take(std::forward<T&&>(t));
+ // CHECK: %3 = load ptr, ptr %[[T_REF]]
+ // CHECK: call void @take_lval(ptr {{.*}} %3)
+ take_lval(std::as_const<T&&>(t));
// CHECK: call {{.*}} @_ZSt4moveI1TS0_ET_T0_S2_S1_
std::move(t, t, t);
@@ -49,4 +54,4 @@ extern "C" void *use_address() {
return (void*)&std::move<int>;
}
-// CHECK: define {{.*}} i32* @_ZSt4moveIiEOT_RS0_(i32*
+// CHECK: define {{.*}} ptr @_ZSt4moveIiEOT_RS0_(ptr
diff --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp
index c1c8b51cbae6d..56a29eac2490c 100644
--- a/clang/test/CodeGenCXX/builtins.cpp
+++ b/clang/test/CodeGenCXX/builtins.cpp
@@ -30,6 +30,24 @@ S *addressof(bool b, S &s, S &t) {
return __builtin_addressof(b ? s : t);
}
+namespace std { template<typename T> T *addressof(T &); }
+
+// CHECK: define {{.*}} @_Z13std_addressofbR1SS0_(
+S *std_addressof(bool b, S &s, S &t) {
+ // CHECK: %[[LVALUE:.*]] = phi
+ // CHECK: ret {{.*}}* %[[LVALUE]]
+ return std::addressof(b ? s : t);
+}
+
+namespace std { template<typename T> T *__addressof(T &); }
+
+// CHECK: define {{.*}} @_Z15std___addressofbR1SS0_(
+S *std___addressof(bool b, S &s, S &t) {
+ // CHECK: %[[LVALUE:.*]] = phi
+ // CHECK: ret {{.*}}* %[[LVALUE]]
+ return std::__addressof(b ? s : t);
+}
+
extern "C" int __builtin_abs(int); // #1
long __builtin_abs(long); // #2
extern "C" int __builtin_abs(int); // #3
diff --git a/clang/test/SemaCXX/builtin-std-move.cpp b/clang/test/SemaCXX/builtin-std-move.cpp
index 6a263239ae6b0..a53e57c86c14c 100644
--- a/clang/test/SemaCXX/builtin-std-move.cpp
+++ b/clang/test/SemaCXX/builtin-std-move.cpp
@@ -35,6 +35,21 @@ namespace std {
// expected-error at -1 {{no member named 'moveable' in 'C'}}
return static_cast<T&&>(x);
}
+
+ template<typename T> CONSTEXPR const T &as_const(T &x) {
+ static_assert(T::moveable, "instantiated as_const"); // expected-error {{no member named 'moveable' in 'B'}}
+ return x;
+ }
+
+ template<typename T> CONSTEXPR T *addressof(T &x) {
+ static_assert(T::moveable, "instantiated addressof"); // expected-error {{no member named 'moveable' in 'B'}}
+ return __builtin_addressof(x);
+ }
+
+ template<typename T> CONSTEXPR T *__addressof(T &x) {
+ static_assert(T::moveable, "instantiated __addressof"); // expected-error {{no member named 'moveable' in 'B'}}
+ return __builtin_addressof(x);
+ }
}
// Note: this doesn't have a 'moveable' member. Instantiation of the above
@@ -45,9 +60,13 @@ constexpr bool f(A a) { // #f
A &&move_if_noexcept = std::move_if_noexcept(a);
A &&forward1 = std::forward<A>(a);
A &forward2 = std::forward<A&>(a);
+ const A &as_const = std::as_const(a);
+ A *addressof = std::addressof(a);
+ A *addressof2 = std::__addressof(a);
return &move == &a && &move_if_noexcept == &a &&
&forward1 == &a && &forward2 == &a &&
- std::move(a, a) == 5;
+ &as_const == &a && addressof == &a &&
+ addressof2 == &a && std::move(a, a) == 5;
}
#ifndef NO_CONSTEXPR
@@ -61,11 +80,14 @@ struct B {};
B &&(*pMove)(B&) = std::move; // #1 expected-note {{instantiation of}}
B &&(*pMoveIfNoexcept)(B&) = &std::move_if_noexcept; // #2 expected-note {{instantiation of}}
B &&(*pForward)(B&) = &std::forward<B>; // #3 expected-note {{instantiation of}}
+const B &(*pAsConst)(B&) = &std::as_const; // #4 expected-note {{instantiation of}}
+B *(*pAddressof)(B&) = &std::addressof; // #5 expected-note {{instantiation of}}
+B *(*pUnderUnderAddressof)(B&) = &std::__addressof; // #6 expected-note {{instantiation of}}
int (*pUnrelatedMove)(B, B) = std::move;
struct C {};
-C &&(&rMove)(C&) = std::move; // #4 expected-note {{instantiation of}}
-C &&(&rForward)(C&) = std::forward<C>; // #5 expected-note {{instantiation of}}
+C &&(&rMove)(C&) = std::move; // #7 expected-note {{instantiation of}}
+C &&(&rForward)(C&) = std::forward<C>; // #8 expected-note {{instantiation of}}
int (&rUnrelatedMove)(B, B) = std::move;
#if __cplusplus <= 201703L
@@ -74,12 +96,18 @@ int (&rUnrelatedMove)(B, B) = std::move;
// expected-warning@#3 {{non-addressable}}
// expected-warning@#4 {{non-addressable}}
// expected-warning@#5 {{non-addressable}}
+// expected-warning@#6 {{non-addressable}}
+// expected-warning@#7 {{non-addressable}}
+// expected-warning@#8 {{non-addressable}}
#else
// expected-error@#1 {{non-addressable}}
// expected-error@#2 {{non-addressable}}
// expected-error@#3 {{non-addressable}}
// expected-error@#4 {{non-addressable}}
// expected-error@#5 {{non-addressable}}
+// expected-error@#6 {{non-addressable}}
+// expected-error@#7 {{non-addressable}}
+// expected-error@#8 {{non-addressable}}
#endif
void attribute_const() {
@@ -87,4 +115,12 @@ void attribute_const() {
std::move(n); // expected-warning {{ignoring return value}}
std::move_if_noexcept(n); // expected-warning {{ignoring return value}}
std::forward<int>(n); // expected-warning {{ignoring return value}}
+ std::addressof(n); // expected-warning {{ignoring return value}}
+ std::__addressof(n); // expected-warning {{ignoring return value}}
+ std::as_const(n); // expected-warning {{ignoring return value}}
+}
+
+namespace std {
+ template<typename T> int move(T);
}
+int bad_signature = std::move(0); // expected-error {{unsupported signature for 'std::move<int>'}}
diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
index a4410d330d393..e6360d88a893d 100644
--- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
+++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp
@@ -1444,7 +1444,7 @@ TEST(ExprMutationAnalyzerTest, UnevaluatedContext) {
TEST(ExprMutationAnalyzerTest, ReproduceFailureMinimal) {
const std::string Reproducer =
"namespace std {"
- "template <class T> T forward(T & A) { return static_cast<T&&>(A); }"
+ "template <class T> T &forward(T &A) { return static_cast<T&&>(A); }"
"template <class T> struct __bind {"
" T f;"
" template <class V> __bind(T v, V &&) : f(forward(v)) {}"
More information about the cfe-commits
mailing list