lime created this revision.
lime added reviewers: aaron.ballman, cor3ntin, erichkeane, clang-language-wg.
lime added projects: All, clang, clang-language-wg.
lime requested review of this revision.
Herald added a subscriber: cfe-commits.

This patch replace member accesses to declaration references during template
instantiation if the context is the unevaluated context and the class does not
contain the declaration.

The replacement fixes the issue #58674. Unlike previous fixes such as D143840 
<https://reviews.llvm.org/D143840>,
it checks the membership during instantiation rather than right after parsing,
so the check is more accurate and efficient.

This patch also includes cases that previous fixes had once failed on.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D145491

Files:
  clang/docs/ReleaseNotes.rst
  clang/lib/Sema/TreeTransform.h
  clang/test/CodeGenCXX/decl-ref-inheritance.cpp
  clang/test/SemaCXX/decltype.cpp

Index: clang/test/SemaCXX/decltype.cpp
===================================================================
--- clang/test/SemaCXX/decltype.cpp
+++ clang/test/SemaCXX/decltype.cpp
@@ -101,6 +101,44 @@
   template<class T> void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {}
 }
 
+namespace GH58674 {
+  struct Foo {
+    float value_;
+    struct nested {
+      float value_;
+    };
+  };
+
+  template <typename T>
+  struct TemplateFoo {
+    float value_;
+  };
+
+  float bar;
+
+  template <typename T>
+  struct Animal{};
+
+  template <typename T>
+  class Cat : Animal<T> {
+    using okay = decltype(Foo::value_);
+    using also_okay = decltype(bar);
+    using okay2 = decltype(Foo::nested::value_);
+    using okay3 = decltype(TemplateFoo<T>::value_);
+  public:
+    void meow() {
+      using okay = decltype(Foo::value_);
+      using also_okay = decltype(bar);
+      using okay2 = decltype(Foo::nested::value_);
+      using okay3 = decltype(TemplateFoo<T>::value_);
+    }
+  };
+
+  void baz() {
+      Cat<void>{}.meow();
+  }
+}
+
 template<typename>
 class conditional {
 };
Index: clang/test/CodeGenCXX/decl-ref-inheritance.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGenCXX/decl-ref-inheritance.cpp
@@ -0,0 +1,60 @@
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck \
+// RUN: -check-prefix=CHECK-1 %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck \
+// RUN: -check-prefix=CHECK-2 %s
+// RUN: %clang_cc1 -triple=x86_64-unknown-linux -emit-llvm %s -o - | FileCheck \
+// RUN: -check-prefix=CHECK-3 %s
+
+// CHECK-1: [[FOO:%.+]] = type { float }
+struct foo {
+  float val;
+};
+
+template <typename T> struct bar : T {
+};
+
+struct baz : bar<foo> {
+  // CHECK-1: define{{.*}} float @_ZN3baz3getEv
+  // CHECK-1: {{%.+}} = getelementptr inbounds [[FOO]], ptr {{%.+}}, i32 0, i32 0
+  float get() {
+    return val;
+  }
+};
+
+int qux() {
+  auto f = baz{};
+  return f.get();
+}
+
+// CHECK-2: [[F:%.+]] = type { ptr }
+struct f {
+  void *g;
+};
+
+template <typename j> struct k : j {
+  // CHECK-2: define{{.*}} void @_ZN1kI1fE1lEv
+  // CHECK-2: {{%.+}} = getelementptr inbounds [[F]], ptr {{%.+}}, i32 0, i32 0
+  virtual void l(){ (void)f::g; }
+};
+
+k<f> q;
+
+// CHECK-3: [[BASE:%.+]] = type { i32 }
+class Base {
+protected:
+  int member;
+};
+
+template <typename Parent>
+struct Subclass : public Parent {
+  // CHECK-3: define{{.*}} i32 @_ZN8SubclassI4BaseE4funcEv
+  // CHECK-3: {{%.+}} = getelementptr inbounds [[BASE]], ptr {{%.+}}, i32 0, i32 0
+  int func() { return Base::member; }
+};
+
+using Impl = Subclass<Base>;
+
+int use() {
+  Impl i;
+  return i.func();
+}
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -2803,6 +2803,21 @@
     R.addDecl(FoundDecl);
     R.resolveKind();
 
+    if (getSema().isUnevaluatedContext() && Base->isImplicitCXXThis() &&
+        isa<FieldDecl, IndirectFieldDecl, MSPropertyDecl>(Member)) {
+      if (auto ThisClass = cast<CXXThisExpr>(Base)
+                               ->getType()
+                               ->getPointeeType()
+                               ->getAsCXXRecordDecl()) {
+        auto Class = cast<CXXRecordDecl>(Member->getDeclContext());
+        // In unevaluated contexts, an expression supposed to be a member access
+        // might reference a member in an unrelated class.
+        if (!ThisClass->Equals(Class) && !ThisClass->isDerivedFrom(Class))
+          return getSema().BuildDeclRefExpr(Member, Member->getType(),
+                                            VK_LValue, Member->getLocation());
+      }
+    }
+
     return getSema().BuildMemberReferenceExpr(Base, BaseType, OpLoc, isArrow,
                                               SS, TemplateKWLoc,
                                               FirstQualifierInScope,
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -194,6 +194,9 @@
 - Fix crash when evaluating consteval constructor of derived class whose base
   has more than one field.
   (`#60166 <https://github.com/llvm/llvm-project/issues/60166>`_)
+- Fix an issue about ``decltype`` in the members of class templates derived from
+  templates with related parameters.
+  (`#58674 <https://github.com/llvm/llvm-project/issues/58674>`_)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to