Index: clang/lib/AST/Interp/Function.h =================================================================== --- clang/lib/AST/Interp/Function.h +++ clang/lib/AST/Interp/Function.h @@ -171,6 +171,17 @@ unsigned getBuiltinID() const { return F->getBuiltinID(); } + bool isBuiltin() const { return F->getBuiltinID() != 0; } + + bool needsRuntimeArgPop() const { + if (!isBuiltin()) + return false; + // FIXME: Is there a better way to get this information? + if (getName() == "__builtin_isnan") + return true; + return false; + } + unsigned getNumParams() const { return ParamTypes.size(); } unsigned getParamOffset(unsigned ParamIndex) const { Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -200,6 +200,9 @@ // Returning values //===----------------------------------------------------------------------===// +/// Pop arguments of builtins defined as func-name(...). +bool popBuiltinArgs(InterpState &S, CodePtr OpPC); + template ::T> bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { const T &Ret = S.Stk.pop(); @@ -216,8 +219,16 @@ } assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); - if (!S.checkingPotentialConstantExpression() || S.Current->Caller) - S.Current->popArgs(); + if (!S.checkingPotentialConstantExpression() || S.Current->Caller) { + // Certain builtin functions are declared as func-name(...), so the + // parameters are checked in Sema and only available through the CallExpr. + // The interp::Function we create for them has 0 parameters, so we need to + // remove them from the stack by checking the CallExpr. + if (S.Current && S.Current->getFunction()->needsRuntimeArgPop()) + popBuiltinArgs(S, PC); + else + S.Current->popArgs(); + } if (InterpFrame *Caller = S.Current->Caller) { PC = S.Current->getRetPC(); Index: clang/lib/AST/Interp/Interp.cpp =================================================================== --- clang/lib/AST/Interp/Interp.cpp +++ clang/lib/AST/Interp/Interp.cpp @@ -122,6 +122,18 @@ namespace clang { namespace interp { +bool popBuiltinArgs(InterpState &S, CodePtr OpPC) { + assert(S.Current && S.Current->getFunction()->needsRuntimeArgPop()); + const Expr *E = S.Current->getExpr(OpPC); + assert(isa(E)); + const CallExpr *CE = cast(E); + for (const auto &A : CE->arguments()) { + PrimType Ty = S.getContext().classify(A->getType()).value_or(PT_Ptr); + TYPE_SWITCH(Ty, S.Stk.discard()); + } + return true; +} + bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isExtern()) return true; Index: clang/lib/AST/Interp/InterpBuiltin.cpp =================================================================== --- clang/lib/AST/Interp/InterpBuiltin.cpp +++ clang/lib/AST/Interp/InterpBuiltin.cpp @@ -158,6 +158,20 @@ return true; } +/// Defined as __builtin_isnan(...), to accommodate the fact that it can +/// take a float, double, long double, etc. +/// But for us, that's all a Floating anyway. +static bool interp__builtin_isnan(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *F) { + // FIXME: We are not going through getParam() here, because the function + // doesn't have any parameters. Wait for a pattern to emerge and maybe + // refactor this into a different function that checks things are valid. + const Floating &Arg = S.Stk.peek(); + + S.Stk.push>(Integral<32, true>::from(Arg.isNan())); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F) { InterpFrame *Frame = S.Current; APValue Dummy; @@ -213,6 +227,11 @@ return Ret(S, OpPC, Dummy); break; + case Builtin::BI__builtin_isnan: + if (interp__builtin_isnan(S, OpPC, Frame, F)) + return Ret(S, OpPC, Dummy); + break; + default: return false; } Index: clang/test/Sema/constant-builtins-fmin.cpp =================================================================== --- clang/test/Sema/constant-builtins-fmin.cpp +++ clang/test/Sema/constant-builtins-fmin.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -fexperimental-new-constant-interpreter %s // expected-no-diagnostics constexpr double NaN = __builtin_nan("");