}
/// EvaluateBuiltinConstantPForLValue - Determine the result of
-/// __builtin_constant_p when applied to the given lvalue.
+/// __builtin_constant_p when applied to the given pointer.
///
-/// An lvalue is only "constant" if it is a pointer or reference to the first
-/// character of a string literal.
-template<typename LValue>
-static bool EvaluateBuiltinConstantPForLValue(const LValue &LV) {
- const Expr *E = LV.getLValueBase().template dyn_cast<const Expr*>();
- return E && isa<StringLiteral>(E) && LV.getLValueOffset().isZero();
+/// A pointer is only "constant" if it is null (or a pointer cast to integer)
+/// or it points to the first character of a string literal.
+static bool EvaluateBuiltinConstantPForLValue(const APValue &LV) {
+ APValue::LValueBase Base = LV.getLValueBase();
+ if (Base.isNull()) {
+ // A null base is acceptable.
+ return true;
+ } else if (const Expr *E = Base.dyn_cast<const Expr *>()) {
+ if (!isa<StringLiteral>(E))
+ return false;
+ return LV.getLValueOffset().isZero();
+ } else {
+ // Any other base is not constant enough for GCC.
+ return false;
+ }
}
/// EvaluateBuiltinConstantP - Evaluate __builtin_constant_p as similarly to
/// GCC as we can manage.
-static bool EvaluateBuiltinConstantP(ASTContext &Ctx, const Expr *Arg) {
+static bool EvaluateBuiltinConstantP(EvalInfo &Info, const Expr *Arg) {
+ // Constant-folding is always enabled for the operand of __builtin_constant_p
+ // (even when the enclosing evaluation context otherwise requires a strict
+ // language-specific constant expression).
+ FoldConstant Fold(Info, true);
+
QualType ArgType = Arg->getType();
// __builtin_constant_p always has one operand. The rules which gcc follows
//
// - If the operand is of integral, floating, complex or enumeration type,
// and can be folded to a known value of that type, it returns 1.
- // - If the operand and can be folded to a pointer to the first character
- // of a string literal (or such a pointer cast to an integral type), it
- // returns 1.
+ // - If the operand can be folded to a pointer to the first character
+ // of a string literal (or such a pointer cast to an integral type)
+ // or to a null pointer or an integer cast to a pointer, it returns 1.
//
// Otherwise, it returns 0.
//
// FIXME: GCC also intends to return 1 for literals of aggregate types, but
- // its support for this does not currently work.
- if (ArgType->isIntegralOrEnumerationType()) {
- Expr::EvalResult Result;
- if (!Arg->EvaluateAsRValue(Result, Ctx) || Result.HasSideEffects)
+ // its support for this did not work prior to GCC 9 and is not yet well
+ // understood.
+ if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() ||
+ ArgType->isAnyComplexType() || ArgType->isPointerType() ||
+ ArgType->isNullPtrType()) {
+ APValue V;
+ if (!::EvaluateAsRValue(Info, Arg, V)) {
+ Fold.keepDiagnostics();
return false;
+ }
- APValue &V = Result.Val;
- if (V.getKind() == APValue::Int)
- return true;
+ // For a pointer (possibly cast to integer), there are special rules.
if (V.getKind() == APValue::LValue)
return EvaluateBuiltinConstantPForLValue(V);
- } else if (ArgType->isFloatingType() || ArgType->isAnyComplexType()) {
- return Arg->isEvaluatable(Ctx);
- } else if (ArgType->isPointerType() || Arg->isGLValue()) {
- LValue LV;
- Expr::EvalStatus Status;
- EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantFold);
- if ((Arg->isGLValue() ? EvaluateLValue(Arg, LV, Info)
- : EvaluatePointer(Arg, LV, Info)) &&
- !Status.HasSideEffects)
- return EvaluateBuiltinConstantPForLValue(LV);
+
+ // Otherwise, any constant value is good enough.
+ return V.getKind() != APValue::Uninitialized;
}
// Anything else isn't considered to be sufficiently constant.
}
case Builtin::BI__builtin_constant_p: {
- auto Arg = E->getArg(0);
- if (EvaluateBuiltinConstantP(Info.Ctx, Arg))
+ const Expr *Arg = E->getArg(0);
+ if (EvaluateBuiltinConstantP(Info, Arg))
return Success(true, E);
- auto ArgTy = Arg->IgnoreImplicit()->getType();
- if (!Info.InConstantContext && !Arg->HasSideEffects(Info.Ctx) &&
- !ArgTy->isAggregateType() && !ArgTy->isPointerType()) {
- // We can delay calculation of __builtin_constant_p until after
- // inlining. Note: This diagnostic won't be shown to the user.
+ else if (Info.InConstantContext)
+ return Success(false, E);
+ else {
Info.FFDiag(E, diag::note_invalid_subexpr_in_const_expr);
return false;
}
- return Success(false, E);
}
case Builtin::BI__builtin_is_constant_evaluated:
--- /dev/null
+// RUN: %clang_cc1 -std=c++17 -verify %s
+
+using intptr_t = __INTPTR_TYPE__;
+
+// Test interaction of constexpr and __builtin_constant_p.
+
+template<typename T> constexpr bool bcp(T t) {
+ return __builtin_constant_p(t);
+}
+template<typename T> constexpr bool bcp_fold(T t) {
+ return __builtin_constant_p(((void)(intptr_t)&t, t));
+}
+
+constexpr intptr_t ensure_fold_is_generally_not_enabled = // expected-error {{constant expression}}
+ (intptr_t)&ensure_fold_is_generally_not_enabled; // expected-note {{cast}}
+
+constexpr intptr_t ptr_to_int(const void *p) {
+ return __builtin_constant_p(1) ? (intptr_t)p : (intptr_t)p;
+}
+
+constexpr int *int_to_ptr(intptr_t n) {
+ return __builtin_constant_p(1) ? (int*)n : (int*)n;
+}
+
+int x;
+
+// Integer and floating point constants encountered during constant expression
+// evaluation are considered constant. So is nullptr_t.
+static_assert(bcp(1));
+static_assert(bcp_fold(1));
+static_assert(bcp(1.0));
+static_assert(bcp_fold(1.0));
+static_assert(bcp(nullptr));
+static_assert(bcp_fold(nullptr));
+
+// Pointers to the start of strings are considered constant.
+static_assert(bcp("foo"));
+static_assert(bcp_fold("foo"));
+
+// Null pointers are considered constant.
+static_assert(bcp<int*>(nullptr));
+static_assert(bcp_fold<int*>(nullptr));
+static_assert(bcp<const char*>(nullptr));
+static_assert(bcp_fold<const char*>(nullptr));
+
+// Other pointers are not.
+static_assert(!bcp(&x));
+static_assert(!bcp_fold(&x));
+
+// Pointers cast to integers follow the rules for pointers.
+static_assert(bcp(ptr_to_int("foo")));
+static_assert(bcp_fold(ptr_to_int("foo")));
+static_assert(!bcp(ptr_to_int(&x)));
+static_assert(!bcp_fold(ptr_to_int(&x)));
+
+// Integers cast to pointers follow the integer rules.
+static_assert(bcp(int_to_ptr(0)));
+static_assert(bcp_fold(int_to_ptr(0)));
+static_assert(bcp(int_to_ptr(123))); // GCC rejects these due to not recognizing
+static_assert(bcp_fold(int_to_ptr(123))); // the bcp conditional in 'int_to_ptr' ...
+static_assert(__builtin_constant_p((int*)123)); // ... but GCC accepts this