Author: Mészáros Gergely Date: 2025-04-16T08:02:42+02:00 New Revision: f3c77445791b510858561cb424ffa1cd7513250b
URL: https://github.com/llvm/llvm-project/commit/f3c77445791b510858561cb424ffa1cd7513250b DIFF: https://github.com/llvm/llvm-project/commit/f3c77445791b510858561cb424ffa1cd7513250b.diff LOG: [Clang][Sema] Fix -Whigher-precision-for-complex-division (#131477) - Fix false positive when divisor is a real number. - Fix false negative when divident is real, but divisor is complex. - Fix false negative when due to promotion the division is performed in higher precision than the divident. - Fix false negative in divide and assign (`a /= b`). Fixes: #131127 --------- Co-authored-by: Zahira Ammarguellat <zahira.ammarguel...@intel.com> Added: clang/test/Sema/complex-div-warn-higher-precision.cpp Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaExpr.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 84ad253c1ec4f..5af4c08f64cd8 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -371,6 +371,14 @@ Improvements to Clang's diagnostics - An error is now emitted when a ``musttail`` call is made to a function marked with the ``not_tail_called`` attribute. (#GH133509). +- ``-Whigher-precisision-for-complex-divison`` warns when: + + - The divisor is complex. + - When the complex division happens in a higher precision type due to arithmetic promotion. + - When using the divide and assign operator (``/=``). + + Fixes #GH131127 + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c65b4eadf9c67..6830bb5c01c7d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -10602,6 +10602,45 @@ static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); } +static void DetectPrecisionLossInComplexDivision(Sema &S, QualType DivisorTy, + SourceLocation OpLoc) { + // If the divisor is real, then this is real/real or complex/real division. + // Either way there can be no precision loss. + auto *CT = DivisorTy->getAs<ComplexType>(); + if (!CT) + return; + + QualType ElementType = CT->getElementType(); + bool IsComplexRangePromoted = S.getLangOpts().getComplexRange() == + LangOptions::ComplexRangeKind::CX_Promoted; + if (!ElementType->isFloatingType() || !IsComplexRangePromoted) + return; + + ASTContext &Ctx = S.getASTContext(); + QualType HigherElementType = Ctx.GetHigherPrecisionFPType(ElementType); + const llvm::fltSemantics &ElementTypeSemantics = + Ctx.getFloatTypeSemantics(ElementType); + const llvm::fltSemantics &HigherElementTypeSemantics = + Ctx.getFloatTypeSemantics(HigherElementType); + + if ((llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 > + llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) || + (HigherElementType == Ctx.LongDoubleTy && + !Ctx.getTargetInfo().hasLongDoubleType())) { + // Retain the location of the first use of higher precision type. + if (!S.LocationOfExcessPrecisionNotSatisfied.isValid()) + S.LocationOfExcessPrecisionNotSatisfied = OpLoc; + for (auto &[Type, Num] : S.ExcessPrecisionNotSatisfied) { + if (Type == HigherElementType) { + Num++; + return; + } + } + S.ExcessPrecisionNotSatisfied.push_back(std::make_pair( + HigherElementType, S.ExcessPrecisionNotSatisfied.size())); + } +} + static void DiagnoseDivisionSizeofPointerOrArray(Sema &S, Expr *LHS, Expr *RHS, SourceLocation Loc) { const auto *LUE = dyn_cast<UnaryExprOrTypeTraitExpr>(LHS); @@ -10696,6 +10735,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, if (compType.isNull() || !compType->isArithmeticType()) return InvalidOperands(Loc, LHS, RHS); if (IsDiv) { + DetectPrecisionLossInComplexDivision(*this, RHS.get()->getType(), Loc); DiagnoseBadDivideOrRemainderValues(*this, LHS, RHS, Loc, IsDiv); DiagnoseDivisionSizeofPointerOrArray(*this, LHS.get(), RHS.get(), Loc); } @@ -15347,39 +15387,6 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, DiagnoseShiftCompare(Self, OpLoc, LHSExpr, RHSExpr); } -static void DetectPrecisionLossInComplexDivision(Sema &S, SourceLocation OpLoc, - Expr *Operand) { - if (auto *CT = Operand->getType()->getAs<ComplexType>()) { - QualType ElementType = CT->getElementType(); - bool IsComplexRangePromoted = S.getLangOpts().getComplexRange() == - LangOptions::ComplexRangeKind::CX_Promoted; - if (ElementType->isFloatingType() && IsComplexRangePromoted) { - ASTContext &Ctx = S.getASTContext(); - QualType HigherElementType = Ctx.GetHigherPrecisionFPType(ElementType); - const llvm::fltSemantics &ElementTypeSemantics = - Ctx.getFloatTypeSemantics(ElementType); - const llvm::fltSemantics &HigherElementTypeSemantics = - Ctx.getFloatTypeSemantics(HigherElementType); - if ((llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 > - llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) || - (HigherElementType == Ctx.LongDoubleTy && - !Ctx.getTargetInfo().hasLongDoubleType())) { - // Retain the location of the first use of higher precision type. - if (!S.LocationOfExcessPrecisionNotSatisfied.isValid()) - S.LocationOfExcessPrecisionNotSatisfied = OpLoc; - for (auto &[Type, Num] : S.ExcessPrecisionNotSatisfied) { - if (Type == HigherElementType) { - Num++; - return; - } - } - S.ExcessPrecisionNotSatisfied.push_back(std::make_pair( - HigherElementType, S.ExcessPrecisionNotSatisfied.size())); - } - } - } -} - ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr) { @@ -15390,11 +15397,6 @@ ExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" DiagnoseBinOpPrecedence(*this, Opc, TokLoc, LHSExpr, RHSExpr); - // Emit warnings if the requested higher precision type equal to the current - // type precision. - if (Kind == tok::TokenKind::slash) - DetectPrecisionLossInComplexDivision(*this, TokLoc, LHSExpr); - BuiltinCountedByRefKind K = BinaryOperator::isAssignmentOp(Opc) ? AssignmentKind : BinaryExprKind; diff --git a/clang/test/Sema/complex-div-warn-higher-precision.cpp b/clang/test/Sema/complex-div-warn-higher-precision.cpp new file mode 100644 index 0000000000000..a7cc2fbc7ed21 --- /dev/null +++ b/clang/test/Sema/complex-div-warn-higher-precision.cpp @@ -0,0 +1,93 @@ +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-linux -verify=no-diag \ +// RUN: -DDIV_CC -DDIV_RC -DDIVASSIGN -DDIVMIXEDFD -DDIVMIXEDFD2 -DDIVMIXEDID -DDIVASSIGN_MIXEDFD + +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify=no-diag +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIV_CC +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIV_RC +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVASSIGN +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDFD +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDFD2 +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVMIXEDID +// RUN: %clang_cc1 %s -complex-range=promoted -fsyntax-only -triple x86_64-unknown-windows -verify -DDIVASSIGN_MIXEDFD + +_Complex double div_ccf(_Complex float a, _Complex float b) { + return a / b; +} + +_Complex double div_cr(_Complex double a, double b) { + return a / b; +} + +_Complex double div_cr_mixed1(_Complex double a, float b) { + return a / b; +} + +_Complex double div_cr_mixed2(_Complex float a, double b) { + return a / b; +} + +_Complex double div_rr(double a, double b) { + return a / b; +} + +_Complex int div_ii(_Complex int a, _Complex int b) { + return a / b; +} + +struct UserT { + friend UserT operator/(UserT, _Complex double); + friend UserT operator/(_Complex double, UserT); +}; + +UserT div_uc(UserT a, _Complex double b) { + return a / b; +} + +UserT div_cu(_Complex double a, UserT b) { + return a / b; +} + +#ifdef DIV_CC +_Complex double div_cc(_Complex double a, const _Complex double b) { + return a / b; // #1 +} +#endif // DIV_CC + +#ifdef DIV_RC +_Complex double div_rc(double a, _Complex float b) { + return a / b; // #1 +} +#endif // DIV_RC + +#ifdef DIVASSIGN +_Complex double divassign(_Complex double a, _Complex double b) { + return a /= b; // #1 +} +#endif // DIVASSIGN + +#ifdef DIVMIXEDFD +_Complex double divmixedfd(_Complex float a, _Complex double b) { + return a / b; // #1 +} +#endif // DIVMIXEDFD + +#ifdef DIVMIXEDFD2 +_Complex double divmixedfd2(_Complex double a, _Complex float b) { + return a / b; // #1 +} +#endif // DIVMIXEDFD2 + +#ifdef DIVMIXEDID +_Complex double divmixedid(_Complex int a, _Complex double b) { + return a / b; // #1 +} +#endif // DIVMIXEDID + +#ifdef DIVASSIGN_MIXEDFD +_Complex double divassign_mixedfd(_Complex float a, _Complex double b) { + return a /= b; // #1 +} +#endif // DIVMIXEDFD + +// no-diag-no-diagnostics +// expected-warning@#1 {{excess precision is requested but the target does not support excess precision which may result in observable diff erences in complex division behavior}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits