Skip to content

Commit eace867

Browse files
committed
wip: prevent any type mixing
1 parent 769bd0e commit eace867

File tree

7 files changed

+103
-183
lines changed

7 files changed

+103
-183
lines changed

clang/include/clang/Sema/Sema.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2323,7 +2323,8 @@ class Sema final : public SemaBase {
23232323
const FunctionProtoType *Proto);
23242324

23252325
/// \param FPOnly restricts the arguments to floating-point types.
2326-
bool BuiltinVectorMath(CallExpr *TheCall, QualType &Res, bool FPOnly = false);
2326+
std::optional<QualType> BuiltinVectorMath(CallExpr *TheCall,
2327+
bool FPOnly = false);
23272328
bool BuiltinVectorToScalarMath(CallExpr *TheCall);
23282329

23292330
void checkLifetimeCaptureBy(FunctionDecl *FDecl, bool IsMemberFunction,
@@ -7557,6 +7558,11 @@ class Sema final : public SemaBase {
75577558
ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT,
75587559
FunctionDecl *FDecl);
75597560

7561+
// Check that the usual arithmetic conversions can be performed on this pair
7562+
// of expressions that might be of enumeration type.
7563+
void checkEnumArithmeticConversions(Expr *LHS, Expr *RHS, SourceLocation Loc,
7564+
Sema::ArithConvKind ACK);
7565+
75607566
// UsualArithmeticConversions - performs the UsualUnaryConversions on it's
75617567
// operands and then handles various conversions that are common to binary
75627568
// operators (C99 6.3.1.8). If both operands aren't arithmetic, this

clang/lib/Sema/SemaChecking.cpp

Lines changed: 49 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2765,44 +2765,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
27652765
// types only.
27662766
case Builtin::BI__builtin_elementwise_add_sat:
27672767
case Builtin::BI__builtin_elementwise_sub_sat: {
2768-
if (checkArgCount(TheCall, 2))
2769-
return ExprError();
2770-
ExprResult LHS = TheCall->getArg(0);
2771-
ExprResult RHS = TheCall->getArg(1);
2772-
QualType LHSType = LHS.get()->getType().getUnqualifiedType();
2773-
QualType RHSType = RHS.get()->getType().getUnqualifiedType();
2774-
// If both LHS/RHS are promotable integer types, do not perform the usual
2775-
// conversions - we must keep the saturating operation at the correct
2776-
// bitwidth.
2777-
if (Context.isPromotableIntegerType(LHSType) &&
2778-
Context.isPromotableIntegerType(RHSType)) {
2779-
// First, convert each argument to an r-value.
2780-
ExprResult ResLHS = DefaultFunctionArrayLvalueConversion(LHS.get());
2781-
if (ResLHS.isInvalid())
2782-
return ExprError();
2783-
LHS = ResLHS.get();
2784-
2785-
ExprResult ResRHS = DefaultFunctionArrayLvalueConversion(RHS.get());
2786-
if (ResRHS.isInvalid())
2787-
return ExprError();
2788-
RHS = ResRHS.get();
2789-
2790-
LHSType = LHS.get()->getType().getUnqualifiedType();
2791-
RHSType = RHS.get()->getType().getUnqualifiedType();
2792-
2793-
// If the two integer types are not of equal order, cast the smaller
2794-
// integer one to the larger one
2795-
if (int Order = Context.getIntegerTypeOrder(LHSType, RHSType); Order == 1)
2796-
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_IntegralCast);
2797-
else if (Order == -1)
2798-
LHS = ImpCastExprToType(LHS.get(), RHSType, CK_IntegralCast);
2799-
2800-
TheCall->setArg(0, LHS.get());
2801-
TheCall->setArg(1, RHS.get());
2802-
TheCall->setType(LHS.get()->getType().getUnqualifiedType());
2803-
break;
2804-
}
2805-
28062768
if (BuiltinElementwiseMath(TheCall))
28072769
return ExprError();
28082770

@@ -2828,28 +2790,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
28282790
break;
28292791
case Builtin::BI__builtin_elementwise_popcount:
28302792
case Builtin::BI__builtin_elementwise_bitreverse: {
2831-
if (checkArgCount(TheCall, 1))
2832-
return ExprError();
2833-
2834-
Expr *Arg = TheCall->getArg(0);
2835-
QualType ArgTy = Arg->getType();
2836-
2837-
// If the argument is a promotable integer type, do not perform the usual
2838-
// conversions - we must keep the operation at the correct bitwidth.
2839-
if (Context.isPromotableIntegerType(ArgTy)) {
2840-
// Convert the argument to an r-value - avoid the usual conversions.
2841-
ExprResult ResLHS = DefaultFunctionArrayLvalueConversion(Arg);
2842-
if (ResLHS.isInvalid())
2843-
return ExprError();
2844-
Arg = ResLHS.get();
2845-
TheCall->setArg(0, Arg);
2846-
TheCall->setType(Arg->getType());
2847-
break;
2848-
}
2849-
28502793
if (PrepareBuiltinElementwiseMathOneArgCall(TheCall))
28512794
return ExprError();
28522795

2796+
const Expr *Arg = TheCall->getArg(0);
2797+
QualType ArgTy = Arg->getType();
28532798
QualType EltTy = ArgTy;
28542799

28552800
if (auto *VecTy = EltTy->getAs<VectorType>())
@@ -14640,11 +14585,18 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) {
1464014585
_2, _3, _4));
1464114586
}
1464214587

14588+
static ExprResult UsualUnaryConversionsNoPromoteInt(Sema &S, Expr *E) {
14589+
// Don't promote integer types
14590+
if (QualType Ty = E->getType(); S.getASTContext().isPromotableIntegerType(Ty))
14591+
return S.DefaultFunctionArrayLvalueConversion(E);
14592+
return S.UsualUnaryConversions(E);
14593+
}
14594+
1464314595
bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1464414596
if (checkArgCount(TheCall, 1))
1464514597
return true;
1464614598

14647-
ExprResult A = UsualUnaryConversions(TheCall->getArg(0));
14599+
ExprResult A = UsualUnaryConversionsNoPromoteInt(*this, TheCall->getArg(0));
1464814600
if (A.isInvalid())
1464914601
return true;
1465014602

@@ -14659,57 +14611,63 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
1465914611
}
1466014612

1466114613
bool Sema::BuiltinElementwiseMath(CallExpr *TheCall, bool FPOnly) {
14662-
QualType Res;
14663-
if (BuiltinVectorMath(TheCall, Res, FPOnly))
14664-
return true;
14665-
TheCall->setType(Res);
14666-
return false;
14614+
if (auto Res = BuiltinVectorMath(TheCall, FPOnly); Res.has_value()) {
14615+
TheCall->setType(*Res);
14616+
return false;
14617+
}
14618+
return true;
1466714619
}
1466814620

1466914621
bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) {
14670-
QualType Res;
14671-
if (BuiltinVectorMath(TheCall, Res))
14622+
std::optional<QualType> Res = BuiltinVectorMath(TheCall);
14623+
if (!Res)
1467214624
return true;
1467314625

14674-
if (auto *VecTy0 = Res->getAs<VectorType>())
14626+
if (auto *VecTy0 = (*Res)->getAs<VectorType>())
1467514627
TheCall->setType(VecTy0->getElementType());
1467614628
else
14677-
TheCall->setType(Res);
14629+
TheCall->setType(*Res);
1467814630

1467914631
return false;
1468014632
}
1468114633

14682-
bool Sema::BuiltinVectorMath(CallExpr *TheCall, QualType &Res, bool FPOnly) {
14634+
std::optional<QualType> Sema::BuiltinVectorMath(CallExpr *TheCall,
14635+
bool FPOnly) {
1468314636
if (checkArgCount(TheCall, 2))
14684-
return true;
14637+
return std::nullopt;
1468514638

14686-
ExprResult A = TheCall->getArg(0);
14687-
ExprResult B = TheCall->getArg(1);
14688-
// Do standard promotions between the two arguments, returning their common
14689-
// type.
14690-
Res = UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison);
14691-
if (A.isInvalid() || B.isInvalid())
14692-
return true;
14639+
checkEnumArithmeticConversions(TheCall->getArg(0), TheCall->getArg(1),
14640+
TheCall->getExprLoc(), ACK_Comparison);
1469314641

14694-
QualType TyA = A.get()->getType();
14695-
QualType TyB = B.get()->getType();
14642+
Expr *Args[2];
14643+
for (int I = 0; I < 2; ++I) {
14644+
ExprResult Converted =
14645+
UsualUnaryConversionsNoPromoteInt(*this, TheCall->getArg(I));
14646+
if (Converted.isInvalid())
14647+
return std::nullopt;
14648+
Args[I] = Converted.get();
14649+
}
1469614650

14697-
if (Res.isNull() || TyA.getCanonicalType() != TyB.getCanonicalType())
14698-
return Diag(A.get()->getBeginLoc(),
14699-
diag::err_typecheck_call_different_arg_types)
14700-
<< TyA << TyB;
14651+
SourceLocation LocA = Args[0]->getBeginLoc();
14652+
QualType TyA = Args[0]->getType();
14653+
QualType TyB = Args[1]->getType();
14654+
14655+
if (TyA.getCanonicalType() != TyB.getCanonicalType()) {
14656+
Diag(LocA, diag::err_typecheck_call_different_arg_types) << TyA << TyB;
14657+
return std::nullopt;
14658+
}
1470114659

1470214660
if (FPOnly) {
14703-
if (checkFPMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
14704-
return true;
14661+
if (checkFPMathBuiltinElementType(*this, LocA, TyA, 1))
14662+
return std::nullopt;
1470514663
} else {
14706-
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
14707-
return true;
14664+
if (checkMathBuiltinElementType(*this, LocA, TyA, 1))
14665+
return std::nullopt;
1470814666
}
1470914667

14710-
TheCall->setArg(0, A.get());
14711-
TheCall->setArg(1, B.get());
14712-
return false;
14668+
TheCall->setArg(0, Args[0]);
14669+
TheCall->setArg(1, Args[1]);
14670+
return TyA;
1471314671
}
1471414672

1471514673
bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
@@ -14719,7 +14677,8 @@ bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall,
1471914677

1472014678
Expr *Args[3];
1472114679
for (int I = 0; I < 3; ++I) {
14722-
ExprResult Converted = UsualUnaryConversions(TheCall->getArg(I));
14680+
ExprResult Converted =
14681+
UsualUnaryConversionsNoPromoteInt(*this, TheCall->getArg(I));
1472314682
if (Converted.isInvalid())
1472414683
return true;
1472514684
Args[I] = Converted.get();

clang/lib/Sema/SemaExpr.cpp

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,64 +1489,63 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy,
14891489

14901490
/// Check that the usual arithmetic conversions can be performed on this pair of
14911491
/// expressions that might be of enumeration type.
1492-
static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
1493-
SourceLocation Loc,
1494-
Sema::ArithConvKind ACK) {
1492+
void Sema::checkEnumArithmeticConversions(Expr *LHS, Expr *RHS,
1493+
SourceLocation Loc,
1494+
Sema::ArithConvKind ACK) {
14951495
// C++2a [expr.arith.conv]p1:
14961496
// If one operand is of enumeration type and the other operand is of a
14971497
// different enumeration type or a floating-point type, this behavior is
14981498
// deprecated ([depr.arith.conv.enum]).
14991499
//
15001500
// Warn on this in all language modes. Produce a deprecation warning in C++20.
15011501
// Eventually we will presumably reject these cases (in C++23 onwards?).
1502-
QualType L = LHS->getEnumCoercedType(S.Context),
1503-
R = RHS->getEnumCoercedType(S.Context);
1502+
QualType L = LHS->getEnumCoercedType(Context),
1503+
R = RHS->getEnumCoercedType(Context);
15041504
bool LEnum = L->isUnscopedEnumerationType(),
15051505
REnum = R->isUnscopedEnumerationType();
15061506
bool IsCompAssign = ACK == Sema::ACK_CompAssign;
15071507
if ((!IsCompAssign && LEnum && R->isFloatingType()) ||
15081508
(REnum && L->isFloatingType())) {
1509-
S.Diag(Loc, S.getLangOpts().CPlusPlus26
1510-
? diag::err_arith_conv_enum_float_cxx26
1511-
: S.getLangOpts().CPlusPlus20
1512-
? diag::warn_arith_conv_enum_float_cxx20
1513-
: diag::warn_arith_conv_enum_float)
1509+
Diag(Loc, getLangOpts().CPlusPlus26 ? diag::err_arith_conv_enum_float_cxx26
1510+
: getLangOpts().CPlusPlus20
1511+
? diag::warn_arith_conv_enum_float_cxx20
1512+
: diag::warn_arith_conv_enum_float)
15141513
<< LHS->getSourceRange() << RHS->getSourceRange() << (int)ACK << LEnum
15151514
<< L << R;
15161515
} else if (!IsCompAssign && LEnum && REnum &&
1517-
!S.Context.hasSameUnqualifiedType(L, R)) {
1516+
!Context.hasSameUnqualifiedType(L, R)) {
15181517
unsigned DiagID;
15191518
// In C++ 26, usual arithmetic conversions between 2 different enum types
15201519
// are ill-formed.
1521-
if (S.getLangOpts().CPlusPlus26)
1520+
if (getLangOpts().CPlusPlus26)
15221521
DiagID = diag::err_conv_mixed_enum_types_cxx26;
15231522
else if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() ||
15241523
!R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) {
15251524
// If either enumeration type is unnamed, it's less likely that the
15261525
// user cares about this, but this situation is still deprecated in
15271526
// C++2a. Use a different warning group.
1528-
DiagID = S.getLangOpts().CPlusPlus20
1529-
? diag::warn_arith_conv_mixed_anon_enum_types_cxx20
1530-
: diag::warn_arith_conv_mixed_anon_enum_types;
1527+
DiagID = getLangOpts().CPlusPlus20
1528+
? diag::warn_arith_conv_mixed_anon_enum_types_cxx20
1529+
: diag::warn_arith_conv_mixed_anon_enum_types;
15311530
} else if (ACK == Sema::ACK_Conditional) {
15321531
// Conditional expressions are separated out because they have
15331532
// historically had a different warning flag.
1534-
DiagID = S.getLangOpts().CPlusPlus20
1533+
DiagID = getLangOpts().CPlusPlus20
15351534
? diag::warn_conditional_mixed_enum_types_cxx20
15361535
: diag::warn_conditional_mixed_enum_types;
15371536
} else if (ACK == Sema::ACK_Comparison) {
15381537
// Comparison expressions are separated out because they have
15391538
// historically had a different warning flag.
1540-
DiagID = S.getLangOpts().CPlusPlus20
1539+
DiagID = getLangOpts().CPlusPlus20
15411540
? diag::warn_comparison_mixed_enum_types_cxx20
15421541
: diag::warn_comparison_mixed_enum_types;
15431542
} else {
1544-
DiagID = S.getLangOpts().CPlusPlus20
1543+
DiagID = getLangOpts().CPlusPlus20
15451544
? diag::warn_arith_conv_mixed_enum_types_cxx20
15461545
: diag::warn_arith_conv_mixed_enum_types;
15471546
}
1548-
S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
1549-
<< (int)ACK << L << R;
1547+
Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange()
1548+
<< (int)ACK << L << R;
15501549
}
15511550
}
15521551

@@ -1557,7 +1556,7 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS,
15571556
QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
15581557
SourceLocation Loc,
15591558
ArithConvKind ACK) {
1560-
checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK);
1559+
checkEnumArithmeticConversions(LHS.get(), RHS.get(), Loc, ACK);
15611560

15621561
if (ACK != ACK_CompAssign) {
15631562
LHS = UsualUnaryConversions(LHS.get());

0 commit comments

Comments
 (0)