[clang] 09f8315 - [Sema] a[x] has type T when a has type T* or T[], even when T is dependent
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 30 16:30:49 PST 2021
Author: Sam McCall
Date: 2021-12-31T01:30:39+01:00
New Revision: 09f8315bba391eac1dbdfbdc3fd654c0c0cbe3e7
URL: https://github.com/llvm/llvm-project/commit/09f8315bba391eac1dbdfbdc3fd654c0c0cbe3e7
DIFF: https://github.com/llvm/llvm-project/commit/09f8315bba391eac1dbdfbdc3fd654c0c0cbe3e7.diff
LOG: [Sema] a[x] has type T when a has type T* or T[], even when T is dependent
This more precise type is useful for tools, e.g.
fixes https://github.com/clangd/clangd/issues/831
Differential Revision: https://reviews.llvm.org/D107275
Added:
Modified:
clang/lib/Sema/SemaExpr.cpp
clang/test/AST/ast-dump-array.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 736e76152fe48..d454e4877bcef 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4645,6 +4645,38 @@ static bool isMSPropertySubscriptExpr(Sema &S, Expr *Base) {
return isa<MSPropertySubscriptExpr>(BaseNoParens);
}
+// Returns the type used for LHS[RHS], given one of LHS, RHS is type-dependent.
+// Typically this is DependentTy, but can sometimes be more precise.
+//
+// There are cases when we could determine a non-dependent type:
+// - LHS and RHS may have non-dependent types despite being type-dependent
+// (e.g. unbounded array static members of the current instantiation)
+// - one may be a dependent-sized array with known element type
+// - one may be a dependent-typed valid index (enum in current instantiation)
+//
+// We *always* return a dependent type, in such cases it is DependentTy.
+// This avoids creating type-dependent expressions with non-dependent types.
+// FIXME: is this important to avoid? See https://reviews.llvm.org/D107275
+static QualType getDependentArraySubscriptType(Expr *LHS, Expr *RHS,
+ const ASTContext &Ctx) {
+ assert(LHS->isTypeDependent() || RHS->isTypeDependent());
+ QualType LTy = LHS->getType(), RTy = RHS->getType();
+ QualType Result = Ctx.DependentTy;
+ if (RTy->isIntegralOrUnscopedEnumerationType()) {
+ if (const PointerType *PT = LTy->getAs<PointerType>())
+ Result = PT->getPointeeType();
+ else if (const ArrayType *AT = LTy->getAsArrayTypeUnsafe())
+ Result = AT->getElementType();
+ } else if (LTy->isIntegralOrUnscopedEnumerationType()) {
+ if (const PointerType *PT = RTy->getAs<PointerType>())
+ Result = PT->getPointeeType();
+ else if (const ArrayType *AT = RTy->getAsArrayTypeUnsafe())
+ Result = AT->getElementType();
+ }
+ // Ensure we return a dependent type.
+ return Result->isDependentType() ? Result : Ctx.DependentTy;
+}
+
ExprResult
Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
Expr *idx, SourceLocation rbLoc) {
@@ -4737,8 +4769,9 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc,
// Build an unanalyzed expression if either operand is type-dependent.
if (getLangOpts().CPlusPlus &&
(base->isTypeDependent() || idx->isTypeDependent())) {
- return new (Context) ArraySubscriptExpr(base, idx, Context.DependentTy,
- VK_LValue, OK_Ordinary, rbLoc);
+ return new (Context) ArraySubscriptExpr(
+ base, idx, getDependentArraySubscriptType(base, idx, getASTContext()),
+ VK_LValue, OK_Ordinary, rbLoc);
}
// MSDN, property (C++)
@@ -5492,7 +5525,8 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc,
if (LHSTy->isDependentType() || RHSTy->isDependentType()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
- ResultType = Context.DependentTy;
+ ResultType =
+ getDependentArraySubscriptType(LHSExp, RHSExp, getASTContext());
} else if (const PointerType *PTy = LHSTy->getAs<PointerType>()) {
BaseExpr = LHSExp;
IndexExpr = RHSExp;
diff --git a/clang/test/AST/ast-dump-array.cpp b/clang/test/AST/ast-dump-array.cpp
index 609ad31a0e420..418e4292680ee 100644
--- a/clang/test/AST/ast-dump-array.cpp
+++ b/clang/test/AST/ast-dump-array.cpp
@@ -26,3 +26,58 @@ class array {
using const_array_T_size = const T[Size];
// CHECK: `-DependentSizedArrayType 0x{{[^ ]*}} 'const T[Size]' dependent <col:37, col:42>
};
+
+struct V {};
+template <typename U, typename Idx, int N>
+void testDependentSubscript() {
+ U* a;
+ U b[5];
+ Idx i{};
+ enum E { One = 1 };
+
+ // Can types of subscript expressions can be determined?
+ // LHS is a type-dependent array, RHS is a known integer type.
+ a[1];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U'
+ b[1];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U'
+
+ // Reverse case: RHS is a type-dependent array, LHS is an integer.
+ 1[a];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U'
+ 1[b];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U'
+
+ // LHS is a type-dependent array, RHS is type-dependent.
+ a[i];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+ b[i];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+
+ V *a2;
+ V b2[5];
+
+ // LHS is a known array, RHS is type-dependent.
+ a2[i];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+ b2[i];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+
+ // LHS is a known array, RHS is a type-dependent index.
+ // We know the element type is V, but insist on some dependent type.
+ a2[One];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+ b2[One];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+
+ V b3[N];
+ // LHS is an array with dependent bounds but known elements.
+ // We insist on a dependent type.
+ b3[0];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '<dependent type>'
+
+ U b4[N];
+ // LHS is an array with dependent bounds and dependent elements.
+ b4[0];
+ // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U'
+}
More information about the cfe-commits
mailing list