-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[Clang] Fix warning for non std functions with name infinity
#123417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8454,26 +8454,43 @@ static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) { | |
llvm_unreachable("unknown MathCheck"); | ||
} | ||
|
||
static bool IsInfinityFunction(const FunctionDecl *FDecl) { | ||
if (FDecl->getName() != "infinity") | ||
return false; | ||
|
||
if (const CXXMethodDecl *MDecl = dyn_cast<CXXMethodDecl>(FDecl)) { | ||
const CXXRecordDecl *RDecl = MDecl->getParent(); | ||
if (RDecl->getName() != "numeric_limits") | ||
return false; | ||
|
||
if (const NamespaceDecl *NSDecl = | ||
dyn_cast<NamespaceDecl>(RDecl->getDeclContext())) | ||
return NSDecl->isStdNamespace(); | ||
} | ||
|
||
return false; | ||
} | ||
|
||
void Sema::CheckInfNaNFunction(const CallExpr *Call, | ||
const FunctionDecl *FDecl) { | ||
if (!FDecl->getIdentifier()) | ||
return; | ||
|
||
FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts()); | ||
bool HasIdentifier = FDecl->getIdentifier() != nullptr; | ||
bool IsNaNOrIsUnordered = | ||
IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered"); | ||
bool IsSpecialNaN = | ||
HasIdentifier && IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN); | ||
if ((IsNaNOrIsUnordered || IsSpecialNaN) && FPO.getNoHonorNaNs()) { | ||
if (FPO.getNoHonorNaNs() && | ||
(IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") || | ||
IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN))) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think for readability the intermediate There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't mind but my point was that functions are readable for example, for the first boolean, we can easily know the meaning from the condition itself. bool IsInfOrIsFinite =
IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite");
bool IsInfinityOrIsSpecialInf =
HasIdentifier && ((FDecl->getName() == "infinity") ||
IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf)); Also I am thinking of performing the checking only if What do you think? @zahiraam |
||
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | ||
<< 1 << 0 << Call->getSourceRange(); | ||
} else { | ||
bool IsInfOrIsFinite = | ||
IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite"); | ||
bool IsInfinityOrIsSpecialInf = | ||
HasIdentifier && ((FDecl->getName() == "infinity") || | ||
IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf)); | ||
if ((IsInfOrIsFinite || IsInfinityOrIsSpecialInf) && FPO.getNoHonorInfs()) | ||
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | ||
<< 0 << 0 << Call->getSourceRange(); | ||
return; | ||
} | ||
|
||
if (FPO.getNoHonorInfs() && | ||
(IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite") || | ||
IsInfinityFunction(FDecl) || | ||
IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf))) { | ||
Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) | ||
<< 0 << 0 << Call->getSourceRange(); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -48,24 +48,49 @@ namespace std __attribute__((__visibility__("default"))) { | |
isnan(double __x); | ||
bool | ||
isnan(long double __x); | ||
bool | ||
bool | ||
isfinite(float __x); | ||
bool | ||
isfinite(double __x); | ||
bool | ||
isfinte(long double __x); | ||
bool | ||
bool | ||
isunordered(float __x, float __y); | ||
bool | ||
isunordered(double __x, double __y); | ||
bool | ||
isunordered(long double __x, long double __y); | ||
|
||
template <class _Ty> | ||
class numeric_limits { | ||
public: | ||
[[nodiscard]] static constexpr _Ty infinity() noexcept { | ||
return _Ty(); | ||
} | ||
}; | ||
|
||
} // namespace ) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should annotate the std namespace as well |
||
|
||
#define INFINITY ((float)(1e+300 * 1e+300)) | ||
#define NAN (-(float)(INFINITY * 0.0F)) | ||
|
||
template <> | ||
class std::numeric_limits<float> { | ||
public: | ||
[[nodiscard]] static constexpr float infinity() noexcept { | ||
return __builtin_huge_val(); | ||
} | ||
}; | ||
|
||
template <> | ||
class std::numeric_limits<double> { | ||
public: | ||
[[nodiscard]] static constexpr double infinity() noexcept { | ||
return __builtin_huge_val(); | ||
} | ||
}; | ||
|
||
template <class _Ty> | ||
class numeric_limits { | ||
public: | ||
|
@@ -81,6 +106,7 @@ class numeric_limits<float> { | |
return __builtin_huge_val(); | ||
} | ||
}; | ||
|
||
template <> | ||
class numeric_limits<double> { | ||
public: | ||
|
@@ -89,6 +115,8 @@ class numeric_limits<double> { | |
} | ||
}; | ||
|
||
double infinity() { return 0; } | ||
|
||
int compareit(float a, float b) { | ||
volatile int i, j, k, l, m, n, o, p; | ||
// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} | ||
|
@@ -216,11 +244,18 @@ int compareit(float a, float b) { | |
|
||
// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} | ||
// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} | ||
double y = i * numeric_limits<double>::infinity(); | ||
double y = i * std::numeric_limits<double>::infinity(); | ||
|
||
y = i * numeric_limits<double>::infinity(); // expected-no-diagnostics | ||
|
||
// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} | ||
// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} | ||
j = numeric_limits<float>::infinity(); | ||
j = std::numeric_limits<float>::infinity(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So what happens if we are using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes should expect a diagnostic because we check Decl name space not the call expr, I will create a pr to cover this case and update minor comment related to namespace I will tag you as reviewer once I push it Thanks |
||
|
||
j = numeric_limits<float>::infinity(); // expected-no-diagnostics | ||
|
||
y = infinity(); // expected-no-diagnostics | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would like a dependent test or two, to make sure we don't get this wrong/double-diagnose :
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found that we got use of infinity is undefined behavior due to the currently enabled floating-point options for std::numeric_limits::infinity(); for each copy generated from foo function, I will check it more and handle it in different pr There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The same problem will happen with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I'm not getting your point in the previous message. Can you explain it more for me? From my example, I would expect TWO diagnostics (one per use). But I don't want 3 or 4 diagnostics. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I expected two too but what I got is two same warns on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We cannot really, since there is no such thing as 'phase 2' for most of the program (non templates). Typically if you want something ONLY during phase 2, you do it during tree-transform or during the calls to the 'Rebuild' functions. So you ALSO have to do it during phase-1, but the phase-2 work can suppress its diagnostic if it has already been done (assuming you are close enough to rebuild to do that). The fix is likely that you'll have to mvoe where this is diagnosed to somewhere that isn't currently being called by the template instantiation, and re-add it then. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, I will understand the Sema structure more and move it :D Thanks There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have a similar case with a place that covers most cases of using CallExpr, I found a function like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None I can think of at the moment unfortunately. If i run across one, I'll bring it up. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Thank you, I created a PR for the test cases, and I will continue searching for a good function or a place so I can create a one |
||
return 0; | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't something like this work?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with this, Is that in the case of
FPO.getNoHonorNaNs() == false
we performed un needed 3 function calls InIsNaNOrIsUnordered
andIsSpecialNaN
, and in case it's true we performed 3 more un needed tooIsInfOrIsFinite
,IsInfinityOrIsSpecialInf
This reorder can eliminate 3 function calls in the case of
FPO.getNoHonorNaNs() == true
, but still don't eliminate theIsNaNOrIsUnordered
andIsSpecialNaN
in case ofFPO.getNoHonorNaNs() == false
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh! right, That makes sense!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you