|
7 | 7 | //===----------------------------------------------------------------------===//
|
8 | 8 | #include "../ExprConstShared.h"
|
9 | 9 | #include "Boolean.h"
|
| 10 | +#include "Compiler.h" |
| 11 | +#include "EvalEmitter.h" |
10 | 12 | #include "Interp.h"
|
11 | 13 | #include "PrimType.h"
|
12 | 14 | #include "clang/AST/OSLog.h"
|
@@ -1127,6 +1129,73 @@ static bool interp__builtin_ptrauth_string_discriminator(
|
1127 | 1129 | return true;
|
1128 | 1130 | }
|
1129 | 1131 |
|
| 1132 | +// FIXME: This implementation is not complete. |
| 1133 | +// The Compiler instance we create cannot access the current stack frame, local |
| 1134 | +// variables, function parameters, etc. We also need protection from |
| 1135 | +// side-effects, fatal errors, etc. |
| 1136 | +static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC, |
| 1137 | + const InterpFrame *Frame, |
| 1138 | + const Function *Func, |
| 1139 | + const CallExpr *Call) { |
| 1140 | + const Expr *Arg = Call->getArg(0); |
| 1141 | + QualType ArgType = Arg->getType(); |
| 1142 | + |
| 1143 | + auto returnInt = [&S, Call](bool Value) -> bool { |
| 1144 | + pushInteger(S, Value, Call->getType()); |
| 1145 | + return true; |
| 1146 | + }; |
| 1147 | + |
| 1148 | + // __builtin_constant_p always has one operand. The rules which gcc follows |
| 1149 | + // are not precisely documented, but are as follows: |
| 1150 | + // |
| 1151 | + // - If the operand is of integral, floating, complex or enumeration type, |
| 1152 | + // and can be folded to a known value of that type, it returns 1. |
| 1153 | + // - If the operand can be folded to a pointer to the first character |
| 1154 | + // of a string literal (or such a pointer cast to an integral type) |
| 1155 | + // or to a null pointer or an integer cast to a pointer, it returns 1. |
| 1156 | + // |
| 1157 | + // Otherwise, it returns 0. |
| 1158 | + // |
| 1159 | + // FIXME: GCC also intends to return 1 for literals of aggregate types, but |
| 1160 | + // its support for this did not work prior to GCC 9 and is not yet well |
| 1161 | + // understood. |
| 1162 | + if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() || |
| 1163 | + ArgType->isAnyComplexType() || ArgType->isPointerType() || |
| 1164 | + ArgType->isNullPtrType()) { |
| 1165 | + InterpStack Stk; |
| 1166 | + Compiler<EvalEmitter> C(S.Ctx, S.P, S, Stk); |
| 1167 | + auto Res = C.interpretExpr(Arg, /*ConvertResultToRValue=*/Arg->isGLValue()); |
| 1168 | + if (Res.isInvalid()) { |
| 1169 | + C.cleanup(); |
| 1170 | + Stk.clear(); |
| 1171 | + } |
| 1172 | + |
| 1173 | + const APValue &LV = Res.toAPValue(); |
| 1174 | + if (!Res.isInvalid() && LV.isLValue()) { |
| 1175 | + APValue::LValueBase Base = LV.getLValueBase(); |
| 1176 | + if (Base.isNull()) { |
| 1177 | + // A null base is acceptable. |
| 1178 | + return returnInt(true); |
| 1179 | + } else if (const auto *E = Base.dyn_cast<const Expr *>()) { |
| 1180 | + if (!isa<StringLiteral>(E)) |
| 1181 | + return returnInt(false); |
| 1182 | + return returnInt(LV.getLValueOffset().isZero()); |
| 1183 | + } else if (Base.is<TypeInfoLValue>()) { |
| 1184 | + // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to |
| 1185 | + // evaluate to true. |
| 1186 | + return returnInt(true); |
| 1187 | + } else { |
| 1188 | + // Any other base is not constant enough for GCC. |
| 1189 | + return returnInt(false); |
| 1190 | + } |
| 1191 | + } |
| 1192 | + |
| 1193 | + return returnInt(!Res.isInvalid() && !Res.empty()); |
| 1194 | + } |
| 1195 | + |
| 1196 | + return returnInt(false); |
| 1197 | +} |
| 1198 | + |
1130 | 1199 | bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
1131 | 1200 | const CallExpr *Call) {
|
1132 | 1201 | const InterpFrame *Frame = S.Current;
|
@@ -1456,6 +1525,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
|
1456 | 1525 | return false;
|
1457 | 1526 | break;
|
1458 | 1527 |
|
| 1528 | + case Builtin::BI__builtin_constant_p: |
| 1529 | + if (!interp__builtin_constant_p(S, OpPC, Frame, F, Call)) |
| 1530 | + return false; |
| 1531 | + break; |
| 1532 | + |
1459 | 1533 | default:
|
1460 | 1534 | S.FFDiag(S.Current->getLocation(OpPC),
|
1461 | 1535 | diag::note_invalid_subexpr_in_const_expr)
|
|
0 commit comments