[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
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user