r243069 - Fix the equal-vector-size rule for reinterpret_casts in C++

John McCall rjmccall at apple.com
Thu Jul 23 16:54:08 PDT 2015


Author: rjmccall
Date: Thu Jul 23 18:54:07 2015
New Revision: 243069

URL: http://llvm.org/viewvc/llvm-project?rev=243069&view=rev
Log:
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

Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCast.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/test/Sema/vector-cast.c
    cfe/trunk/test/SemaCXX/vector-casts.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=243069&r1=243068&r2=243069&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 23 18:54:07 2015
@@ -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)

Modified: cfe/trunk/lib/Sema/SemaCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCast.cpp?rev=243069&r1=243068&r2=243069&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCast.cpp Thu Jul 23 18:54:07 2015
@@ -1877,28 +1877,29 @@ static TryCastResult TryReinterpretCast(
     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;

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=243069&r1=243068&r2=243069&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jul 23 18:54:07 2015
@@ -5400,7 +5400,16 @@ static bool breakDownVectorType(QualType
   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, Qu
   // 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(Sour
   // 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)

Modified: cfe/trunk/test/Sema/vector-cast.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/vector-cast.c?rev=243069&r1=243068&r2=243069&view=diff
==============================================================================
--- cfe/trunk/test/Sema/vector-cast.c (original)
+++ cfe/trunk/test/Sema/vector-cast.c Thu Jul 23 18:54:07 2015
@@ -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}}

Modified: cfe/trunk/test/SemaCXX/vector-casts.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/vector-casts.cpp?rev=243069&r1=243068&r2=243069&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/vector-casts.cpp (original)
+++ cfe/trunk/test/SemaCXX/vector-casts.cpp Thu Jul 23 18:54:07 2015
@@ -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<E>(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<S>(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 {





More information about the cfe-commits mailing list