diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -202,6 +202,9 @@ - Fix crash when evaluating consteval constructor of derived class whose base has more than one field. (`#60166 `_) +- Fix an issue about ``decltype`` in the members of class templates derived from + templates with related parameters. + (`#58674 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2803,6 +2803,21 @@ R.addDecl(FoundDecl); R.resolveKind(); + if (getSema().isUnevaluatedContext() && Base->isImplicitCXXThis() && + isa(Member)) { + if (auto *ThisClass = cast(Base) + ->getType() + ->getPointeeType() + ->getAsCXXRecordDecl()) { + auto *Class = cast(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, diff --git a/clang/test/CodeGenCXX/decl-ref-inheritance.cpp b/clang/test/CodeGenCXX/decl-ref-inheritance.cpp new file mode 100644 --- /dev/null +++ b/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 struct bar : T { +}; + +struct baz : bar { + // 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 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 q; + +// CHECK-3: [[BASE:%.+]] = type { i32 } +class Base { +protected: + int member; +}; + +template +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; + +int use() { + Impl i; + return i.func(); +} diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp --- a/clang/test/SemaCXX/decltype.cpp +++ b/clang/test/SemaCXX/decltype.cpp @@ -101,6 +101,44 @@ template void foo(decltype(T(LP1{ .p1 = g1, .p1.x[1] = 'x' }))) {} } +namespace GH58674 { + struct Foo { + float value_; + struct nested { + float value_; + }; + }; + + template + struct TemplateFoo { + float value_; + }; + + float bar; + + template + struct Animal{}; + + template + class Cat : Animal { + using okay = decltype(Foo::value_); + using also_okay = decltype(bar); + using okay2 = decltype(Foo::nested::value_); + using okay3 = decltype(TemplateFoo::value_); + public: + void meow() { + using okay = decltype(Foo::value_); + using also_okay = decltype(bar); + using okay2 = decltype(Foo::nested::value_); + using okay3 = decltype(TemplateFoo::value_); + } + }; + + void baz() { + Cat{}.meow(); + } +} + template class conditional { };