[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