From 3c880489dac6efe5912cc0b6ce9792a30e6a7c09 Mon Sep 17 00:00:00 2001 From: John McCall Date: Thu, 23 Jul 2015 23:54:07 +0000 Subject: [PATCH] Fix the equal-vector-size rule for reinterpret_casts in C++ to consider the storage size of the vector instead of its sizeof. In other words, ban <3 x int> to <4 x int> casts, which produced invalid IR anyway. Also, attempt to be a little more rigorous, or at least explicit, about when enums are allowed in these casts. rdar://21901132 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@243069 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 1 + lib/Sema/SemaCast.cpp | 27 ++++++++++++++------------- lib/Sema/SemaExpr.cpp | 26 ++++++++++++++++++-------- test/Sema/vector-cast.c | 8 ++++++++ test/SemaCXX/vector-casts.cpp | 22 ++++++++++++++++++++-- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 57b014d629..575f705542 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8375,6 +8375,7 @@ public: QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); + bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); /// type checking declaration initializers (C99 6.7.8) diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index c0754ba790..fe16fc2df3 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1877,28 +1877,29 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_Success; } + // Allow reinterpret_casts between vectors of the same size and + // between vectors and integers of the same size. bool destIsVector = DestType->isVectorType(); bool srcIsVector = SrcType->isVectorType(); if (srcIsVector || destIsVector) { - // FIXME: Should this also apply to floating point types? - bool srcIsScalar = SrcType->isIntegralType(Self.Context); - bool destIsScalar = DestType->isIntegralType(Self.Context); - - // Check if this is a cast between a vector and something else. - if (!(srcIsScalar && destIsVector) && !(srcIsVector && destIsScalar) && - !(srcIsVector && destIsVector)) + // The non-vector type, if any, must have integral type. This is + // the same rule that C vector casts use; note, however, that enum + // types are not integral in C++. + if ((!destIsVector && !DestType->isIntegralType(Self.Context)) || + (!srcIsVector && !SrcType->isIntegralType(Self.Context))) return TC_NotApplicable; - // If both types have the same size, we can successfully cast. - if (Self.Context.getTypeSize(SrcType) - == Self.Context.getTypeSize(DestType)) { + // The size we want to consider is eltCount * eltSize. + // That's exactly what the lax-conversion rules will check. + if (Self.areLaxCompatibleVectorTypes(SrcType, DestType)) { Kind = CK_BitCast; return TC_Success; } - - if (destIsScalar) + + // Otherwise, pick a reasonable diagnostic. + if (!destIsVector) msg = diag::err_bad_cxx_cast_vector_to_scalar_different_size; - else if (srcIsScalar) + else if (!srcIsVector) msg = diag::err_bad_cxx_cast_scalar_to_vector_different_size; else msg = diag::err_bad_cxx_cast_vector_to_vector_different_size; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f384f56269..61f361676d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5400,7 +5400,16 @@ static bool breakDownVectorType(QualType type, uint64_t &len, return true; } -static bool VectorTypesMatch(Sema &S, QualType srcTy, QualType destTy) { +/// Are the two types lax-compatible vector types? That is, given +/// that one of them is a vector, do they have equal storage sizes, +/// where the storage size is the number of elements times the element +/// size? +/// +/// This will also return false if either of the types is neither a +/// vector nor a real type. +bool Sema::areLaxCompatibleVectorTypes(QualType srcTy, QualType destTy) { + assert(destTy->isVectorType() || srcTy->isVectorType()); + uint64_t srcLen, destLen; QualType srcElt, destElt; if (!breakDownVectorType(srcTy, srcLen, srcElt)) return false; @@ -5409,27 +5418,28 @@ static bool VectorTypesMatch(Sema &S, QualType srcTy, QualType destTy) { // ASTContext::getTypeSize will return the size rounded up to a // power of 2, so instead of using that, we need to use the raw // element size multiplied by the element count. - uint64_t srcEltSize = S.Context.getTypeSize(srcElt); - uint64_t destEltSize = S.Context.getTypeSize(destElt); + uint64_t srcEltSize = Context.getTypeSize(srcElt); + uint64_t destEltSize = Context.getTypeSize(destElt); return (srcLen * srcEltSize == destLen * destEltSize); } -/// Is this a legal conversion between two known vector types? +/// Is this a legal conversion between two types, one of which is +/// known to be a vector type? bool Sema::isLaxVectorConversion(QualType srcTy, QualType destTy) { assert(destTy->isVectorType() || srcTy->isVectorType()); if (!Context.getLangOpts().LaxVectorConversions) return false; - return VectorTypesMatch(*this, srcTy, destTy); + return areLaxCompatibleVectorTypes(srcTy, destTy); } bool Sema::CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind) { assert(VectorTy->isVectorType() && "Not a vector type!"); - if (Ty->isVectorType() || Ty->isIntegerType()) { - if (!VectorTypesMatch(*this, Ty, VectorTy)) + if (Ty->isVectorType() || Ty->isIntegralType(Context)) { + if (!areLaxCompatibleVectorTypes(Ty, VectorTy)) return Diag(R.getBegin(), Ty->isVectorType() ? diag::err_invalid_conversion_between_vectors : @@ -5455,7 +5465,7 @@ ExprResult Sema::CheckExtVectorCast(SourceRange R, QualType DestTy, // In OpenCL, casts between vectors of different types are not allowed. // (See OpenCL 6.2). if (SrcTy->isVectorType()) { - if (!VectorTypesMatch(*this, SrcTy, DestTy) + if (!areLaxCompatibleVectorTypes(SrcTy, DestTy) || (getLangOpts().OpenCL && (DestTy.getCanonicalType() != SrcTy.getCanonicalType()))) { Diag(R.getBegin(),diag::err_invalid_conversion_between_ext_vectors) diff --git a/test/Sema/vector-cast.c b/test/Sema/vector-cast.c index 0415c13990..03db5408c4 100644 --- a/test/Sema/vector-cast.c +++ b/test/Sema/vector-cast.c @@ -3,12 +3,20 @@ typedef long long t1 __attribute__ ((vector_size (8))); typedef char t2 __attribute__ ((vector_size (16))); typedef float t3 __attribute__ ((vector_size (16))); +typedef short s2 __attribute__ ((vector_size(4))); + +typedef enum { Evalue = 0x10000 } E; void f() { t1 v1; t2 v2; t3 v3; + s2 v4; + E e; + + e = (E)v4; + v4 = (s2)e; v2 = (t2)v1; // expected-error {{invalid conversion between vector type \ 't2' (vector of 16 'char' values) and 't1' (vector of 1 'long long' value) of different size}} diff --git a/test/SemaCXX/vector-casts.cpp b/test/SemaCXX/vector-casts.cpp index 2ccd5979c7..26e7df8396 100644 --- a/test/SemaCXX/vector-casts.cpp +++ b/test/SemaCXX/vector-casts.cpp @@ -1,18 +1,22 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++11 -triple x86_64-unknown-unknown -fsyntax-only -verify %s typedef int __v2si __attribute__((__vector_size__(8))); typedef short __v4hi __attribute__((__vector_size__(8))); typedef short __v8hi __attribute__((__vector_size__(16))); typedef short __v3hi __attribute__((__ext_vector_type__(3))); -struct S { }; // expected-note 2 {{candidate constructor}} +struct S { }; // expected-note 3 {{candidate constructor}} + +enum E : long long { Evalue }; void f() { __v2si v2si; + __v3hi v3hi; __v4hi v4hi; __v8hi v8hi; unsigned long long ll; unsigned char c; S s; + E e; (void)reinterpret_cast<__v2si>(v4hi); (void)(__v2si)v4hi; @@ -23,6 +27,11 @@ void f() { (void)reinterpret_cast<__v2si>(ll); (void)(__v2si)(ll); + (void)(E)v2si; // expected-error {{C-style cast from '__v2si' (vector of 2 'int' values) to 'E' is not allowed}} + (void)(__v2si)e; // expected-error {{C-style cast from 'E' to '__v2si' (vector of 2 'int' values)}} + (void)reinterpret_cast(v2si); // expected-error {{reinterpret_cast from '__v2si' (vector of 2 'int' values) to 'E' is not allowed}} + (void)reinterpret_cast<__v2si>(e); // expected-error {{reinterpret_cast from 'E' to '__v2si' (vector of 2 'int' values)}} + (void)reinterpret_cast(v2si); // expected-error {{reinterpret_cast from '__v2si' (vector of 2 'int' values) to 'S' is not allowed}} (void)(S)v2si; // expected-error {{no matching conversion for C-style cast from '__v2si' (vector of 2 'int' values) to 'S'}} (void)reinterpret_cast<__v2si>(s); // expected-error {{reinterpret_cast from 'S' to '__v2si' (vector of 2 'int' values) is not allowed}} @@ -36,6 +45,15 @@ void f() { (void)(__v8hi)v4hi; // expected-error {{C-style cast from vector '__v4hi' (vector of 4 'short' values) to vector '__v8hi' (vector of 8 'short' values) of different size}} (void)reinterpret_cast<__v4hi>(v8hi); // expected-error {{reinterpret_cast from vector '__v8hi' (vector of 8 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}} (void)(__v4hi)v8hi; // expected-error {{C-style cast from vector '__v8hi' (vector of 8 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}} + + (void)(__v3hi)v4hi; // expected-error {{C-style cast from vector '__v4hi' (vector of 4 'short' values) to vector '__v3hi' (vector of 3 'short' values) of different size}} + (void)(__v3hi)v2si; // expected-error {{C-style cast from vector '__v2si' (vector of 2 'int' values) to vector '__v3hi' (vector of 3 'short' values) of different size}} + (void)(__v4hi)v3hi; // expected-error {{C-style cast from vector '__v3hi' (vector of 3 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}} + (void)(__v2si)v3hi; // expected-error {{C-style cast from vector '__v3hi' (vector of 3 'short' values) to vector '__v2si' (vector of 2 'int' values) of different size}} + (void)reinterpret_cast<__v3hi>(v4hi); // expected-error {{reinterpret_cast from vector '__v4hi' (vector of 4 'short' values) to vector '__v3hi' (vector of 3 'short' values) of different size}} + (void)reinterpret_cast<__v3hi>(v2si); // expected-error {{reinterpret_cast from vector '__v2si' (vector of 2 'int' values) to vector '__v3hi' (vector of 3 'short' values) of different size}} + (void)reinterpret_cast<__v4hi>(v3hi); // expected-error {{reinterpret_cast from vector '__v3hi' (vector of 3 'short' values) to vector '__v4hi' (vector of 4 'short' values) of different size}} + (void)reinterpret_cast<__v2si>(v3hi); // expected-error {{reinterpret_cast from vector '__v3hi' (vector of 3 'short' values) to vector '__v2si' (vector of 2 'int' values) of different size}} } struct testvec { -- 2.40.0