Skip to content

[clang][ExprConst] allow single element access of vector object to be constant expression #101126

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 7, 2024

Conversation

vikramRH
Copy link
Contributor

@vikramRH vikramRH commented Jul 30, 2024

This is a slightly updated version of #72607 (I could not find a way to continue with the same PR, hopefully this is not very confusing). @sethp , I have tried addressing your views here although I have not given much thought on extending pathEntry for vector elements.

originally authored by @yuanfang-chen (perhaps we could close the old PR?)

Copy link
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @vikramRH and the rest of your teammates on Graphite Graphite

@vikramRH vikramRH marked this pull request as ready for review July 30, 2024 05:00
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 30, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 30, 2024

@llvm/pr-subscribers-clang

Author: Vikram Hegde (vikramRH)

Changes

This is a slightly updated version of #72607 (I could not find a way to continue with the same PR, hopefully this is not very confusing). @sethp , I have tried addressing your views here although I have not given much thought on extending pathEntry for vector elements.

originally authored by @yuanfang-chen (perhaps we could close the old PR?)


Full diff: https://github.com/llvm/llvm-project/pull/101126.diff

7 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+3)
  • (modified) clang/lib/AST/ExprConstant.cpp (+98-4)
  • (modified) clang/lib/AST/Interp/State.h (+2-1)
  • (modified) clang/test/AST/Interp/builtin-functions.cpp (+13-13)
  • (modified) clang/test/AST/Interp/vectors.cpp (+25-25)
  • (modified) clang/test/CodeGenCXX/temporaries.cpp (+20-21)
  • (added) clang/test/SemaCXX/constexpr-vectors-access-elements.cpp (+29)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index ddad083571eb1..2179aaea12387 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -64,6 +64,9 @@ sections with improvements to Clang's support for those languages.
 
 C++ Language Changes
 --------------------
+- Allow single element access of vector object to be constant expression.
+  Supports the `V.xyzw` syntax and other tidbits as seen in OpenCL.
+  Selecting multiple elements is left as a future work.
 
 C++17 Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 558e20ed3e423..08f49ac896153 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -222,6 +222,11 @@ namespace {
         ArraySize = 2;
         MostDerivedLength = I + 1;
         IsArray = true;
+      } else if (const auto *VT = Type->getAs<VectorType>()) {
+        Type = VT->getElementType();
+        ArraySize = VT->getNumElements();
+        MostDerivedLength = I + 1;
+        IsArray = true;
       } else if (const FieldDecl *FD = getAsField(Path[I])) {
         Type = FD->getType();
         ArraySize = 0;
@@ -268,7 +273,6 @@ namespace {
     /// If the current array is an unsized array, the value of this is
     /// undefined.
     uint64_t MostDerivedArraySize;
-
     /// The type of the most derived object referred to by this address.
     QualType MostDerivedType;
 
@@ -442,6 +446,16 @@ namespace {
       MostDerivedArraySize = 2;
       MostDerivedPathLength = Entries.size();
     }
+
+    void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
+                                   uint64_t Idx) {
+      Entries.push_back(PathEntry::ArrayIndex(Idx));
+      MostDerivedType = EltTy;
+      MostDerivedPathLength = Entries.size();
+      MostDerivedArraySize = 0;
+      MostDerivedIsArrayElement = false;
+    }
+
     void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
     void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
                                    const APSInt &N);
@@ -1737,6 +1751,11 @@ namespace {
       if (checkSubobject(Info, E, Imag ? CSK_Imag : CSK_Real))
         Designator.addComplexUnchecked(EltTy, Imag);
     }
+    void addVectorElement(EvalInfo &Info, const Expr *E, QualType EltTy,
+                          uint64_t Size, uint64_t Idx) {
+      if (checkSubobject(Info, E, CSK_VectorElement))
+        Designator.addVectorElementUnchecked(EltTy, Size, Idx);
+    }
     void clearIsNullPointer() {
       IsNullPtr = false;
     }
@@ -3310,6 +3329,19 @@ static bool HandleLValueComplexElement(EvalInfo &Info, const Expr *E,
   return true;
 }
 
+static bool HandleLValueVectorElement(EvalInfo &Info, const Expr *E,
+                                      LValue &LVal, QualType EltTy,
+                                      uint64_t Size, uint64_t Idx) {
+  if (Idx) {
+    CharUnits SizeOfElement;
+    if (!HandleSizeof(Info, E->getExprLoc(), EltTy, SizeOfElement))
+      return false;
+    LVal.Offset += SizeOfElement * Idx;
+  }
+  LVal.addVectorElement(Info, E, EltTy, Size, Idx);
+  return true;
+}
+
 /// Try to evaluate the initializer for a variable declaration.
 ///
 /// \param Info   Information about the ongoing evaluation.
@@ -3855,6 +3887,19 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
         return handler.found(Index ? O->getComplexFloatImag()
                                    : O->getComplexFloatReal(), ObjType);
       }
+    } else if (const auto *VT = ObjType->getAs<VectorType>()) {
+      uint64_t Index = Sub.Entries[I].getAsArrayIndex();
+      if (Index >= VT->getNumElements()) {
+        if (Info.getLangOpts().CPlusPlus11)
+          Info.FFDiag(E, diag::note_constexpr_access_past_end)
+              << handler.AccessKind;
+        else
+          Info.FFDiag(E);
+        return handler.failed();
+      }
+      ObjType = VT->getElementType();
+      assert(I == N - 1 && "extracting subobject of scalar?");
+      return handler.found(O->getVectorElt(Index), ObjType);
     } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
       if (Field->isMutable() &&
           !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
@@ -8509,6 +8554,7 @@ class LValueExprEvaluator
   bool VisitCXXTypeidExpr(const CXXTypeidExpr *E);
   bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
+  bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);
   bool VisitUnaryDeref(const UnaryOperator *E);
   bool VisitUnaryReal(const UnaryOperator *E);
   bool VisitUnaryImag(const UnaryOperator *E);
@@ -8850,15 +8896,63 @@ bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
   return LValueExprEvaluatorBaseTy::VisitMemberExpr(E);
 }
 
+bool LValueExprEvaluator::VisitExtVectorElementExpr(
+    const ExtVectorElementExpr *E) {
+  bool Success = true;
+
+  APValue Val;
+  if (!Evaluate(Val, Info, E->getBase())) {
+    if (!Info.noteFailure())
+      return false;
+    Success = false;
+  }
+
+  SmallVector<uint32_t, 4> Indices;
+  E->getEncodedElementAccess(Indices);
+  // FIXME: support accessing more than one element
+  if (Indices.size() > 1)
+    return false;
+
+  if (Success) {
+    Result.setFrom(Info.Ctx, Val);
+    const auto *VT = E->getBase()->getType()->castAs<VectorType>();
+    HandleLValueVectorElement(Info, E, Result, VT->getElementType(),
+                              VT->getNumElements(), Indices[0]);
+  }
+
+  return Success;
+}
+
 bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
-  // FIXME: Deal with vectors as array subscript bases.
-  if (E->getBase()->getType()->isVectorType() ||
-      E->getBase()->getType()->isSveVLSBuiltinType())
+  if (E->getBase()->getType()->isSveVLSBuiltinType())
     return Error(E);
 
   APSInt Index;
   bool Success = true;
 
+  if (const auto *VT = E->getBase()->getType()->getAs<VectorType>()) {
+    APValue Val;
+    if (!Evaluate(Val, Info, E->getBase())) {
+      if (!Info.noteFailure())
+        return false;
+      Success = false;
+    }
+
+    if (!EvaluateInteger(E->getIdx(), Index, Info)) {
+      if (!Info.noteFailure())
+        return false;
+      Success = false;
+    }
+
+    if (Success) {
+      Result.setFrom(Info.Ctx, Val);
+      HandleLValueVectorElement(Info, E, Result, VT->getElementType(),
+                                VT->getNumElements(), Index.getExtValue());
+    }
+
+    return Success;
+  }
+
   // C++17's rules require us to evaluate the LHS first, regardless of which
   // side is the base.
   for (const Expr *SubExpr : {E->getLHS(), E->getRHS()}) {
diff --git a/clang/lib/AST/Interp/State.h b/clang/lib/AST/Interp/State.h
index f1e8e3618f34f..44d6c037c5ad9 100644
--- a/clang/lib/AST/Interp/State.h
+++ b/clang/lib/AST/Interp/State.h
@@ -44,7 +44,8 @@ enum CheckSubobjectKind {
   CSK_ArrayToPointer,
   CSK_ArrayIndex,
   CSK_Real,
-  CSK_Imag
+  CSK_Imag,
+  CSK_VectorElement
 };
 
 namespace interp {
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 0a17106449faf..b179298fee9bd 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -866,11 +866,11 @@ namespace convertvector {
   constexpr vector8BitInt128 from_vector8BitInt128_to_vector8BitInt128_var =
       __builtin_convertvector((vector8BitInt128){0, 1, 2, 3, 4, 5, 6, 7},
                               vector8BitInt128);
-  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[0] == 0, ""); // ref-error {{not an integral constant expression}}
-  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[1] == 1, ""); // ref-error {{not an integral constant expression}}
-  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[2] == 2, ""); // ref-error {{not an integral constant expression}}
-  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[3] == 3, ""); // ref-error {{not an integral constant expression}}
-  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[4] == 4, ""); // ref-error {{not an integral constant expression}}
+  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[0] == 0, ""); 
+  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[1] == 1, ""); 
+  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[2] == 2, ""); 
+  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[3] == 3, ""); 
+  static_assert(from_vector8BitInt128_to_vector8BitInt128_var[4] == 4, "");
 }
 
 namespace shufflevector {
@@ -890,14 +890,14 @@ namespace shufflevector {
   constexpr vector8char vectorShuffle6 = __builtin_shufflevector(
       vector4charConst1, vector4charConst2, 0, 2, 4, 6, 1, 3, 5, 7);
 
-  static_assert(vectorShuffle6[0] == 0, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[1] == 2, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[2] == 4, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[3] == 6, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[4] == 1, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[5] == 3, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[6] == 5, "");// ref-error {{not an integral constant expression}}
-  static_assert(vectorShuffle6[7] == 7, "");// ref-error {{not an integral constant expression}}
+  static_assert(vectorShuffle6[0] == 0, "");
+  static_assert(vectorShuffle6[1] == 2, "");
+  static_assert(vectorShuffle6[2] == 4, "");
+  static_assert(vectorShuffle6[3] == 6, "");
+  static_assert(vectorShuffle6[4] == 1, "");
+  static_assert(vectorShuffle6[5] == 3, "");
+  static_assert(vectorShuffle6[6] == 5, "");
+  static_assert(vectorShuffle6[7] == 7, "");
 
   constexpr vector4char  vectorShuffleFail1 = __builtin_shufflevector( // both-error {{must be initialized by a constant expression}}\
                                                                        // ref-error {{index for __builtin_shufflevector not within the bounds of the input vectors; index of -1 found at position 0 is not permitted in a constexpr context}}
diff --git a/clang/test/AST/Interp/vectors.cpp b/clang/test/AST/Interp/vectors.cpp
index 6991a348b07a9..b6a9579f67ee2 100644
--- a/clang/test/AST/Interp/vectors.cpp
+++ b/clang/test/AST/Interp/vectors.cpp
@@ -3,25 +3,25 @@
 
 typedef int __attribute__((vector_size(16))) VI4;
 constexpr VI4 A = {1,2,3,4};
-static_assert(A[0] == 1, ""); // ref-error {{not an integral constant expression}}
-static_assert(A[1] == 2, ""); // ref-error {{not an integral constant expression}}
-static_assert(A[2] == 3, ""); // ref-error {{not an integral constant expression}}
-static_assert(A[3] == 4, ""); // ref-error {{not an integral constant expression}}
+static_assert(A[0] == 1, "");
+static_assert(A[1] == 2, "");
+static_assert(A[2] == 3, "");
+static_assert(A[3] == 4, "");
 
 
 /// FIXME: It would be nice if the note said 'vector' instead of 'array'.
-static_assert(A[12] == 4, ""); // ref-error {{not an integral constant expression}} \
-                               // expected-error {{not an integral constant expression}} \
-                               // expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}}
+static_assert(A[12] == 4, ""); // both-error {{not an integral constant expression}} \
+                               // expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}} \
+                               // ref-note {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
 
 
 /// VectorSplat casts
 typedef __attribute__(( ext_vector_type(4) )) float float4;
 constexpr float4 vec4_0 = (float4)0.5f;
-static_assert(vec4_0[0] == 0.5, ""); // ref-error {{not an integral constant expression}}
-static_assert(vec4_0[1] == 0.5, ""); // ref-error {{not an integral constant expression}}
-static_assert(vec4_0[2] == 0.5, ""); // ref-error {{not an integral constant expression}}
-static_assert(vec4_0[3] == 0.5, ""); // ref-error {{not an integral constant expression}}
+static_assert(vec4_0[0] == 0.5, "");
+static_assert(vec4_0[1] == 0.5, "");
+static_assert(vec4_0[2] == 0.5, "");
+static_assert(vec4_0[3] == 0.5, "");
 constexpr int vec4_0_discarded = ((float4)12.0f, 0);
 
 
@@ -29,14 +29,14 @@ constexpr int vec4_0_discarded = ((float4)12.0f, 0);
 constexpr float4 arr4[2] = {
   {1,2,3,4},
 };
-static_assert(arr4[0][0] == 1, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[0][1] == 2, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[0][2] == 3, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[0][3] == 4, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
-static_assert(arr4[1][0] == 0, ""); // ref-error {{not an integral constant expression}}
+static_assert(arr4[0][0] == 1, "");
+static_assert(arr4[0][1] == 2, "");
+static_assert(arr4[0][2] == 3, "");
+static_assert(arr4[0][3] == 4, "");
+static_assert(arr4[1][0] == 0, "");
+static_assert(arr4[1][0] == 0, "");
+static_assert(arr4[1][0] == 0, "");
+static_assert(arr4[1][0] == 0, "");
 
 
 /// From constant-expression-cxx11.cpp
@@ -65,10 +65,10 @@ namespace {
 namespace BoolToSignedIntegralCast{
   typedef __attribute__((__ext_vector_type__(4))) unsigned int int4;
   constexpr int4 intsT = (int4)true;
-  static_assert(intsT[0] == -1, "");// ref-error {{not an integral constant expression}}
-  static_assert(intsT[1] == -1, "");// ref-error {{not an integral constant expression}}
-  static_assert(intsT[2] == -1, "");// ref-error {{not an integral constant expression}}
-  static_assert(intsT[3] == -1, "");// ref-error {{not an integral constant expression}}
+  static_assert(intsT[0] == -1, "");
+  static_assert(intsT[1] == -1, "");
+  static_assert(intsT[2] == -1, "");
+  static_assert(intsT[3] == -1, "");
 }
 
 namespace VectorElementExpr {
@@ -78,8 +78,8 @@ namespace VectorElementExpr {
   static_assert(oneElt == 3);
 
   constexpr int2 twoElts = ((int4){11, 22, 33, 44}).yz;
-  static_assert(twoElts.x == 22, ""); // ref-error {{not an integral constant expression}}
-  static_assert(twoElts.y == 33, ""); // ref-error {{not an integral constant expression}}
+  static_assert(twoElts.x == 22, "");
+  static_assert(twoElts.y == 33, "");
 }
 
 namespace Temporaries {
diff --git a/clang/test/CodeGenCXX/temporaries.cpp b/clang/test/CodeGenCXX/temporaries.cpp
index 9f697bd9bf3ef..0990c804b8bcf 100644
--- a/clang/test/CodeGenCXX/temporaries.cpp
+++ b/clang/test/CodeGenCXX/temporaries.cpp
@@ -64,6 +64,26 @@ namespace RefTempSubobject {
   constexpr const SelfReferential &sr = SelfReferential();
 }
 
+namespace Vector {
+  typedef __attribute__((vector_size(16))) int vi4a;
+  typedef __attribute__((ext_vector_type(4))) int vi4b;
+  struct S {
+    vi4a v;
+    vi4b w;
+  };
+
+  int &&r = S().v[1];
+  // CHECK: @_ZGRN6Vector1rE_ = internal global i32 0, align 4
+  // CHECK: @_ZN6Vector1rE = constant ptr @_ZGRN6Vector1rE_, align 8
+
+  int &&s = S().w[1];
+  // CHECK: @_ZGRN6Vector1sE_ = internal global i32 0, align 4
+  // CHECK: @_ZN6Vector1sE = constant ptr @_ZGRN6Vector1sE_, align 8
+
+  int &&t = S().w.y;
+  // CHECK: @_ZGRN6Vector1tE_ = internal global i32 0, align 4
+  // CHECK: @_ZN6Vector1tE = constant ptr @_ZGRN6Vector1tE_, align 8
+}
 struct A {
   A();
   ~A();
@@ -665,27 +685,6 @@ namespace Bitfield {
   int &&r = S().a;
 }
 
-namespace Vector {
-  typedef __attribute__((vector_size(16))) int vi4a;
-  typedef __attribute__((ext_vector_type(4))) int vi4b;
-  struct S {
-    vi4a v;
-    vi4b w;
-  };
-  // CHECK: alloca
-  // CHECK: extractelement
-  // CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1rE_
-  // CHECK: store ptr @_ZGRN6Vector1rE_, ptr @_ZN6Vector1rE,
-  int &&r = S().v[1];
-
-  // CHECK: alloca
-  // CHECK: extractelement
-  // CHECK: store i32 {{.*}}, ptr @_ZGRN6Vector1sE_
-  // CHECK: store ptr @_ZGRN6Vector1sE_, ptr @_ZN6Vector1sE,
-  int &&s = S().w[1];
-  int &&ss = S().w.y;
-}
-
 namespace ImplicitTemporaryCleanup {
   struct A { A(int); ~A(); };
   void g();
diff --git a/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp b/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp
new file mode 100644
index 0000000000000..d31db4c496840
--- /dev/null
+++ b/clang/test/SemaCXX/constexpr-vectors-access-elements.cpp
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -Wno-uninitialized -std=c++17 -fsyntax-only -verify
+
+namespace Vector {
+
+using TwoIntsVecSize __attribute__((vector_size(8))) = int;
+
+constexpr TwoIntsVecSize a = {1,2};
+static_assert(a[1] == 2);
+static_assert(a[2]); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+
+}
+
+namespace ExtVector {
+
+using FourIntsExtVec __attribute__((ext_vector_type(4))) = int;
+
+constexpr FourIntsExtVec b = {1,2,3,4};
+static_assert(b[0] == 1 && b[1] == 2 && b[2] == 3 && b[3] == 4);
+static_assert(b.s0 == 1 && b.s1 == 2 && b.s2 == 3 && b.s3 == 4);
+static_assert(b.x == 1 && b.y == 2 && b.z == 3 && b.w == 4);
+static_assert(b.r == 1 && b.g == 2 && b.b == 3 && b.a == 4);
+static_assert(b[5]); // expected-error {{not an integral constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+
+// FIXME: support selecting multiple elements
+static_assert(b.lo.lo == 1); // expected-error {{not an integral constant expression}}
+// static_assert(b.lo.lo==1 && b.lo.hi==2 && b.hi.lo == 3 && b.hi.hi == 4);
+// static_assert(b.odd[0]==1 && b.odd[1]==2 && b.even[0] == 3 && b.even[1] == 4);
+
+}

// expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}}
static_assert(A[12] == 4, ""); // both-error {{not an integral constant expression}} \
// expected-note {{cannot refer to element 12 of array of 4 elements in a constant expression}} \
// ref-note {{read of dereferenced one-past-the-end pointer is not allowed in a constant expression}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this note is being generated? I don't see how A[12] is a one-past-the-end pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just kept the original version of the PR, but the message "cannot refer to element 12 of array of 4 elements" seems correct here. I shall update this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done, let me know if the updated changes are okay

Copy link
Collaborator

@shafik shafik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working to get this PR finished up. I see at least two comments from the previous PR not addressed here. Please, let's try and get those addressed.

@AaronBallman wanted a test to make sure we reject &V[0] which I don't see: #72607 (comment)


void addVectorElementUnchecked(QualType EltTy, uint64_t Size,
uint64_t Idx) {
Entries.push_back(PathEntry::ArrayIndex(Idx));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sethp had a comment in the previous PR that is not address here: #72607 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I thought about having a new accessor of the sort "vectorIndex" but all it seems to achieve is just adding new API that returns does the exact same thing as array (other than perhaps adding a new meaning to PathEntry value). I will update it if you feel this makes sense.

static_assert(A[0] == 1, "");
static_assert(A[1] == 2, "");
static_assert(A[2] == 3, "");
static_assert(A[3] == 4, "");


/// FIXME: It would be nice if the note said 'vector' instead of 'array'.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolving this fixme comment would be a nice follow-up.

@tbaederr
Copy link
Contributor

tbaederr commented Aug 5, 2024

If nobody else still has concerns, this LGTM from my end.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@tbaederr
Copy link
Contributor

tbaederr commented Aug 7, 2024

@vikramRH Do you need someone else to merge this for you?

Copy link
Contributor Author

vikramRH commented Aug 7, 2024

Merge activity

@vikramRH vikramRH merged commit 7753429 into main Aug 7, 2024
8 checks passed
@vikramRH vikramRH deleted the users/vikramRH/vector_constexpr branch August 7, 2024 10:41
@vikramRH
Copy link
Contributor Author

vikramRH commented Aug 7, 2024

@vikramRH Do you need someone else to merge this for you?

sorry for the delay, merged.

searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Aug 23, 2024
… constant expression (llvm#101126)

This is a slightly updated version of llvm#72607,

originally authored by @yuanfang-chen

Change-Id: Ifdf143d4d766b076bf3010048ab121932c83bb1e
searlmc1 pushed a commit to ROCm/llvm-project that referenced this pull request Nov 22, 2024
… constant expression (llvm#101126)

This is a slightly updated version of llvm#72607,

originally authored by @yuanfang-chen

Change-Id: Id9f94ebb5ce74e853ad9704c97170a128bfd2bc9
@ahatanak
Copy link
Collaborator

clang crashes compiling the following code.

typedef float float4 __attribute__((ext_vector_type(4)));
constexpr float4 v{1,2,3,4};
constexpr const float4 *p = &v;
constexpr float f = p->x;

I created a PR that fixes the crash: #136771

@ziqingluo-90
Copy link
Contributor

typedef __attribute__((__ext_vector_type__(2))) float float2;

struct vec2 {
    float2 _v;
public:
    constexpr vec2(float x, float y) {
       _v.x = x;
       _v.y = y;
    }
};

constexpr struct vec2 f() {
  return vec2(1.0, 1.0);
}

int main() {
    vec2 S = f();
}

Clang crashes: https://godbolt.org/z/sx74s1bqd

@AaronBallman
Copy link
Collaborator

typedef __attribute__((__ext_vector_type__(2))) float float2;

struct vec2 {
    float2 _v;
public:
    constexpr vec2(float x, float y) {
       _v.x = x;
       _v.y = y;
    }
};

constexpr struct vec2 f() {
  return vec2(1.0, 1.0);
}

int main() {
    vec2 S = f();
}

Clang crashes: https://godbolt.org/z/sx74s1bqd

Can confirm the crash is happening. The issue is related to the constructor being constexpr and not initializing the member variable. If you use a member initializer list, the assert is silenced: https://godbolt.org/z/vEbeb4jbz

Can you file an issue so we don't lose track of the bug? Also @vikramRH any chance you can look into this?

@ziqingluo-90
Copy link
Contributor

Can you file an issue so we don't lose track of the bug?
Looks like we have an issue already #140348

@AaronBallman do you think my original example is well-defined according to the standard? I saw there is a warning
constexpr constructor that does not initialize all members is a C++20 extension [-Wc++20-extensions].

@tbaederr
Copy link
Contributor

It's well defined, even if only after c++20. It should work fine, but the root of the problem is pre-existing (which is why it also fails with complex values).

@vikramRH
Copy link
Contributor Author

@AaronBallman @tbaederr I can look into this, shall i assign #84315 to myself ?

@AaronBallman
Copy link
Collaborator

@AaronBallman @tbaederr I can look into this, shall i assign #84315 to myself ?

Yup! FWIW, we don't require assignments in GitHub issue, you're always welcome to post a PR even if an issue isn't assigned to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants