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