diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4645,6 +4645,38 @@ return isa(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()) + Result = PT->getPointeeType(); + else if (const ArrayType *AT = LTy->getAsArrayTypeUnsafe()) + Result = AT->getElementType(); + } else if (LTy->isIntegralOrUnscopedEnumerationType()) { + if (const PointerType *PT = RTy->getAs()) + 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 @@ // 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 @@ if (LHSTy->isDependentType() || RHSTy->isDependentType()) { BaseExpr = LHSExp; IndexExpr = RHSExp; - ResultType = Context.DependentTy; + ResultType = + getDependentArraySubscriptType(LHSExp, RHSExp, getASTContext()); } else if (const PointerType *PTy = LHSTy->getAs()) { BaseExpr = LHSExp; IndexExpr = RHSExp; diff --git a/clang/test/AST/ast-dump-array.cpp b/clang/test/AST/ast-dump-array.cpp --- a/clang/test/AST/ast-dump-array.cpp +++ b/clang/test/AST/ast-dump-array.cpp @@ -26,3 +26,58 @@ using const_array_T_size = const T[Size]; // CHECK: `-DependentSizedArrayType 0x{{[^ ]*}} 'const T[Size]' dependent }; + +struct V {}; +template +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]]{{.*}} '' + b[i]; + // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '' + + V *a2; + V b2[5]; + + // LHS is a known array, RHS is type-dependent. + a2[i]; + // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '' + b2[i]; + // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '' + + // 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]]{{.*}} '' + b2[One]; + // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} '' + + 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]]{{.*}} '' + + U b4[N]; + // LHS is an array with dependent bounds and dependent elements. + b4[0]; + // CHECK: ArraySubscriptExpr {{.*}}line:[[@LINE-1]]{{.*}} 'U' +}