[clang] Do not crash on arrow operator on dependent type.
authorAdam Czachorowski <adamcz@google.com>
Wed, 16 Mar 2022 13:27:27 +0000 (14:27 +0100)
committerAdam Czachorowski <adamcz@google.com>
Fri, 25 Mar 2022 14:48:08 +0000 (15:48 +0100)
There seems to be more than one way to get to that state. I included to
example cases in the test, both were noticed recently.

There is room for improvement, for example by creating RecoveryExpr in
place of the bad initializer, but for now let's stop the crashes.

Differential Revision: https://reviews.llvm.org/D121824

clang/lib/Sema/TreeTransform.h
clang/test/SemaCXX/arrow-operator.cpp

index fb830ef..1ee457b 100644 (file)
@@ -14757,6 +14757,10 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
       return getSema().CreateBuiltinArraySubscriptExpr(
           First, Callee->getBeginLoc(), Second, OpLoc);
   } else if (Op == OO_Arrow) {
+    // It is possible that the type refers to a RecoveryExpr created earlier
+    // in the tree transformation.
+    if (First->getType()->isDependentType())
+      return ExprError();
     // -> is never a builtin operation.
     return SemaRef.BuildOverloadedArrowExpr(nullptr, First, OpLoc);
   } else if (Second == nullptr || isPostIncDec) {
index 3e32a6b..c6d2a99 100644 (file)
@@ -65,3 +65,51 @@ void test() {
 }
 
 } // namespace arrow_suggest
+
+namespace no_crash_dependent_type {
+
+template <class T>
+struct A {
+  void call();
+  A *operator->();
+};
+
+template <class T>
+void foo() {
+  // The "requires an initializer" error seems unnecessary.
+  A<int> &x = blah[7]; // expected-error {{use of undeclared identifier 'blah'}} \
+                        // expected-error {{requires an initializer}}
+  // x is dependent.
+  x->call();
+}
+
+void test() {
+  foo<int>(); // expected-note {{requested here}}
+}
+
+} // namespace no_crash_dependent_type
+
+namespace clangd_issue_1073_no_crash_dependent_type {
+
+template <typename T> struct Ptr {
+  T *operator->();
+};
+
+struct Struct {
+  int len;
+};
+
+template <int>
+struct TemplateStruct {
+  Ptr<Struct> val(); // expected-note {{declared here}}
+};
+
+template <int I>
+void templateFunc(const TemplateStruct<I> &ts) {
+  Ptr<Struct> ptr = ts.val(); // expected-error {{function is not marked const}}
+  auto foo = ptr->len;
+}
+
+template void templateFunc<0>(const TemplateStruct<0> &); // expected-note {{requested here}}
+
+} // namespace clangd_issue_1073_no_crash_dependent_type