Skip to content

Commit

Permalink
[CLANG] Fix INF/NAN warning. (llvm#80290)
Browse files Browse the repository at this point in the history
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.
  • Loading branch information
zahiraam authored Feb 6, 2024
1 parent ffd79b3 commit 62c352e
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 22 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def warn_pragma_debug_unexpected_argument : Warning<
def warn_fp_nan_inf_when_disabled : Warning<
"use of %select{infinity|NaN}0%select{| via a macro}1 is undefined behavior "
"due to the currently enabled floating-point options">,
InGroup<DiagGroup<"nan-infinity-disabled">>;
InGroup<DiagGroup<"nan-infinity-disabled", [], NanInfDisabledDocs>>;
}

// Parse && Sema
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Basic/DiagnosticDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,12 @@ program by treating all string literals as having type ``const char *``
instead of ``char *``. This can cause unexpected behaviors with type-sensitive
constructs like ``_Generic``.
}];

defvar NanInfDisabledDocs = [{
This warning is enabled when source code using the macros ``INFINITY`` or ``NAN``
is compiled with floating-point options preventing these two values. This can
lead to undefined behavior. Check the order of command line arguments that modify
this behavior, such as ``-ffast-math``, ``-fhonor-infinities``, and
``-fhonor-nans`` (etc), as well as ``#pragma`` directives if this diagnostic is
generated unexpectedly.
}];
11 changes: 6 additions & 5 deletions clang/include/clang/Lex/Preprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2838,7 +2838,8 @@ class Preprocessor {
return AnnotationInfos.find(II)->second;
}

void emitMacroExpansionWarnings(const Token &Identifier) const {
void emitMacroExpansionWarnings(const Token &Identifier,
bool IsIfnDef = false) const {
IdentifierInfo *Info = Identifier.getIdentifierInfo();
if (Info->isDeprecatedMacro())
emitMacroDeprecationWarning(Identifier);
Expand All @@ -2847,12 +2848,12 @@ class Preprocessor {
!SourceMgr.isInMainFile(Identifier.getLocation()))
emitRestrictExpansionWarning(Identifier);

if (Info->getName() == "INFINITY")
if (getLangOpts().NoHonorInfs)
if (!IsIfnDef) {
if (Info->getName() == "INFINITY" && getLangOpts().NoHonorInfs)
emitRestrictInfNaNWarning(Identifier, 0);
if (Info->getName() == "NAN")
if (getLangOpts().NoHonorNaNs)
if (Info->getName() == "NAN" && getLangOpts().NoHonorNaNs)
emitRestrictInfNaNWarning(Identifier, 1);
}
}

static void processPathForFileMacro(SmallVectorImpl<char> &Path,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Lex/PPDirectives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3288,7 +3288,7 @@ void Preprocessor::HandleIfdefDirective(Token &Result,
return;
}

emitMacroExpansionWarnings(MacroNameTok);
emitMacroExpansionWarnings(MacroNameTok, /*IsIfnDef=*/true);

// Check to see if this is the last token on the #if[n]def line.
CheckEndOfDirective(isIfndef ? "ifndef" : "ifdef");
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Lex/PPExpressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ static bool EvaluateDefined(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
Result.Val.setIsUnsigned(false); // Result is signed intmax_t.
DT.IncludedUndefinedIds = !Macro;

PP.emitMacroExpansionWarnings(PeekTok);
PP.emitMacroExpansionWarnings(
PeekTok,
(II->getName() == "INFINITY" || II->getName() == "NAN") ? true : false);

// If there is a macro, mark it used.
if (Result.Val != 0 && ValueLive)
Expand Down
60 changes: 53 additions & 7 deletions clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs -menable-no-nans
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
// RUN: -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown %s
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs
// RUN: -menable-no-infs -funsafe-math-optimizations -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans
// RUN: -funsafe-math-optimizations -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -Wno-nan-infinity-disabled -menable-no-infs -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -Wno-nan-infinity-disabled -menable-no-nans -std=c++23

// no-fast-no-diagnostics

Expand Down Expand Up @@ -133,13 +151,41 @@ int compareit(float a, float b) {
// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
p = __builtin_isfinite(a);

// These should NOT warn, since they are not using NaN or infinity.
// These should NOT warn, since they are not using NaN or infinity.
j = a > 1.1;
j = b < 1.1;
j = a >= 1.1;
j = b <= 1.1;
j = isunorderedf(a, b);

#ifndef INFINITY
j = a;
#endif
#ifndef NAN
j = b;
#endif
#ifdef INFINITY
j = a;
#endif
#ifdef NAN
j = b;
#endif
#if defined(INFINITY)
j = a;
#elifndef(INFINITY)
j = b;
#endif
#if defined(INFINITY)
j = a;
#elifndef(NAN)
j = b;
#endif
#if defined(NAN)
j = a;
#elifndef(INFINITY)
j = b;
#endif

// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}}
// no-nan-warning@+2 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}}
Expand Down Expand Up @@ -173,4 +219,4 @@ int compareit(float a, float b) {
j = numeric_limits<float>::infinity();
return 0;

}
}
60 changes: 53 additions & 7 deletions clang/test/Sema/warn-infinity-nan-disabled-win.cpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
// Use of NAN macro will trigger a warning "infinity defined in macro" because
// on Windows the NAN macro is defined using INFINITY. See below.

// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs -menable-no-nans
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
// RUN: -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown %s
// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \
// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \
// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs
// RUN: -menable-no-infs -funsafe-math-optimizations -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans
// RUN: -funsafe-math-optimizations -menable-no-nans -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -Wno-nan-infinity-disabled -menable-no-infs -std=c++23

// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \
// RUN: %s -Wno-nan-infinity-disabled -menable-no-nans -std=c++23

// no-fast-no-diagnostics

Expand Down Expand Up @@ -136,13 +154,41 @@ int compareit(float a, float b) {
// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}}
p = __builtin_isfinite(a);

// These should NOT warn, since they are not using NaN or infinity.
// These should NOT warn, since they are not using NaN or infinity.
j = a > 1.1;
j = b < 1.1;
j = a >= 1.1;
j = b <= 1.1;
j = isunorderedf(a, b);

#ifndef INFINITY
j = a;
#endif
#ifndef NAN
j = b;
#endif
#ifdef INFINITY
j = a;
#endif
#ifdef NAN
j = b;
#endif
#if defined(INFINITY)
j = a;
#elifndef(INFINITY)
j = b;
#endif
#if defined(INFINITY)
j = a;
#elifndef(NAN)
j = b;
#endif
#if defined(NAN)
j = a;
#elifndef(INFINITY)
j = b;
#endif

// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point option}}
// no-inf-no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}}
// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}}
Expand Down Expand Up @@ -176,4 +222,4 @@ int compareit(float a, float b) {
j = numeric_limits<float>::infinity();
return 0;

}
}

0 comments on commit 62c352e

Please sign in to comment.