From: Richard Smith Date: Thu, 11 Jul 2013 02:27:57 +0000 (+0000) Subject: Add a __builtin_addressof that performs the same functionality as the built-in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5154dce6388e3aaa445467030df7a45ed1211abe;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186053 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index d7f46b5f15..bfc5feb30b 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -1533,6 +1533,22 @@ correct code by avoiding expensive loops around implementation details of ``__sync_lock_test_and_set()``. The ``__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 constexpr T *addressof(T &value) { + return __builtin_addressof(value); + } + Multiprecision Arithmetic Builtins ---------------------------------- diff --git a/include/clang/Basic/Builtins.def b/include/clang/Basic/Builtins.def index 7aad5ea96a..71c45ffa15 100644 --- a/include/clang/Basic/Builtins.def +++ b/include/clang/Basic/Builtins.def @@ -959,5 +959,8 @@ BUILTIN(__builtin_smul_overflow, "bSiCSiCSi*", "n") BUILTIN(__builtin_smull_overflow, "bSLiCSLiCSLi*", "n") BUILTIN(__builtin_smulll_overflow, "bSLLiCSLLiCSLLi*", "n") +// Clang builtins (not available in GCC). +BUILTIN(__builtin_addressof, "v*v&", "nct") + #undef BUILTIN #undef LIBBUILTIN diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 67c187c039..28473f0bdb 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -4513,7 +4513,13 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (IsStringLiteralCall(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); + } } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2fd873ef56..b5c673c75c 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1489,6 +1489,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Carry); } + case Builtin::BI__builtin_addressof: + return RValue::get(EmitLValue(E->getArg(0)).getAddress()); case Builtin::BI__noop: return RValue::get(0); } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index e82f918198..c0dd9fc46d 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -95,6 +95,22 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { 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 Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(Owned(TheCall)); @@ -275,6 +291,10 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (SemaBuiltinAnnotation(*this, TheCall)) return ExprError(); 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 diff --git a/test/CodeGenCXX/builtins.cpp b/test/CodeGenCXX/builtins.cpp index c9b0bff0f2..7b17e14653 100644 --- a/test/CodeGenCXX/builtins.cpp +++ b/test/CodeGenCXX/builtins.cpp @@ -7,3 +7,11 @@ int main() { // CHECK: call {{signext i8|i8}} @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); +} diff --git a/test/SemaCXX/builtins.cpp b/test/SemaCXX/builtins.cpp index 5d61690c16..63aa711d62 100644 --- a/test/SemaCXX/builtins.cpp +++ b/test/SemaCXX/builtins.cpp @@ -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; #define CFSTR __builtin___CFStringMakeConstantString @@ -24,3 +24,17 @@ void f2() { // pr14895 typedef __typeof(sizeof(int)) 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}} +}