Skip to content

Commit aff1f63

Browse files
committed
[clang] use getCommonSugar in an assortment of places
For this patch, a simple search was performed for patterns where there are two types (usually an LHS and an RHS) which are structurally the same, and there is some result type which is resolved as either one of them (typically LHS for consistency). We change those cases to resolve as the common sugared type between those two, utilizing the new infrastructure created for this purpose. Signed-off-by: Matheus Izvekov <[email protected]> Differential Revision: https://reviews.llvm.org/D111509
1 parent b430980 commit aff1f63

File tree

23 files changed

+222
-159
lines changed

23 files changed

+222
-159
lines changed

clang-tools-extra/clangd/unittests/tweaks/ExtractVariableTests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ TEST_F(ExtractVariableTest, Test) {
330330
void bar() {
331331
int (*placeholder)(int) = foo('c'); (void)placeholder;
332332
})cpp"},
333-
// Arithmetic on typedef types yields plain integer types
333+
// Arithmetic on typedef types preserves typedef types
334334
{R"cpp(typedef long NSInteger;
335335
void varDecl() {
336336
NSInteger a = 2 * 5;
@@ -339,7 +339,7 @@ TEST_F(ExtractVariableTest, Test) {
339339
R"cpp(typedef long NSInteger;
340340
void varDecl() {
341341
NSInteger a = 2 * 5;
342-
long placeholder = a * 7; NSInteger b = placeholder + 3;
342+
NSInteger placeholder = a * 7; NSInteger b = placeholder + 3;
343343
})cpp"},
344344
};
345345
for (const auto &IO : InputOutputs) {

clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/narrowing-conversions-ignoreconversionfromtypes-option.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ void narrowing_size_method() {
4242
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
4343

4444
i = j + v.size();
45-
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
45+
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'global_size_t' (aka 'long long') to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
4646
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
4747
}
4848

@@ -51,7 +51,7 @@ void narrowing_size_method_binary_expr() {
5151
int j;
5252
vector v;
5353
i = j + v.size();
54-
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
54+
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'global_size_t' (aka 'long long') to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
5555
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
5656
}
5757

@@ -63,7 +63,7 @@ void narrowing_size_method_binary_op() {
6363
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
6464

6565
i += j + v.size();
66-
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
66+
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: narrowing conversion from 'global_size_t' (aka 'long long') to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
6767
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
6868
}
6969

clang/lib/Sema/SemaExpr.cpp

Lines changed: 84 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
10881088
if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
10891089
if (SkipCast) return false;
10901090
if (IntTy->isIntegerType()) {
1091-
QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
1091+
QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
10921092
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
10931093
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
10941094
CK_FloatingRealToComplex);
@@ -1100,60 +1100,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
11001100
return false;
11011101
}
11021102

1103+
// This handles complex/complex, complex/float, or float/complex.
1104+
// When both operands are complex, the shorter operand is converted to the
1105+
// type of the longer, and that is the type of the result. This corresponds
1106+
// to what is done when combining two real floating-point operands.
1107+
// The fun begins when size promotion occur across type domains.
1108+
// From H&S 6.3.4: When one operand is complex and the other is a real
1109+
// floating-point type, the less precise type is converted, within it's
1110+
// real or complex domain, to the precision of the other type. For example,
1111+
// when combining a "long double" with a "double _Complex", the
1112+
// "double _Complex" is promoted to "long double _Complex".
1113+
static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter,
1114+
QualType ShorterType,
1115+
QualType LongerType,
1116+
bool PromotePrecision) {
1117+
bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType());
1118+
QualType Result =
1119+
LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType);
1120+
1121+
if (PromotePrecision) {
1122+
if (isa<ComplexType>(ShorterType.getCanonicalType())) {
1123+
Shorter =
1124+
S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast);
1125+
} else {
1126+
if (LongerIsComplex)
1127+
LongerType = LongerType->castAs<ComplexType>()->getElementType();
1128+
Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast);
1129+
}
1130+
}
1131+
return Result;
1132+
}
1133+
11031134
/// Handle arithmetic conversion with complex types. Helper function of
11041135
/// UsualArithmeticConversions()
1105-
static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
1106-
ExprResult &RHS, QualType LHSType,
1107-
QualType RHSType,
1108-
bool IsCompAssign) {
1136+
static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
1137+
ExprResult &RHS, QualType LHSType,
1138+
QualType RHSType, bool IsCompAssign) {
11091139
// if we have an integer operand, the result is the complex type.
11101140
if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
1111-
/*skipCast*/false))
1141+
/*SkipCast=*/false))
11121142
return LHSType;
11131143
if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
1114-
/*skipCast*/IsCompAssign))
1144+
/*SkipCast=*/IsCompAssign))
11151145
return RHSType;
11161146

1117-
// This handles complex/complex, complex/float, or float/complex.
1118-
// When both operands are complex, the shorter operand is converted to the
1119-
// type of the longer, and that is the type of the result. This corresponds
1120-
// to what is done when combining two real floating-point operands.
1121-
// The fun begins when size promotion occur across type domains.
1122-
// From H&S 6.3.4: When one operand is complex and the other is a real
1123-
// floating-point type, the less precise type is converted, within it's
1124-
// real or complex domain, to the precision of the other type. For example,
1125-
// when combining a "long double" with a "double _Complex", the
1126-
// "double _Complex" is promoted to "long double _Complex".
1127-
11281147
// Compute the rank of the two types, regardless of whether they are complex.
11291148
int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);
1130-
1131-
auto *LHSComplexType = dyn_cast<ComplexType>(LHSType);
1132-
auto *RHSComplexType = dyn_cast<ComplexType>(RHSType);
1133-
QualType LHSElementType =
1134-
LHSComplexType ? LHSComplexType->getElementType() : LHSType;
1135-
QualType RHSElementType =
1136-
RHSComplexType ? RHSComplexType->getElementType() : RHSType;
1137-
1138-
QualType ResultType = S.Context.getComplexType(LHSElementType);
1139-
if (Order < 0) {
1149+
if (Order < 0)
11401150
// Promote the precision of the LHS if not an assignment.
1141-
ResultType = S.Context.getComplexType(RHSElementType);
1142-
if (!IsCompAssign) {
1143-
if (LHSComplexType)
1144-
LHS =
1145-
S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast);
1146-
else
1147-
LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast);
1148-
}
1149-
} else if (Order > 0) {
1150-
// Promote the precision of the RHS.
1151-
if (RHSComplexType)
1152-
RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast);
1153-
else
1154-
RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast);
1155-
}
1156-
return ResultType;
1151+
return handleComplexFloatConversion(S, LHS, LHSType, RHSType,
1152+
/*PromotePrecision=*/!IsCompAssign);
1153+
// Promote the precision of the RHS unless it is already the same as the LHS.
1154+
return handleComplexFloatConversion(S, RHS, RHSType, LHSType,
1155+
/*PromotePrecision=*/Order > 0);
11571156
}
11581157

11591158
/// Handle arithmetic conversion from integer to float. Helper function
@@ -1539,18 +1538,16 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
15391538

15401539
// For conversion purposes, we ignore any qualifiers.
15411540
// For example, "const float" and "float" are equivalent.
1542-
QualType LHSType =
1543-
Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
1544-
QualType RHSType =
1545-
Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
1541+
QualType LHSType = LHS.get()->getType().getUnqualifiedType();
1542+
QualType RHSType = RHS.get()->getType().getUnqualifiedType();
15461543

15471544
// For conversion purposes, we ignore any atomic qualifier on the LHS.
15481545
if (const AtomicType *AtomicLHS = LHSType->getAs<AtomicType>())
15491546
LHSType = AtomicLHS->getValueType();
15501547

15511548
// If both types are identical, no conversion is needed.
1552-
if (LHSType == RHSType)
1553-
return LHSType;
1549+
if (Context.hasSameType(LHSType, RHSType))
1550+
return Context.getCommonSugaredType(LHSType, RHSType);
15541551

15551552
// If either side is a non-arithmetic type (e.g. a pointer), we are done.
15561553
// The caller can deal with this (e.g. pointer + int).
@@ -1568,8 +1565,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
15681565
LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast);
15691566

15701567
// If both types are identical, no conversion is needed.
1571-
if (LHSType == RHSType)
1572-
return LHSType;
1568+
if (Context.hasSameType(LHSType, RHSType))
1569+
return Context.getCommonSugaredType(LHSType, RHSType);
15731570

15741571
// At this point, we have two different arithmetic types.
15751572

@@ -1580,8 +1577,8 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
15801577

15811578
// Handle complex types first (C99 6.3.1.8p1).
15821579
if (LHSType->isComplexType() || RHSType->isComplexType())
1583-
return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
1584-
ACK == ACK_CompAssign);
1580+
return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType,
1581+
ACK == ACK_CompAssign);
15851582

15861583
// Now handle "real" floating types (i.e. float, double, long double).
15871584
if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType())
@@ -8158,23 +8155,6 @@ static bool checkCondition(Sema &S, Expr *Cond, SourceLocation QuestionLoc) {
81588155
return true;
81598156
}
81608157

8161-
/// Handle when one or both operands are void type.
8162-
static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
8163-
ExprResult &RHS) {
8164-
Expr *LHSExpr = LHS.get();
8165-
Expr *RHSExpr = RHS.get();
8166-
8167-
if (!LHSExpr->getType()->isVoidType())
8168-
S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
8169-
<< RHSExpr->getSourceRange();
8170-
if (!RHSExpr->getType()->isVoidType())
8171-
S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
8172-
<< LHSExpr->getSourceRange();
8173-
LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid);
8174-
RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid);
8175-
return S.Context.VoidTy;
8176-
}
8177-
81788158
/// Return false if the NullExpr can be promoted to PointerTy,
81798159
/// true otherwise.
81808160
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
@@ -8198,7 +8178,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
81988178

81998179
if (S.Context.hasSameType(LHSTy, RHSTy)) {
82008180
// Two identical pointers types are always compatible.
8201-
return LHSTy;
8181+
return S.Context.getCommonSugaredType(LHSTy, RHSTy);
82028182
}
82038183

82048184
QualType lhptee, rhptee;
@@ -8700,7 +8680,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
87008680

87018681
// And if they're both bfloat (which isn't arithmetic), that's fine too.
87028682
if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) {
8703-
return LHSTy;
8683+
return Context.getCommonSugaredType(LHSTy, RHSTy);
87048684
}
87058685

87068686
// If both operands are the same structure or union type, the result is that
@@ -8710,14 +8690,29 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
87108690
if (LHSRT->getDecl() == RHSRT->getDecl())
87118691
// "If both the operands have structure or union type, the result has
87128692
// that type." This implies that CV qualifiers are dropped.
8713-
return LHSTy.getUnqualifiedType();
8693+
return Context.getCommonSugaredType(LHSTy.getUnqualifiedType(),
8694+
RHSTy.getUnqualifiedType());
87148695
// FIXME: Type of conditional expression must be complete in C mode.
87158696
}
87168697

87178698
// C99 6.5.15p5: "If both operands have void type, the result has void type."
87188699
// The following || allows only one side to be void (a GCC-ism).
87198700
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
8720-
return checkConditionalVoidType(*this, LHS, RHS);
8701+
QualType ResTy;
8702+
if (LHSTy->isVoidType() && RHSTy->isVoidType()) {
8703+
ResTy = Context.getCommonSugaredType(LHSTy, RHSTy);
8704+
} else if (RHSTy->isVoidType()) {
8705+
ResTy = RHSTy;
8706+
Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
8707+
<< RHS.get()->getSourceRange();
8708+
} else {
8709+
ResTy = LHSTy;
8710+
Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
8711+
<< LHS.get()->getSourceRange();
8712+
}
8713+
LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid);
8714+
RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid);
8715+
return ResTy;
87218716
}
87228717

87238718
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
@@ -8756,7 +8751,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
87568751
// Allow ?: operations in which both operands have the same
87578752
// built-in sizeless type.
87588753
if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy))
8759-
return LHSTy;
8754+
return Context.getCommonSugaredType(LHSTy, RHSTy);
87608755

87618756
// Emit a better diagnostic if one of the expressions is a null pointer
87628757
// constant and the other is not a pointer type. In this case, the user most
@@ -10427,7 +10422,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
1042710422

1042810423
// If the vector types are identical, return.
1042910424
if (Context.hasSameType(LHSType, RHSType))
10430-
return LHSType;
10425+
return Context.getCommonSugaredType(LHSType, RHSType);
1043110426

1043210427
// If we have compatible AltiVec and GCC vector types, use the AltiVec type.
1043310428
if (LHSVecType && RHSVecType &&
@@ -13145,7 +13140,7 @@ QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS,
1314513140
assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix");
1314613141

1314713142
if (Context.hasSameType(LHSType, RHSType))
13148-
return LHSType;
13143+
return Context.getCommonSugaredType(LHSType, RHSType);
1314913144

1315013145
// Type conversion may change LHS/RHS. Keep copies to the original results, in
1315113146
// case we have to return InvalidOperands.
@@ -13189,13 +13184,19 @@ QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS,
1318913184
if (LHSMatType->getNumColumns() != RHSMatType->getNumRows())
1319013185
return InvalidOperands(Loc, LHS, RHS);
1319113186

13192-
if (!Context.hasSameType(LHSMatType->getElementType(),
13193-
RHSMatType->getElementType()))
13187+
if (Context.hasSameType(LHSMatType, RHSMatType))
13188+
return Context.getCommonSugaredType(
13189+
LHS.get()->getType().getUnqualifiedType(),
13190+
RHS.get()->getType().getUnqualifiedType());
13191+
13192+
QualType LHSELTy = LHSMatType->getElementType(),
13193+
RHSELTy = RHSMatType->getElementType();
13194+
if (!Context.hasSameType(LHSELTy, RHSELTy))
1319413195
return InvalidOperands(Loc, LHS, RHS);
1319513196

13196-
return Context.getConstantMatrixType(LHSMatType->getElementType(),
13197-
LHSMatType->getNumRows(),
13198-
RHSMatType->getNumColumns());
13197+
return Context.getConstantMatrixType(
13198+
Context.getCommonSugaredType(LHSELTy, RHSELTy),
13199+
LHSMatType->getNumRows(), RHSMatType->getNumColumns());
1319913200
}
1320013201
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
1320113202
}

0 commit comments

Comments
 (0)