Skip to content

Commit 4b5fe9c

Browse files
committed
[clang][Interp] Check floating results for NaNs
Differential Revision: https://reviews.llvm.org/D156506
1 parent 53602e6 commit 4b5fe9c

File tree

3 files changed

+38
-10
lines changed

3 files changed

+38
-10
lines changed

clang/lib/AST/Interp/Interp.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,13 +495,25 @@ bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
495495
return false;
496496
}
497497

498-
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
498+
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
499+
APFloat::opStatus Status) {
500+
const SourceInfo &E = S.Current->getSource(OpPC);
501+
502+
// [expr.pre]p4:
503+
// If during the evaluation of an expression, the result is not
504+
// mathematically defined [...], the behavior is undefined.
505+
// FIXME: C++ rules require us to not conform to IEEE 754 here.
506+
if (Result.isNan()) {
507+
S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
508+
<< /*NaN=*/true << S.Current->getRange(OpPC);
509+
return S.noteUndefinedBehavior();
510+
}
511+
499512
// In a constant context, assume that any dynamic rounding mode or FP
500513
// exception state matches the default floating-point environment.
501514
if (S.inConstantContext())
502515
return true;
503516

504-
const SourceInfo &E = S.Current->getSource(OpPC);
505517
FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
506518

507519
if ((Status & APFloat::opInexact) &&

clang/lib/AST/Interp/Interp.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
172172

173173
/// Checks if the result of a floating-point operation is valid
174174
/// in the current context.
175-
bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
175+
bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
176+
APFloat::opStatus Status);
176177

177178
/// Interpreter entry point.
178179
bool Interpret(InterpState &S, APValue &Result);
@@ -304,7 +305,7 @@ inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
304305
Floating Result;
305306
auto Status = Floating::add(LHS, RHS, RM, &Result);
306307
S.Stk.push<Floating>(Result);
307-
return CheckFloatResult(S, OpPC, Status);
308+
return CheckFloatResult(S, OpPC, Result, Status);
308309
}
309310

310311
template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -322,7 +323,7 @@ inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
322323
Floating Result;
323324
auto Status = Floating::sub(LHS, RHS, RM, &Result);
324325
S.Stk.push<Floating>(Result);
325-
return CheckFloatResult(S, OpPC, Status);
326+
return CheckFloatResult(S, OpPC, Result, Status);
326327
}
327328

328329
template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -340,7 +341,7 @@ inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
340341
Floating Result;
341342
auto Status = Floating::mul(LHS, RHS, RM, &Result);
342343
S.Stk.push<Floating>(Result);
343-
return CheckFloatResult(S, OpPC, Status);
344+
return CheckFloatResult(S, OpPC, Result, Status);
344345
}
345346
/// 1) Pops the RHS from the stack.
346347
/// 2) Pops the LHS from the stack.
@@ -443,7 +444,7 @@ inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
443444
Floating Result;
444445
auto Status = Floating::div(LHS, RHS, RM, &Result);
445446
S.Stk.push<Floating>(Result);
446-
return CheckFloatResult(S, OpPC, Status);
447+
return CheckFloatResult(S, OpPC, Result, Status);
447448
}
448449

449450
//===----------------------------------------------------------------------===//
@@ -622,7 +623,7 @@ bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
622623

623624
Ptr.deref<Floating>() = Result;
624625

625-
return CheckFloatResult(S, OpPC, Status);
626+
return CheckFloatResult(S, OpPC, Result, Status);
626627
}
627628

628629
inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
@@ -1525,7 +1526,7 @@ bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
15251526
auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
15261527
S.Stk.push<Floating>(Result);
15271528

1528-
return CheckFloatResult(S, OpPC, Status);
1529+
return CheckFloatResult(S, OpPC, Result, Status);
15291530
}
15301531

15311532
template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -1550,7 +1551,7 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
15501551
}
15511552

15521553
S.Stk.push<T>(T(Result));
1553-
return CheckFloatResult(S, OpPC, Status);
1554+
return CheckFloatResult(S, OpPC, F, Status);
15541555
}
15551556
}
15561557

clang/test/AST/Interp/floats.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,18 @@ namespace Compare {
202202
static_assert(!(inf < nan), "");
203203
static_assert(!(inf > nan), "");
204204
}
205+
206+
namespace nan {
207+
constexpr double nan = __builtin_nan("");
208+
static_assert(nan);
209+
210+
constexpr double D1 = 1 + nan; // ref-error {{must be initialized by a constant expression}} \
211+
// ref-note {{produces a NaN}} \
212+
// expected-error {{must be initialized by a constant expression}} \
213+
// expected-note {{produces a NaN}}
214+
215+
constexpr double D2 = __builtin_inf() / __builtin_inf(); // ref-error {{must be initialized by a constant expression}} \
216+
// ref-note {{produces a NaN}} \
217+
// expected-error {{must be initialized by a constant expression}} \
218+
// expected-note {{produces a NaN}}
219+
}

0 commit comments

Comments
 (0)