[clang] Fix canonical type of vector types w.r.t. qualified element type. (PR #197624)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 13 23:16:28 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Michele Scandale (michele-scandale)
<details>
<summary>Changes</summary>
This commit changes the way canonical vector types are constructed to ensure that qualifiers on the element type are moved to the vector type iself -- i.e. a canonical vector type has always a unqualified element type.
RFC: https://discourse.llvm.org/t/90783
---
Full diff: https://github.com/llvm/llvm-project/pull/197624.diff
4 Files Affected:
- (modified) clang/lib/AST/ASTContext.cpp (+62-60)
- (modified) clang/lib/Sema/SemaTypeTraits.cpp (+4-2)
- (modified) clang/test/Sema/types.c (+12)
- (modified) clang/test/SemaCXX/vector.cpp (+14)
``````````diff
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index a0894318dbd53..2c9e852817b7a 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -4654,11 +4654,13 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
- // If the element type isn't canonical, this won't be a canonical type either,
- // so fill in the canonical type field.
+ // If the element type isn't canonical or has qualifiers, this won't be a
+ // canonical type either, so fill in the canonical type field.
QualType Canonical;
- if (!vecType.isCanonical()) {
- Canonical = getVectorType(getCanonicalType(vecType), NumElts, VecKind);
+ if (!vecType.isCanonical() || vecType.hasLocalQualifiers()) {
+ SplitQualType canonSplit = getCanonicalType(vecType).split();
+ Canonical = getVectorType(QualType(canonSplit.Ty, 0), NumElts, VecKind);
+ Canonical = getQualifiedType(Canonical, canonSplit.Quals);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -4674,37 +4676,36 @@ QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts,
QualType ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr,
SourceLocation AttrLoc,
VectorKind VecKind) const {
+ SplitQualType CanonVecType = getCanonicalType(VecType).split();
+
llvm::FoldingSetNodeID ID;
- DependentVectorType::Profile(ID, *this, getCanonicalType(VecType), SizeExpr,
- VecKind);
+ DependentVectorType::Profile(ID, *this, QualType(CanonVecType.Ty, 0),
+ SizeExpr, VecKind);
void *InsertPos = nullptr;
DependentVectorType *Canon =
DependentVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- DependentVectorType *New;
- if (Canon) {
- New = new (*this, alignof(DependentVectorType)) DependentVectorType(
- VecType, QualType(Canon, 0), SizeExpr, AttrLoc, VecKind);
- } else {
- QualType CanonVecTy = getCanonicalType(VecType);
- if (CanonVecTy == VecType) {
- New = new (*this, alignof(DependentVectorType))
- DependentVectorType(VecType, QualType(), SizeExpr, AttrLoc, VecKind);
-
- DependentVectorType *CanonCheck =
- DependentVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CanonCheck &&
- "Dependent-sized vector_size canonical type broken");
- (void)CanonCheck;
- DependentVectorTypes.InsertNode(New, InsertPos);
- } else {
- QualType CanonTy = getDependentVectorType(CanonVecTy, SizeExpr,
- SourceLocation(), VecKind);
- New = new (*this, alignof(DependentVectorType))
- DependentVectorType(VecType, CanonTy, SizeExpr, AttrLoc, VecKind);
- }
+ // If we don't have one, build one.
+ if (!Canon) {
+ Canon = new (*this, TypeAlignment) DependentVectorType(
+ QualType(CanonVecType.Ty, 0), QualType(), SizeExpr, AttrLoc, VecKind);
+ DependentVectorTypes.InsertNode(Canon, InsertPos);
+ Types.push_back(Canon);
}
+ // Apply qualifiers from the element type to the vector.
+ QualType CanonTy = getQualifiedType(QualType(Canon, 0), CanonVecType.Quals);
+
+ // If we didn't need extra canonicalization for the element type or the size
+ // expression, then just use that as our result.
+ if (QualType(CanonVecType.Ty, 0) == VecType &&
+ Canon->getSizeExpr() == SizeExpr)
+ return CanonTy;
+
+ // Otherwise, we need to build a type which follows the spelling
+ // of the element type.
+ auto *New = new (*this, TypeAlignment)
+ DependentVectorType(VecType, CanonTy, SizeExpr, AttrLoc, VecKind);
Types.push_back(New);
return QualType(New, 0);
}
@@ -4726,11 +4727,13 @@ QualType ASTContext::getExtVectorType(QualType vecType,
if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos))
return QualType(VTP, 0);
- // If the element type isn't canonical, this won't be a canonical type either,
- // so fill in the canonical type field.
+ // If the element type isn't canonical or has qualifiers, this won't be a
+ // canonical type either, so fill in the canonical type field.
QualType Canonical;
- if (!vecType.isCanonical()) {
- Canonical = getExtVectorType(getCanonicalType(vecType), NumElts);
+ if (!vecType.isCanonical() || vecType.hasLocalQualifiers()) {
+ SplitQualType canonSplit = getCanonicalType(vecType).split();
+ Canonical = getExtVectorType(QualType(canonSplit.Ty, 0), NumElts);
+ Canonical = getQualifiedType(Canonical, canonSplit.Quals);
// Get the new insert position for the node we care about.
VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos);
@@ -4744,42 +4747,41 @@ QualType ASTContext::getExtVectorType(QualType vecType,
}
QualType
-ASTContext::getDependentSizedExtVectorType(QualType vecType,
- Expr *SizeExpr,
+ASTContext::getDependentSizedExtVectorType(QualType VecType, Expr *SizeExpr,
SourceLocation AttrLoc) const {
+ assert(VecKind == VectorType::GenericVector ||
+ VecKind == VectorType::PackedVector);
+
+ SplitQualType CanonVecType = getCanonicalType(VecType).split();
+
llvm::FoldingSetNodeID ID;
- DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType),
+ DependentSizedExtVectorType::Profile(ID, *this, QualType(CanonVecType.Ty, 0),
SizeExpr);
-
void *InsertPos = nullptr;
DependentSizedExtVectorType *Canon
= DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- DependentSizedExtVectorType *New;
- if (Canon) {
- // We already have a canonical version of this array type; use it as
- // the canonical type for a newly-built type.
- New = new (*this, alignof(DependentSizedExtVectorType))
- DependentSizedExtVectorType(vecType, QualType(Canon, 0), SizeExpr,
- AttrLoc);
- } else {
- QualType CanonVecTy = getCanonicalType(vecType);
- if (CanonVecTy == vecType) {
- New = new (*this, alignof(DependentSizedExtVectorType))
- DependentSizedExtVectorType(vecType, QualType(), SizeExpr, AttrLoc);
-
- DependentSizedExtVectorType *CanonCheck
- = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos);
- assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken");
- (void)CanonCheck;
- DependentSizedExtVectorTypes.InsertNode(New, InsertPos);
- } else {
- QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr,
- SourceLocation());
- New = new (*this, alignof(DependentSizedExtVectorType))
- DependentSizedExtVectorType(vecType, CanonExtTy, SizeExpr, AttrLoc);
- }
+
+ // If we don't have one, build one.
+ if (!Canon) {
+ Canon = new (*this, TypeAlignment) DependentSizedExtVectorType(
+ QualType(CanonVecType.Ty, 0), QualType(), SizeExpr, AttrLoc);
+ DependentSizedExtVectorTypes.InsertNode(Canon, InsertPos);
+ Types.push_back(Canon);
}
+ // Apply qualifiers from the element type to the vector.
+ QualType CanonTy = getQualifiedType(QualType(Canon, 0), CanonVecType.Quals);
+
+ // If we didn't need extra canonicalization for the element type or the size
+ // expression, then just use that as our result.
+ if (QualType(CanonVecType.Ty, 0) == VecType &&
+ Canon->getSizeExpr() == SizeExpr)
+ return CanonTy;
+
+ // Otherwise, we need to build a type which follows the spelling
+ // of the element type.
+ auto *New = new (*this, TypeAlignment)
+ DependentSizedExtVectorType(VecType, CanonTy, SizeExpr, AttrLoc);
Types.push_back(New);
return QualType(New, 0);
}
diff --git a/clang/lib/Sema/SemaTypeTraits.cpp b/clang/lib/Sema/SemaTypeTraits.cpp
index c79b3f7045ca6..ee89f5a20a289 100644
--- a/clang/lib/Sema/SemaTypeTraits.cpp
+++ b/clang/lib/Sema/SemaTypeTraits.cpp
@@ -1625,8 +1625,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT,
case BTT_TypeCompatible: {
// GCC ignores cv-qualifiers on arrays for this builtin.
Qualifiers LhsQuals, RhsQuals;
- QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(LhsT, LhsQuals);
- QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(RhsT, RhsQuals);
+ QualType Lhs = Self.getASTContext().getUnqualifiedArrayType(
+ LhsT.getCanonicalType(), LhsQuals);
+ QualType Rhs = Self.getASTContext().getUnqualifiedArrayType(
+ RhsT.getCanonicalType(), RhsQuals);
return Self.Context.typesAreCompatible(Lhs, Rhs);
}
case BTT_IsConvertible:
diff --git a/clang/test/Sema/types.c b/clang/test/Sema/types.c
index 2be0e6544f3d7..21ee2feabc965 100644
--- a/clang/test/Sema/types.c
+++ b/clang/test/Sema/types.c
@@ -75,6 +75,18 @@ typedef int __attribute__((ext_vector_type(0x100000000))) e2; // expected-e
typedef int __attribute__((vector_size((__int128_t)1 << 100))) e3; // expected-error {{vector size too large}}
typedef int __attribute__((ext_vector_type(0))) e4; // expected-error {{zero vector size}}
+typedef const int cint;
+typedef int __attribute__((vector_size(16))) vec4_int;
+typedef cint __attribute__((vector_size(16))) vec4_cint;
+_Static_assert(__builtin_types_compatible_p(vec4_int, const vec4_int), "'vec4_int' and 'const vec4_int' are not compatible");
+_Static_assert(__builtin_types_compatible_p(vec4_int, volatile vec4_int), "'vec4_int' and 'const vec4_int' are not compatible");
+_Static_assert(__builtin_types_compatible_p(const vec4_int, vec4_cint), "'const vec4_int' and 'vec4_cint' are not compatible");
+typedef int __attribute__((ext_vector_type(4))) ext_vec4_int;
+typedef cint __attribute__((ext_vector_type(4))) ext_vec4_cint;
+_Static_assert(__builtin_types_compatible_p(ext_vec4_int, const ext_vec4_int), "'ext_vec4_int' and 'const ext_vec4_int' are not compatible");
+_Static_assert(__builtin_types_compatible_p(ext_vec4_int, volatile ext_vec4_int), "'ext_vec4_int' and 'const ext_vec4_int' are not compatible");
+_Static_assert(__builtin_types_compatible_p(const ext_vec4_int, ext_vec4_cint), "'const ext_vec4_int' and 'ext_vec4_cint' are not compatible'");
+
// no support for vector enum type
enum { e_2 } x3 __attribute__((vector_size(64))); // expected-error {{invalid vector element type}}
diff --git a/clang/test/SemaCXX/vector.cpp b/clang/test/SemaCXX/vector.cpp
index 355d93a2b8cee..ef91848c7d31a 100644
--- a/clang/test/SemaCXX/vector.cpp
+++ b/clang/test/SemaCXX/vector.cpp
@@ -817,3 +817,17 @@ namespace GH173347 {
typedef short __attribute__((__vector_size__(8))) V;
template <int N> V test(V x) { return (x % 5) * N; }
}
+
+namespace test_canonical_quals {
+typedef const int cint;
+typedef int __attribute__((vector_size(16))) vec4_int;
+typedef cint __attribute__((vector_size(16))) vec4_cint;
+_Static_assert(!__is_same(vec4_int, const vec4_int), "'vec4_int' and 'const vec4_int' are not different");
+_Static_assert(!__is_same(vec4_int, volatile vec4_int), "'vec4_int' and 'const vec4_int' are not different");
+_Static_assert(__is_same(const vec4_int, vec4_cint), "'const vec4_int' and 'vec4_cint' are different");
+typedef int __attribute__((ext_vector_type(4))) ext_vec4_int;
+typedef cint __attribute__((ext_vector_type(4))) ext_vec4_cint;
+_Static_assert(!__is_same(ext_vec4_int, const ext_vec4_int), "'ext_vec4_int' and 'const ext_vec4_int' are not different");
+_Static_assert(!__is_same(ext_vec4_int, volatile ext_vec4_int), "'ext_vec4_int' and 'const ext_vec4_int' are not different");
+_Static_assert(__is_same(const ext_vec4_int, ext_vec4_cint), "'const ext_vec4_int' and 'ext_vec4_cint' are different");
+} // namespace test_canonical_quals
``````````
</details>
https://github.com/llvm/llvm-project/pull/197624
More information about the cfe-commits
mailing list