Skip to content

Commit

Permalink
[clang] use getCommonSugar in an assortment of places
Browse files Browse the repository at this point in the history
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 <mizvekov@gmail.com>

Differential Revision: https://reviews.llvm.org/D111509
  • Loading branch information
mizvekov committed Sep 16, 2022
1 parent b430980 commit aff1f63
Show file tree
Hide file tree
Showing 23 changed files with 222 additions and 159 deletions.
Expand Up @@ -330,7 +330,7 @@ TEST_F(ExtractVariableTest, Test) {
void bar() {
int (*placeholder)(int) = foo('c'); (void)placeholder;
})cpp"},
// Arithmetic on typedef types yields plain integer types
// Arithmetic on typedef types preserves typedef types
{R"cpp(typedef long NSInteger;
void varDecl() {
NSInteger a = 2 * 5;
Expand All @@ -339,7 +339,7 @@ TEST_F(ExtractVariableTest, Test) {
R"cpp(typedef long NSInteger;
void varDecl() {
NSInteger a = 2 * 5;
long placeholder = a * 7; NSInteger b = placeholder + 3;
NSInteger placeholder = a * 7; NSInteger b = placeholder + 3;
})cpp"},
};
for (const auto &IO : InputOutputs) {
Expand Down
Expand Up @@ -42,7 +42,7 @@ void narrowing_size_method() {
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.

i = j + v.size();
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
// 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]
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
}

Expand All @@ -51,7 +51,7 @@ void narrowing_size_method_binary_expr() {
int j;
vector v;
i = j + v.size();
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:7: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
// 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]
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
}

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

i += j + v.size();
// CHECK-MESSAGES-DEFAULT: :[[@LINE-1]]:8: warning: narrowing conversion from 'long long' to signed type 'int' is implementation-defined [cppcoreguidelines-narrowing-conversions]
// 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]
// IGNORED: Warning is disabled with IgnoreConversionFromTypes=global_size_t.
}

Expand Down
167 changes: 84 additions & 83 deletions clang/lib/Sema/SemaExpr.cpp
Expand Up @@ -1088,7 +1088,7 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
if (IntTy->isComplexType() || IntTy->isRealFloatingType()) return true;
if (SkipCast) return false;
if (IntTy->isIntegerType()) {
QualType fpTy = cast<ComplexType>(ComplexTy)->getElementType();
QualType fpTy = ComplexTy->castAs<ComplexType>()->getElementType();
IntExpr = S.ImpCastExprToType(IntExpr.get(), fpTy, CK_IntegralToFloating);
IntExpr = S.ImpCastExprToType(IntExpr.get(), ComplexTy,
CK_FloatingRealToComplex);
Expand All @@ -1100,60 +1100,59 @@ static bool handleIntegerToComplexFloatConversion(Sema &S, ExprResult &IntExpr,
return false;
}

// This handles complex/complex, complex/float, or float/complex.
// When both operands are complex, the shorter operand is converted to the
// type of the longer, and that is the type of the result. This corresponds
// to what is done when combining two real floating-point operands.
// The fun begins when size promotion occur across type domains.
// From H&S 6.3.4: When one operand is complex and the other is a real
// floating-point type, the less precise type is converted, within it's
// real or complex domain, to the precision of the other type. For example,
// when combining a "long double" with a "double _Complex", the
// "double _Complex" is promoted to "long double _Complex".
static QualType handleComplexFloatConversion(Sema &S, ExprResult &Shorter,
QualType ShorterType,
QualType LongerType,
bool PromotePrecision) {
bool LongerIsComplex = isa<ComplexType>(LongerType.getCanonicalType());
QualType Result =
LongerIsComplex ? LongerType : S.Context.getComplexType(LongerType);

if (PromotePrecision) {
if (isa<ComplexType>(ShorterType.getCanonicalType())) {
Shorter =
S.ImpCastExprToType(Shorter.get(), Result, CK_FloatingComplexCast);
} else {
if (LongerIsComplex)
LongerType = LongerType->castAs<ComplexType>()->getElementType();
Shorter = S.ImpCastExprToType(Shorter.get(), LongerType, CK_FloatingCast);
}
}
return Result;
}

/// Handle arithmetic conversion with complex types. Helper function of
/// UsualArithmeticConversions()
static QualType handleComplexFloatConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
QualType RHSType,
bool IsCompAssign) {
static QualType handleComplexConversion(Sema &S, ExprResult &LHS,
ExprResult &RHS, QualType LHSType,
QualType RHSType, bool IsCompAssign) {
// if we have an integer operand, the result is the complex type.
if (!handleIntegerToComplexFloatConversion(S, RHS, LHS, RHSType, LHSType,
/*skipCast*/false))
/*SkipCast=*/false))
return LHSType;
if (!handleIntegerToComplexFloatConversion(S, LHS, RHS, LHSType, RHSType,
/*skipCast*/IsCompAssign))
/*SkipCast=*/IsCompAssign))
return RHSType;

// This handles complex/complex, complex/float, or float/complex.
// When both operands are complex, the shorter operand is converted to the
// type of the longer, and that is the type of the result. This corresponds
// to what is done when combining two real floating-point operands.
// The fun begins when size promotion occur across type domains.
// From H&S 6.3.4: When one operand is complex and the other is a real
// floating-point type, the less precise type is converted, within it's
// real or complex domain, to the precision of the other type. For example,
// when combining a "long double" with a "double _Complex", the
// "double _Complex" is promoted to "long double _Complex".

// Compute the rank of the two types, regardless of whether they are complex.
int Order = S.Context.getFloatingTypeOrder(LHSType, RHSType);

auto *LHSComplexType = dyn_cast<ComplexType>(LHSType);
auto *RHSComplexType = dyn_cast<ComplexType>(RHSType);
QualType LHSElementType =
LHSComplexType ? LHSComplexType->getElementType() : LHSType;
QualType RHSElementType =
RHSComplexType ? RHSComplexType->getElementType() : RHSType;

QualType ResultType = S.Context.getComplexType(LHSElementType);
if (Order < 0) {
if (Order < 0)
// Promote the precision of the LHS if not an assignment.
ResultType = S.Context.getComplexType(RHSElementType);
if (!IsCompAssign) {
if (LHSComplexType)
LHS =
S.ImpCastExprToType(LHS.get(), ResultType, CK_FloatingComplexCast);
else
LHS = S.ImpCastExprToType(LHS.get(), RHSElementType, CK_FloatingCast);
}
} else if (Order > 0) {
// Promote the precision of the RHS.
if (RHSComplexType)
RHS = S.ImpCastExprToType(RHS.get(), ResultType, CK_FloatingComplexCast);
else
RHS = S.ImpCastExprToType(RHS.get(), LHSElementType, CK_FloatingCast);
}
return ResultType;
return handleComplexFloatConversion(S, LHS, LHSType, RHSType,
/*PromotePrecision=*/!IsCompAssign);
// Promote the precision of the RHS unless it is already the same as the LHS.
return handleComplexFloatConversion(S, RHS, RHSType, LHSType,
/*PromotePrecision=*/Order > 0);
}

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

// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType LHSType =
Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
QualType RHSType =
Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
QualType LHSType = LHS.get()->getType().getUnqualifiedType();
QualType RHSType = RHS.get()->getType().getUnqualifiedType();

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

// If both types are identical, no conversion is needed.
if (LHSType == RHSType)
return LHSType;
if (Context.hasSameType(LHSType, RHSType))
return Context.getCommonSugaredType(LHSType, RHSType);

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

// If both types are identical, no conversion is needed.
if (LHSType == RHSType)
return LHSType;
if (Context.hasSameType(LHSType, RHSType))
return Context.getCommonSugaredType(LHSType, RHSType);

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

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

// Handle complex types first (C99 6.3.1.8p1).
if (LHSType->isComplexType() || RHSType->isComplexType())
return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
ACK == ACK_CompAssign);
return handleComplexConversion(*this, LHS, RHS, LHSType, RHSType,
ACK == ACK_CompAssign);

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

/// Handle when one or both operands are void type.
static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
ExprResult &RHS) {
Expr *LHSExpr = LHS.get();
Expr *RHSExpr = RHS.get();

if (!LHSExpr->getType()->isVoidType())
S.Diag(RHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
<< RHSExpr->getSourceRange();
if (!RHSExpr->getType()->isVoidType())
S.Diag(LHSExpr->getBeginLoc(), diag::ext_typecheck_cond_one_void)
<< LHSExpr->getSourceRange();
LHS = S.ImpCastExprToType(LHS.get(), S.Context.VoidTy, CK_ToVoid);
RHS = S.ImpCastExprToType(RHS.get(), S.Context.VoidTy, CK_ToVoid);
return S.Context.VoidTy;
}

/// Return false if the NullExpr can be promoted to PointerTy,
/// true otherwise.
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
Expand All @@ -8198,7 +8178,7 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,

if (S.Context.hasSameType(LHSTy, RHSTy)) {
// Two identical pointers types are always compatible.
return LHSTy;
return S.Context.getCommonSugaredType(LHSTy, RHSTy);
}

QualType lhptee, rhptee;
Expand Down Expand Up @@ -8700,7 +8680,7 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,

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

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

// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
return checkConditionalVoidType(*this, LHS, RHS);
QualType ResTy;
if (LHSTy->isVoidType() && RHSTy->isVoidType()) {
ResTy = Context.getCommonSugaredType(LHSTy, RHSTy);
} else if (RHSTy->isVoidType()) {
ResTy = RHSTy;
Diag(RHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
<< RHS.get()->getSourceRange();
} else {
ResTy = LHSTy;
Diag(LHS.get()->getBeginLoc(), diag::ext_typecheck_cond_one_void)
<< LHS.get()->getSourceRange();
}
LHS = ImpCastExprToType(LHS.get(), ResTy, CK_ToVoid);
RHS = ImpCastExprToType(RHS.get(), ResTy, CK_ToVoid);
return ResTy;
}

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

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

// If the vector types are identical, return.
if (Context.hasSameType(LHSType, RHSType))
return LHSType;
return Context.getCommonSugaredType(LHSType, RHSType);

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

if (Context.hasSameType(LHSType, RHSType))
return LHSType;
return Context.getCommonSugaredType(LHSType, RHSType);

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

if (!Context.hasSameType(LHSMatType->getElementType(),
RHSMatType->getElementType()))
if (Context.hasSameType(LHSMatType, RHSMatType))
return Context.getCommonSugaredType(
LHS.get()->getType().getUnqualifiedType(),
RHS.get()->getType().getUnqualifiedType());

QualType LHSELTy = LHSMatType->getElementType(),
RHSELTy = RHSMatType->getElementType();
if (!Context.hasSameType(LHSELTy, RHSELTy))
return InvalidOperands(Loc, LHS, RHS);

return Context.getConstantMatrixType(LHSMatType->getElementType(),
LHSMatType->getNumRows(),
RHSMatType->getNumColumns());
return Context.getConstantMatrixType(
Context.getCommonSugaredType(LHSELTy, RHSELTy),
LHSMatType->getNumRows(), RHSMatType->getNumColumns());
}
return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign);
}
Expand Down

0 comments on commit aff1f63

Please sign in to comment.