[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:
Sam McCall
2021-08-02 15:56:00 +02:00
parent ed67d5a03a
commit 09f8315bba
2 changed files with 92 additions and 3 deletions

View File

@@ -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;

View File

@@ -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'
}