diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index d7f46b5f15d8..bfc5feb30b83 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/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/clang/include/clang/Basic/Builtins.def b/clang/include/clang/Basic/Builtins.def index 7aad5ea96afa..71c45ffa15a3 100644 --- a/clang/include/clang/Basic/Builtins.def +++ b/clang/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/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 67c187c039b1..28473f0bdbd8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/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/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2fd873ef568f..b5c673c75c04 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/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/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e82f918198c5..c0dd9fc46dd2 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/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/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp index c9b0bff0f2e2..7b17e14653d0 100644 --- a/clang/test/CodeGenCXX/builtins.cpp +++ b/clang/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/clang/test/SemaCXX/builtins.cpp b/clang/test/SemaCXX/builtins.cpp index 5d61690c16e5..63aa711d62db 100644 --- a/clang/test/SemaCXX/builtins.cpp +++ b/clang/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}} +}