Skip to content

Commit 9042713

Browse files
author
git apple-llvm automerger
committed
Merge commit 'f3c77445791b' from llvm.org/main into next
2 parents 163855a + f3c7744 commit 9042713

File tree

3 files changed

+141
-38
lines changed

3 files changed

+141
-38
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,14 @@ Improvements to Clang's diagnostics
371371
372372
- An error is now emitted when a ``musttail`` call is made to a function marked with the ``not_tail_called`` attribute. (#GH133509).
373373

374+
- ``-Whigher-precisision-for-complex-divison`` warns when:
375+
376+
- The divisor is complex.
377+
- When the complex division happens in a higher precision type due to arithmetic promotion.
378+
- When using the divide and assign operator (``/=``).
379+
380+
Fixes #GH131127
381+
374382
Improvements to Clang's time-trace
375383
----------------------------------
376384

clang/lib/Sema/SemaExpr.cpp

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13323,6 +13323,45 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
1332313323
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
1332413324
}
1332513325

13326+
static void DetectPrecisionLossInComplexDivision(Sema &S, QualType DivisorTy,
13327+
SourceLocation OpLoc) {
13328+
// If the divisor is real, then this is real/real or complex/real division.
13329+
// Either way there can be no precision loss.
13330+
auto *CT = DivisorTy->getAs<ComplexType>();
13331+
if (!CT)
13332+
return;
13333+
13334+
QualType ElementType = CT->getElementType();
13335+
bool IsComplexRangePromoted = S.getLangOpts().getComplexRange() ==
13336+
LangOptions::ComplexRangeKind::CX_Promoted;
13337+
if (!ElementType->isFloatingType() || !IsComplexRangePromoted)
13338+
return;
13339+
13340+
ASTContext &Ctx = S.getASTContext();
13341+
QualType HigherElementType = Ctx.GetHigherPrecisionFPType(ElementType);
13342+
const llvm::fltSemantics &ElementTypeSemantics =
13343+
Ctx.getFloatTypeSemantics(ElementType);
13344+
const llvm::fltSemantics &HigherElementTypeSemantics =
13345+
Ctx.getFloatTypeSemantics(HigherElementType);
13346+
13347+
if ((llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 >
13348+
llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) ||
13349+
(HigherElementType == Ctx.LongDoubleTy &&
13350+
!Ctx.getTargetInfo().hasLongDoubleType())) {
13351+
// Retain the location of the first use of higher precision type.
13352+
if (!S.LocationOfExcessPrecisionNotSatisfied.isValid())
13353+
S.LocationOfExcessPrecisionNotSatisfied = OpLoc;
13354+
for (auto &[Type, Num] : S.ExcessPrecisionNotSatisfied) {
13355+
if (Type == HigherElementType) {
13356+
Num++;
13357+
return;
13358+
}
13359+
}
13360+
S.ExcessPrecisionNotSatisfied.push_back(std::make_pair(
13361+
HigherElementType, S.ExcessPrecisionNotSatisfied.size()));
13362+
}
13363+
}
13364+
1332613365
static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS,
1332713366
SourceLocation Loc) {
1332813367
const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS);
@@ -13417,6 +13456,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
1341713456
if (compType.isNull() || !compType->isArithmeticType())
1341813457
return InvalidOperands(Loc, LHS, RHS);
1341913458
if (IsDiv) {
13459+
DetectPrecisionLossInComplexDivision(*this, RHS.get()->getType(), Loc);
1342013460
DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv);
1342113461
DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc);
1342213462
}
@@ -18515,39 +18555,6 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc,
1851518555
DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr);
1851618556
}
1851718557

18518-
static void DetectPrecisionLossInComplexDivision(Sema &S, SourceLocation OpLoc,
18519-
Expr *Operand) {
18520-
if (auto *CT = Operand->getType()->getAs<ComplexType>()) {
18521-
QualType ElementType = CT->getElementType();
18522-
bool IsComplexRangePromoted = S.getLangOpts().getComplexRange() ==
18523-
LangOptions::ComplexRangeKind::CX_Promoted;
18524-
if (ElementType->isFloatingType() && IsComplexRangePromoted) {
18525-
ASTContext &Ctx = S.getASTContext();
18526-
QualType HigherElementType = Ctx.GetHigherPrecisionFPType(ElementType);
18527-
const llvm::fltSemantics &ElementTypeSemantics =
18528-
Ctx.getFloatTypeSemantics(ElementType);
18529-
const llvm::fltSemantics &HigherElementTypeSemantics =
18530-
Ctx.getFloatTypeSemantics(HigherElementType);
18531-
if ((llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 >
18532-
llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) ||
18533-
(HigherElementType == Ctx.LongDoubleTy &&
18534-
!Ctx.getTargetInfo().hasLongDoubleType())) {
18535-
// Retain the location of the first use of higher precision type.
18536-
if (!S.LocationOfExcessPrecisionNotSatisfied.isValid())
18537-
S.LocationOfExcessPrecisionNotSatisfied = OpLoc;
18538-
for (auto &[Type, Num] : S.ExcessPrecisionNotSatisfied) {
18539-
if (Type == HigherElementType) {
18540-
Num++;
18541-
return;
18542-
}
18543-
}
18544-
S.ExcessPrecisionNotSatisfied.push_back(std::make_pair(
18545-
HigherElementType, S.ExcessPrecisionNotSatisfied.size()));
18546-
}
18547-
}
18548-
}
18549-
}
18550-
1855118558
ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
1855218559
tok::TokenKind Kind,
1855318560
Expr *LHSExpr, Expr *RHSExpr) {
@@ -18558,11 +18565,6 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc,
1855818565
// Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0"
1855918566
DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr);
1856018567

18561-
// Emit warnings if the requested higher precision type equal to the current
18562-
// type precision.
18563-
if (Kind == tok::TokenKind::slash)
18564-
DetectPrecisionLossInComplexDivision(*this, TokLoc, LHSExpr);
18565-
1856618568
BuiltinCountedByRefKind K =
1856718569
BinaryOperator::isAssignmentOp(Opc) ? AssignmentKind : BinaryExprKind;
1856818570

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-linux -verify=no-diag \
2+
// RUN: -DDIV_CC -DDIV_RC -DDIVASSIGN -DDIVMIXEDFD -DDIVMIXEDFD2 -DDIVMIXEDID -DDIVASSIGN_MIXEDFD
3+
4+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify=no-diag
5+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIV_CC
6+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIV_RC
7+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVASSIGN
8+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDFD
9+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDFD2
10+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDID
11+
// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVASSIGN_MIXEDFD
12+
13+
_Complex double div_ccf(_Complex float a, _Complex float b) {
14+
return a / b;
15+
}
16+
17+
_Complex double div_cr(_Complex double a, double b) {
18+
return a / b;
19+
}
20+
21+
_Complex double div_cr_mixed1(_Complex double a, float b) {
22+
return a / b;
23+
}
24+
25+
_Complex double div_cr_mixed2(_Complex float a, double b) {
26+
return a / b;
27+
}
28+
29+
_Complex double div_rr(double a, double b) {
30+
return a / b;
31+
}
32+
33+
_Complex int div_ii(_Complex int a, _Complex int b) {
34+
return a / b;
35+
}
36+
37+
struct UserT {
38+
friend UserT operator/(UserT, _Complex double);
39+
friend UserT operator/(_Complex double, UserT);
40+
};
41+
42+
UserT div_uc(UserT a, _Complex double b) {
43+
return a / b;
44+
}
45+
46+
UserT div_cu(_Complex double a, UserT b) {
47+
return a / b;
48+
}
49+
50+
#ifdef DIV_CC
51+
_Complex double div_cc(_Complex double a, const _Complex double b) {
52+
return a / b; // #1
53+
}
54+
#endif // DIV_CC
55+
56+
#ifdef DIV_RC
57+
_Complex double div_rc(double a, _Complex float b) {
58+
return a / b; // #1
59+
}
60+
#endif // DIV_RC
61+
62+
#ifdef DIVASSIGN
63+
_Complex double divassign(_Complex double a, _Complex double b) {
64+
return a /= b; // #1
65+
}
66+
#endif // DIVASSIGN
67+
68+
#ifdef DIVMIXEDFD
69+
_Complex double divmixedfd(_Complex float a, _Complex double b) {
70+
return a / b; // #1
71+
}
72+
#endif // DIVMIXEDFD
73+
74+
#ifdef DIVMIXEDFD2
75+
_Complex double divmixedfd2(_Complex double a, _Complex float b) {
76+
return a / b; // #1
77+
}
78+
#endif // DIVMIXEDFD2
79+
80+
#ifdef DIVMIXEDID
81+
_Complex double divmixedid(_Complex int a, _Complex double b) {
82+
return a / b; // #1
83+
}
84+
#endif // DIVMIXEDID
85+
86+
#ifdef DIVASSIGN_MIXEDFD
87+
_Complex double divassign_mixedfd(_Complex float a, _Complex double b) {
88+
return a /= b; // #1
89+
}
90+
#endif // DIVMIXEDFD
91+
92+
// no-diag-no-diagnostics
93+
// expected-warning@#1 {{excess precision is requested but the target does not support excess precision which may result in observable differences in complex division behavior}}

0 commit comments

Comments
 (0)