diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-ignoreconversionfromtypes-option.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-ignoreconversionfromtypes-option.cpp --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-ignoreconversionfromtypes-option.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-narrowing-conversions-ignoreconversionfromtypes-option.cpp @@ -42,7 +42,7 @@ // 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. } @@ -51,7 +51,7 @@ 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. } @@ -63,7 +63,7 @@ // 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. } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -1501,18 +1501,16 @@ // 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()) LHSType = AtomicLHS->getValueType(); // If both types are identical, no conversion is needed. - if (LHSType == RHSType) - return LHSType; + if (Context.hasSameType(LHSType, RHSType)) + return Context.getCommonSugar(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). @@ -1530,8 +1528,8 @@ 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.getCommonSugar(LHSType, RHSType); // At this point, we have two different arithmetic types. @@ -7868,23 +7866,6 @@ 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, @@ -7908,7 +7889,7 @@ if (S.Context.hasSameType(LHSTy, RHSTy)) { // Two identical pointers types are always compatible. - return LHSTy; + return S.Context.getCommonSugar(LHSTy, RHSTy); } QualType lhptee, rhptee; @@ -8401,7 +8382,7 @@ // And if they're both bfloat (which isn't arithmetic), that's fine too. if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) { - return LHSTy; + return Context.getCommonSugar(LHSTy, RHSTy); } // If both operands are the same structure or union type, the result is that @@ -8411,14 +8392,29 @@ 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.getCommonSugar(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.getCommonSugar(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 @@ -8457,7 +8453,7 @@ // Allow ?: operations in which both operands have the same // built-in sizeless type. if (LHSTy->isSizelessBuiltinType() && Context.hasSameType(LHSTy, RHSTy)) - return LHSTy; + return Context.getCommonSugar(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 @@ -10094,7 +10090,7 @@ // If the vector types are identical, return. if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugar(LHSType, RHSType); // If we have compatible AltiVec and GCC vector types, use the AltiVec type. if (LHSVecType && RHSVecType && @@ -12517,7 +12513,7 @@ assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix"); if (Context.hasSameType(LHSType, RHSType)) - return LHSType; + return Context.getCommonSugar(LHSType, RHSType); // Type conversion may change LHS/RHS. Keep copies to the original results, in // case we have to return InvalidOperands. @@ -12561,13 +12557,18 @@ if (LHSMatType->getNumColumns() != RHSMatType->getNumRows()) return InvalidOperands(Loc, LHS, RHS); - if (!Context.hasSameType(LHSMatType->getElementType(), - RHSMatType->getElementType())) + if (Context.hasSameType(LHSMatType, RHSMatType)) + return Context.getCommonSugar(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.getCommonSugar(LHSELTy, RHSELTy), LHSMatType->getNumRows(), + RHSMatType->getNumColumns()); } return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -6087,7 +6087,7 @@ << LHSType << RHSType; return {}; } - ResultType = LHSType; + ResultType = Context.getCommonSugar(LHSType, RHSType); } else if (LHSVT || RHSVT) { ResultType = CheckVectorOperands( LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, @@ -6096,15 +6096,13 @@ return {}; } else { // Both are scalar. - QualType ResultElementTy; - LHSType = LHSType.getCanonicalType().getUnqualifiedType(); - RHSType = RHSType.getCanonicalType().getUnqualifiedType(); - - if (Context.hasSameType(LHSType, RHSType)) - ResultElementTy = LHSType; - else - ResultElementTy = - UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); + LHSType = LHSType.getUnqualifiedType(); + RHSType = RHSType.getUnqualifiedType(); + QualType ResultElementTy = + Context.hasSameType(LHSType, RHSType) + ? Context.getCommonSugar(LHSType, RHSType) + : UsualArithmeticConversions(LHS, RHS, QuestionLoc, + ACK_Conditional); if (ResultElementTy->isEnumeralType()) { Diag(QuestionLoc, diag::err_conditional_vector_operand_type) @@ -6237,7 +6235,7 @@ // -- Both the second and third operands have type void; the result is of // type void and is a prvalue. if (LVoid && RVoid) - return Context.VoidTy; + return Context.getCommonSugar(LTy, RTy); // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) @@ -6354,7 +6352,7 @@ assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); } - return LTy; + return Context.getCommonSugar(LTy, RTy); } // C++11 [expr.cond]p5 @@ -6411,9 +6409,10 @@ LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); assert(!LTy.isNull() && "failed to find composite pointer type for " "canonically equivalent function ptr types"); + return LTy; } - return LTy; + return Context.getCommonSugar(LTy, RTy); } // Extension: conditional operator involving vector types. diff --git a/clang/test/AST/ast-dump-fpfeatures.cpp b/clang/test/AST/ast-dump-fpfeatures.cpp --- a/clang/test/AST/ast-dump-fpfeatures.cpp +++ b/clang/test/AST/ast-dump-fpfeatures.cpp @@ -140,4 +140,4 @@ // CHECK: FunctionDecl {{.*}} func_14 'float (float, float)' // CHECK: CompoundStmt // CHECK-NEXT: ReturnStmt -// CHECK-NEXT: BinaryOperator {{.*}} 'float' '+' RoundingMode=towardzero +// CHECK-NEXT: BinaryOperator {{.*}} 'float':'float' '+' RoundingMode=towardzero diff --git a/clang/test/CodeGen/compound-assign-overflow.c b/clang/test/CodeGen/compound-assign-overflow.c --- a/clang/test/CodeGen/compound-assign-overflow.c +++ b/clang/test/CodeGen/compound-assign-overflow.c @@ -3,9 +3,9 @@ #include -// CHECK: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [6 x i8] } { i16 0, i16 11, [6 x i8] c"'int'\00" } +// CHECK: @[[INT:.*]] = private unnamed_addr constant { i16, i16, [22 x i8] } { i16 0, i16 11, [22 x i8] c"'int32_t' (aka 'int')\00" } // CHECK: @[[LINE_100:.*]] = private unnamed_addr global {{.*}}, i32 100, i32 5 {{.*}} @[[INT]] -// CHECK: @[[UINT:.*]] = private unnamed_addr constant { i16, i16, [15 x i8] } { i16 0, i16 10, [15 x i8] c"'unsigned int'\00" } +// CHECK: @[[UINT:.*]] = private unnamed_addr constant { i16, i16, [32 x i8] } { i16 0, i16 10, [32 x i8] c"'uint32_t' (aka 'unsigned int')\00" } // CHECK: @[[LINE_200:.*]] = private unnamed_addr global {{.*}}, i32 200, i32 5 {{.*}} @[[UINT]] // CHECK: @[[LINE_300:.*]] = private unnamed_addr global {{.*}}, i32 300, i32 5 {{.*}} @[[INT]] diff --git a/clang/test/Sema/matrix-type-operators.c b/clang/test/Sema/matrix-type-operators.c --- a/clang/test/Sema/matrix-type-operators.c +++ b/clang/test/Sema/matrix-type-operators.c @@ -56,7 +56,7 @@ a *= b; // expected-error@-1 {{invalid operands to binary expression ('sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))') and 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))'))}} b = a * a; - // expected-error@-1 {{assigning to 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') from incompatible type 'float __attribute__((matrix_type(10, 10)))'}} + // expected-error@-1 {{assigning to 'sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') from incompatible type 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))')}} // Check element type mismatches. a = b * c; @@ -64,10 +64,10 @@ b *= c; // expected-error@-1 {{invalid operands to binary expression ('sx5x10_t' (aka 'float __attribute__((matrix_type(5, 10)))') and 'ix10x5_t' (aka 'int __attribute__((matrix_type(10, 5)))'))}} d = a * a; - // expected-error@-1 {{assigning to 'ix10x10_t' (aka 'int __attribute__((matrix_type(10, 10)))') from incompatible type 'float __attribute__((matrix_type(10, 10)))'}} + // expected-error@-1 {{assigning to 'ix10x10_t' (aka 'int __attribute__((matrix_type(10, 10)))') from incompatible type 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))')}} p = a * a; - // expected-error@-1 {{assigning to 'char *' from incompatible type 'float __attribute__((matrix_type(10, 10)))'}} + // expected-error@-1 {{assigning to 'char *' from incompatible type 'sx10x10_t' (aka 'float __attribute__((matrix_type(10, 10)))')}} } void mat_scalar_multiply(sx10x10_t a, sx5x10_t b, float sf, char *p) { diff --git a/clang/test/Sema/nullability.c b/clang/test/Sema/nullability.c --- a/clang/test/Sema/nullability.c +++ b/clang/test/Sema/nullability.c @@ -166,7 +166,7 @@ p = c ? nonnullP2 : nonnullP2; p = c ? nonnullP2 : nullableP2; // expected-warning{{implicit conversion from nullable pointer 'IntP _Nullable' (aka 'int *') to non-nullable pointer type 'int * _Nonnull'}} - p = c ? nullableP2 : nonnullP2; // expected-warning{{implicit conversion from nullable pointer 'NullableIntP1' (aka 'int *') to non-nullable pointer type 'int * _Nonnull'}} + p = c ? nullableP2 : nonnullP2; // expected-warning{{implicit conversion from nullable pointer 'IntP _Nullable' (aka 'int *') to non-nullable pointer type 'int * _Nonnull'}} p = c ? nullableP2 : nullableP2; // expected-warning{{implicit conversion from nullable pointer 'NullableIntP1' (aka 'int *') to non-nullable pointer type 'int * _Nonnull'}} } diff --git a/clang/test/Sema/sugar-common-types.c b/clang/test/Sema/sugar-common-types.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/sugar-common-types.c @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c99 -triple aarch64-arm-none-eabi -target-feature +bf16 -target-feature +sve + +typedef struct N {} N; + +typedef int B1; +typedef B1 X1; +typedef B1 Y1; + +typedef void B2; +typedef B2 X2; +typedef B2 Y2; + +typedef struct B3 {} B3; +typedef B3 X3; +typedef B3 Y3; + +typedef struct B4 {} *B4; +typedef B4 X4; +typedef B4 Y4; + +typedef __bf16 B5; +typedef B5 X5; +typedef B5 Y5; + +typedef __SVInt8_t B6; +typedef B6 X6; +typedef B6 Y6; + +N t1 = 0 ? (X1)0 : (Y1)0; // expected-error {{incompatible type 'B1'}} +N t2 = 0 ? (X2)0 : 0; // expected-error {{incompatible type 'X2'}} +N t3 = 0 ? 0 : (Y2)0; // expected-error {{incompatible type 'Y2'}} +N t4 = 0 ? (X2)0 : (Y2)0; // expected-error {{incompatible type 'B2'}} +N t5 = 0 ? (X3){} : (B3){}; // expected-error {{incompatible type 'B3'}} +N t6 = 0 ? (X4)0 : (Y4)0; // expected-error {{incompatible type 'B4'}} + +X5 x5; +Y5 y5; +N t7 = 0 ? x5 : y5; // expected-error {{incompatible type 'B5'}} + +void f8() { + X6 x6; + Y6 y6; + N t8 = 0 ? x6 : y6; // expected-error {{incompatible type 'B6'}} +} diff --git a/clang/test/SemaCXX/matrix-type-operators.cpp b/clang/test/SemaCXX/matrix-type-operators.cpp --- a/clang/test/SemaCXX/matrix-type-operators.cpp +++ b/clang/test/SemaCXX/matrix-type-operators.cpp @@ -68,7 +68,7 @@ template typename MyMatrix::matrix_t multiply(MyMatrix &A, MyMatrix &B) { char *v1 = A.value * B.value; - // expected-error@-1 {{cannot initialize a variable of type 'char *' with an rvalue of type 'unsigned int __attribute__((matrix_type(2, 2)))'}} + // expected-error@-1 {{cannot initialize a variable of type 'char *' with an rvalue of type 'MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))')}} // expected-error@-2 {{invalid operands to binary expression ('MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 2)))') and 'MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(3, 3)))'))}} // expected-error@-3 {{invalid operands to binary expression ('MyMatrix::matrix_t' (aka 'float __attribute__((matrix_type(2, 2)))') and 'MyMatrix::matrix_t' (aka 'unsigned int __attribute__((matrix_type(2, 2)))'))}} diff --git a/clang/test/SemaCXX/sugar-common-types.cpp b/clang/test/SemaCXX/sugar-common-types.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/sugar-common-types.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++20 -fenable-matrix + +enum class N {}; + +using B1 = int; +using X1 = B1; +using Y1 = B1; + +using B2 = void; +using X2 = B2; +using Y2 = B2; + +using A3 = char __attribute__((vector_size(4))); +using B3 = A3; +using X3 = B3; +using Y3 = B3; + +using A4 = float; +using B4 = A4 __attribute__((matrix_type(4, 4))); +using X4 = B4; +using Y4 = B4; + +using X5 = A4 __attribute__((matrix_type(3, 4))); +using Y5 = A4 __attribute__((matrix_type(4, 3))); + +N t1 = 0 ? X1() : Y1(); // expected-error {{rvalue of type 'B1'}} +N t2 = 0 ? X2() : Y2(); // expected-error {{rvalue of type 'B2'}} + +const X1 &xt3 = 0; +const Y1 &yt3 = 0; +N t3 = 0 ? xt3 : yt3; // expected-error {{lvalue of type 'const B1'}} + +N t4 = X3() + Y3(); // expected-error {{rvalue of type 'B3'}} + +N t5 = A3() ? X3() : Y3(); // expected-error {{rvalue of type 'B3'}} +N t6 = A3() ? X1() : Y1(); // expected-error {{vector condition type 'A3' (vector of 4 'char' values) and result type '__attribute__((__vector_size__(4 * sizeof(B1)))) B1' (vector of 4 'B1' values) do not have elements of the same size}} + +N t7 = X4() + Y4(); // expected-error {{rvalue of type 'B4'}} +N t8 = X4() * Y4(); // expected-error {{rvalue of type 'B4'}} +N t9 = X5() * Y5(); // expected-error {{rvalue of type 'A4 __attribute__((matrix_type(3, 3)))'}} diff --git a/clang/test/SemaCXX/sugared-auto.cpp b/clang/test/SemaCXX/sugared-auto.cpp --- a/clang/test/SemaCXX/sugared-auto.cpp +++ b/clang/test/SemaCXX/sugared-auto.cpp @@ -143,7 +143,7 @@ return true ? a : b; if (false) return a; - return N(); // expected-error {{but deduced as 'SARS (*)() throw(Man, Vibrio)' (aka 'void (*)() throw(Man, Vibrio)')}} + return N(); // expected-error {{but deduced as 'Virus (*)() throw(Man, Vibrio)' (aka 'void (*)() throw(Man, Vibrio)')}} } using fp5 = void (*)(const Man); diff --git a/clang/test/SemaObjC/format-strings-objc.m b/clang/test/SemaObjC/format-strings-objc.m --- a/clang/test/SemaObjC/format-strings-objc.m +++ b/clang/test/SemaObjC/format-strings-objc.m @@ -253,7 +253,7 @@ // void testTypeOf(NSInteger dW, NSInteger dH) { - NSLog(@"dW %d dH %d",({ __typeof__(dW) __a = (dW); __a < 0 ? -__a : __a; }),({ __typeof__(dH) __a = (dH); __a < 0 ? -__a : __a; })); // expected-warning 2 {{format specifies type 'int' but the argument has type 'long'}} + NSLog(@"dW %d dH %d",({ __typeof__(dW) __a = (dW); __a < 0 ? -__a : __a; }),({ __typeof__(dH) __a = (dH); __a < 0 ? -__a : __a; })); // expected-warning 2 {{values of type 'NSInteger' should not be used as format arguments; add an explicit cast to 'long' instead}} } void testUnicode() {