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 d7f46b5..bfc5feb 100644
--- a/docs/LanguageExtensions.rst
+++ b/docs/LanguageExtensions.rst
@@ -1533,6 +1533,22 @@
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<typename T> 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 7aad5ea..71c45ff 100644
--- a/include/clang/Basic/Builtins.def
+++ b/include/clang/Basic/Builtins.def
@@ -959,5 +959,8 @@
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 67c187c..28473f0 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -4513,7 +4513,13 @@
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 2fd873e..b5c673c 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -1489,6 +1489,8 @@
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 e82f918..c0dd9fc 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -95,6 +95,22 @@
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 @@
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 c9b0bff..7b17e14 100644
--- a/test/CodeGenCXX/builtins.cpp
+++ b/test/CodeGenCXX/builtins.cpp
@@ -7,3 +7,11 @@
// 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 5d61690..63aa711 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 @@
// 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}}
+}