Add a __builtin_addressof that performs the same functionality as the built-in

& operator (ignoring any overloaded operator& for the type). The purpose of
this builtin is for use in std::addressof, to allow it to be made constexpr;
the existing implementation technique (reinterpret_cast to some reference type,
take address, reinterpert_cast back) does not permit this because
reinterpret_cast between reference types is not permitted in a constant
expression in C++11 onwards.

llvm-svn: 186053
This commit is contained in:
Richard Smith 2013-07-11 02:27:57 +00:00
parent af9de91fd2
commit 6cbd65d84d
7 changed files with 71 additions and 2 deletions

View File

@ -1533,6 +1533,22 @@ correct code by avoiding expensive loops around
implementation details of ``__sync_lock_test_and_set()``. The implementation details of ``__sync_lock_test_and_set()``. The
``__sync_swap()`` builtin is a full barrier. ``__sync_swap()`` builtin is a full barrier.
``__builtin_addressof``
-----------------------
``__builtin_addressof`` performs the functionality of the built-in ``&``
operator, ignoring any ``operator&`` overload. This is useful in constant
expressions in C++11, where there is no other way to take the address of an
object that overloads ``operator&``.
**Example of use**:
.. code-block:: c++
template<typename T> constexpr T *addressof(T &value) {
return __builtin_addressof(value);
}
Multiprecision Arithmetic Builtins Multiprecision Arithmetic Builtins
---------------------------------- ----------------------------------

View File

@ -959,5 +959,8 @@ BUILTIN(__builtin_smul_overflow, "bSiCSiCSi*", "n")
BUILTIN(__builtin_smull_overflow, "bSLiCSLiCSLi*", "n") BUILTIN(__builtin_smull_overflow, "bSLiCSLiCSLi*", "n")
BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n") BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n")
// Clang builtins (not available in GCC).
BUILTIN(__builtin_addressof, "v*v&", "nct")
#undef BUILTIN #undef BUILTIN
#undef LIBBUILTIN #undef LIBBUILTIN

View File

@ -4513,7 +4513,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (IsStringLiteralCall(E)) if (IsStringLiteralCall(E))
return Success(E); return Success(E);
return ExprEvaluatorBaseTy::VisitCallExpr(E); switch (E->isBuiltinCall()) {
case Builtin::BI__builtin_addressof:
return EvaluateLValue(E->getArg(0), Result, Info);
default:
return ExprEvaluatorBaseTy::VisitCallExpr(E);
}
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -1489,6 +1489,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
return RValue::get(Carry); return RValue::get(Carry);
} }
case Builtin::BI__builtin_addressof:
return RValue::get(EmitLValue(E->getArg(0)).getAddress());
case Builtin::BI__noop: case Builtin::BI__noop:
return RValue::get(0); return RValue::get(0);
} }

View File

@ -95,6 +95,22 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) {
return false; return false;
} }
/// Check that the argument to __builtin_addressof is a glvalue, and set the
/// result type to the corresponding pointer type.
static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) {
if (checkArgCount(S, TheCall, 1))
return true;
ExprResult Arg(S.Owned(TheCall->getArg(0)));
QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getLocStart());
if (ResultType.isNull())
return true;
TheCall->setArg(0, Arg.take());
TheCall->setType(ResultType);
return false;
}
ExprResult ExprResult
Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
ExprResult TheCallResult(Owned(TheCall)); ExprResult TheCallResult(Owned(TheCall));
@ -275,6 +291,10 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
if (SemaBuiltinAnnotation(*this, TheCall)) if (SemaBuiltinAnnotation(*this, TheCall))
return ExprError(); return ExprError();
break; break;
case Builtin::BI__builtin_addressof:
if (SemaBuiltinAddressof(*this, TheCall))
return ExprError();
break;
} }
// Since the target specific builtins for each arch overlap, only check those // Since the target specific builtins for each arch overlap, only check those

View File

@ -7,3 +7,11 @@ int main() {
// CHECK: call {{signext i8|i8}} @memmove() // CHECK: call {{signext i8|i8}} @memmove()
return memmove(); return memmove();
} }
struct S;
// CHECK: define {{.*}} @_Z9addressofbR1SS0_(
S *addressof(bool b, S &s, S &t) {
// CHECK: %[[LVALUE:.*]] = phi
// CHECK: ret {{.*}}* %[[LVALUE]]
return __builtin_addressof(b ? s : t);
}

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -fsyntax-only -verify // RUN: %clang_cc1 %s -fsyntax-only -verify -std=c++11
typedef const struct __CFString * CFStringRef; typedef const struct __CFString * CFStringRef;
#define CFSTR __builtin___CFStringMakeConstantString #define CFSTR __builtin___CFStringMakeConstantString
@ -24,3 +24,17 @@ void f2() {
// pr14895 // pr14895
typedef __typeof(sizeof(int)) size_t; typedef __typeof(sizeof(int)) size_t;
extern "C" void *__builtin_alloca (size_t); extern "C" void *__builtin_alloca (size_t);
namespace addressof {
struct S {} s;
static_assert(__builtin_addressof(s) == &s, "");
struct T { constexpr T *operator&() const { return nullptr; } int n; } t;
constexpr T *pt = __builtin_addressof(t);
static_assert(&pt->n == &t.n, "");
struct U { int n : 5; } u;
int *pbf = __builtin_addressof(u.n); // expected-error {{address of bit-field requested}}
S *ptmp = __builtin_addressof(S{}); // expected-error {{taking the address of a temporary}}
}