[clang] 044c51d - Fix vector type scalar checking when the scalar operand is dependent

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Wed Mar 25 11:39:13 PDT 2020


Author: Erich Keane
Date: 2020-03-25T11:38:58-07:00
New Revision: 044c51d8d433da885438fcb141b15c80d7b62eda

URL: https://github.com/llvm/llvm-project/commit/044c51d8d433da885438fcb141b15c80d7b62eda
DIFF: https://github.com/llvm/llvm-project/commit/044c51d8d433da885438fcb141b15c80d7b62eda.diff

LOG: Fix vector type scalar checking when the scalar operand is dependent

As reported in PR45298 and PR45299, vector_size type checking would
crash when done in a situation where the scalar is dependent, such as
a member of the current instantiation.

This is because the scalar checking ensures that you can implicitly
convert a value to a vector-type as long as it doesn't require
truncation. It does this by using the constant evaluator to get the
value as a float. Unfortunately, if the scalar is dependent (such as a
member of the current instantiation), we would hit the assert in the
evaluator.

This patch suppresses the truncation- of-value check in the first phase
of translation. All values are properly errored upon instantiation. This
has one minor regression, in that previously in a non-asserts build,

template<typename T>
struct S {
  float4 f(float4 f) {
    return k + f;
  }
  static constexpr k = 1.1; // causes a truncation on conversion.
};

would error immediately. Because 'k' is value dependent (as a
member-of-the-current-instantiation), this would still be evaluatable
(despite normally asserting).  Due to this patch, this diagnostic is
delayed until instantiation time.

Added: 
    

Modified: 
    clang/lib/Sema/SemaExpr.cpp
    clang/test/SemaCXX/vector.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 7cb12ec9c405..8f4a7f240de1 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -9201,7 +9201,13 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar,
       // Reject cases where the scalar type is not a constant and has a higher
       // Order than the vector element type.
       llvm::APFloat Result(0.0);
-      bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context);
+
+      // Determine whether this is a constant scalar. In the event that the
+      // value is dependent (and thus cannot be evaluated by the constant
+      // evaluator), skip the evaluation. This will then diagnose once the
+      // expression is instantiated.
+      bool CstScalar = Scalar->get()->isValueDependent() ||
+                       Scalar->get()->EvaluateAsFloat(Result, S.Context);
       int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy);
       if (!CstScalar && Order < 0)
         return true;

diff  --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp
index 67e5a94cb108..cabc525771c3 100644
--- a/clang/test/SemaCXX/vector.cpp
+++ b/clang/test/SemaCXX/vector.cpp
@@ -400,3 +400,77 @@ namespace swizzle_typo_correction {
     return A.xyzw < B.x && B.y > A.y; // OK, not a typo for 'xyzv'
   }
 }
+
+namespace PR45299 {
+typedef float float4 __attribute__((vector_size(16)));
+
+// In this example, 'k' is value dependent. PR45299 reported that this asserted
+// because of that, since the truncation check attempted to constant evaluate k,
+// which it could not do because it is dependent.
+template <typename T>
+struct NormalMember {
+  float4 f(float4 x) {
+    return k * x;
+  }
+  float k;
+};
+
+#if __cplusplus >= 201103L
+// This should not diagnose, since the constant evaluator (during instantiation)
+// can tell that this isn't a truncation.
+template <typename T>
+struct ConstantValueNoDiag {
+  float4 f(float4 x) {
+    return k * x;
+  }
+  static constexpr double k = 1;
+};
+
+// The following two both diagnose because they cause a truncation.  Test both
+// the dependent type and non-dependent type versions.
+template <typename T>
+struct DiagTrunc {
+  float4 f(float4 x) {
+    // expected-error at +1{{as implicit conversion would cause truncation}}
+    return k * x;
+  }
+  static constexpr double k = 1340282346638528859811704183484516925443.000000;
+};
+template <typename T>
+struct DiagTruncDependentType {
+  float4 f(float4 x) {
+    // expected-error at +1{{as implicit conversion would cause truncation}}
+    return k * x;
+  }
+  static constexpr T k = 1340282346638528859811704183484516925443.000000;
+};
+
+template <typename T>
+struct PR45298 {
+    T k1 = T(0);
+};
+
+// Ensure this no longer asserts.
+template <typename T>
+struct PR45298Consumer {
+  float4 f(float4 x) {
+    return (float)s.k1 * x;
+  }
+
+  PR45298<T> s;
+};
+#endif // __cplusplus >= 201103L
+
+void use() {
+  float4 theFloat4;
+  NormalMember<double>().f(theFloat4);
+#if __cplusplus >= 201103L
+  ConstantValueNoDiag<double>().f(theFloat4);
+  // expected-note at +1{{in instantiation of member function}}
+  DiagTrunc<double>().f(theFloat4);
+  // expected-note at +1{{in instantiation of member function}}
+  DiagTruncDependentType<double>().f(theFloat4);
+  PR45298Consumer<double>().f(theFloat4);
+#endif // __cplusplus >= 201103L
+}
+}


        


More information about the cfe-commits mailing list