[clang] [clang] Substitute alias templates from correct context (PR #75069)

Mariya Podchishchaeva via cfe-commits cfe-commits at lists.llvm.org
Mon Dec 11 08:41:23 PST 2023


https://github.com/Fznamznon created https://github.com/llvm/llvm-project/pull/75069

Current context set to where alias was met, not where it is declared caused incorrect access check in case alias referenced private members of the parent class.
This is a recommit of 6b1aa31 with a slight modification in order to fix reported regression.

Fixes https://github.com/llvm/llvm-project/issues/41693

>From d0bfa140bdfa2be213151d4d17263bb60e6b46d3 Mon Sep 17 00:00:00 2001
From: "Podchishchaeva, Mariya" <mariya.podchishchaeva at intel.com>
Date: Mon, 11 Dec 2023 08:31:15 -0800
Subject: [PATCH] [clang] Substitute alias templates from correct context

Current context set to where alias was met, not where it is declared caused
incorrect access check in case alias referenced private members of the parent
class.
This is a recommit of 6b1aa31 with a slight modification in order to fix
reported regression.

Fixes https://github.com/llvm/llvm-project/issues/41693
---
 clang/docs/ReleaseNotes.rst                   |  3 +
 clang/include/clang/Sema/Sema.h               |  2 +-
 clang/lib/Sema/SemaCXXScopeSpec.cpp           | 24 +++++--
 clang/lib/Sema/SemaTemplate.cpp               | 16 ++++-
 .../CXX/temp/temp.decls/temp.alias/p3.cpp     |  5 +-
 clang/test/SemaCXX/alias-template.cpp         | 65 +++++++++++++++++++
 6 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b4b5352a306c1c..1d460ae8375e88 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -677,6 +677,9 @@ Bug Fixes in This Version
   (`#62157 <https://github.com/llvm/llvm-project/issues/62157>`_) and
   (`#64885 <https://github.com/llvm/llvm-project/issues/64885>`_) and
   (`#65568 <https://github.com/llvm/llvm-project/issues/65568>`_)
+- Fixed false positive error emitted when templated alias inside a class
+  used private members of the same class.
+  Fixes (`#41693 <https://github.com/llvm/llvm-project/issues/41693>`_)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f45e0a7d3d52d4..d8f4b01ee455f1 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8738,7 +8738,7 @@ class Sema final {
                              SourceLocation IILoc,
                              bool DeducedTSTContext = true);
 
-
+  bool RebuildingTypesInCurrentInstantiation = false;
   TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
                                                     SourceLocation Loc,
                                                     DeclarationName Name);
diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp
index 44a40215b90dfb..b3b19b7ed7ffff 100644
--- a/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -30,6 +30,20 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
     return nullptr;
 
   const Type *Ty = T->getCanonicalTypeInternal().getTypePtr();
+  if (isa<TemplateSpecializationType>(Ty)) {
+    if (auto *Record = dyn_cast<CXXRecordDecl>(CurContext)) {
+      if (isa<ClassTemplatePartialSpecializationDecl>(Record) ||
+          Record->getDescribedClassTemplate()) {
+        const Type *ICNT = Record->getTypeForDecl();
+        QualType Injected =
+            cast<InjectedClassNameType>(ICNT)->getInjectedSpecializationType();
+
+        if (Ty == Injected->getCanonicalTypeInternal().getTypePtr())
+          return Record;
+      }
+    }
+  }
+
   if (const RecordType *RecordTy = dyn_cast<RecordType>(Ty)) {
     CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
     if (!Record->isDependentContext() ||
@@ -37,10 +51,12 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T,
       return Record;
 
     return nullptr;
-  } else if (isa<InjectedClassNameType>(Ty))
-    return cast<InjectedClassNameType>(Ty)->getDecl();
-  else
-    return nullptr;
+  }
+
+  if (auto *ICNT = dyn_cast<InjectedClassNameType>(Ty))
+    return ICNT->getDecl();
+
+  return nullptr;
 }
 
 /// Compute the DeclContext that is associated with the given type.
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index f10abeaba0d451..810a93f37d74e0 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -39,6 +39,7 @@
 #include "llvm/ADT/SmallBitVector.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 #include <iterator>
 #include <optional>
@@ -3990,9 +3991,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
     if (Inst.isInvalid())
       return QualType();
 
-    CanonType = SubstType(Pattern->getUnderlyingType(),
-                          TemplateArgLists, AliasTemplate->getLocation(),
-                          AliasTemplate->getDeclName());
+    if (!RebuildingTypesInCurrentInstantiation) {
+      Sema::ContextRAII SavedContext(*this, Pattern->getDeclContext());
+      CanonType =
+          SubstType(Pattern->getUnderlyingType(), TemplateArgLists,
+                    AliasTemplate->getLocation(), AliasTemplate->getDeclName());
+    } else {
+      CanonType =
+          SubstType(Pattern->getUnderlyingType(), TemplateArgLists,
+                    AliasTemplate->getLocation(), AliasTemplate->getDeclName());
+    }
     if (CanonType.isNull()) {
       // If this was enable_if and we failed to find the nested type
       // within enable_if in a SFINAE context, dig out the specific
@@ -11392,6 +11400,8 @@ TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
   if (!T || !T->getType()->isInstantiationDependentType())
     return T;
 
+  llvm::SaveAndRestore DisableContextSwitchForTypeAliases(
+      RebuildingTypesInCurrentInstantiation, true);
   CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
   return Rebuilder.TransformType(T);
 }
diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp
index 2d46502e1d9b35..2b33a4ef566dad 100644
--- a/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp
@@ -2,11 +2,12 @@
 
 // The example given in the standard (this is rejected for other reasons anyway).
 template<class T> struct A;
-template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<T>'}}
+template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<short>'}}
+                                              // expected-note at -1 {{in instantiation of template class 'A<short>' requested here}}
 template<class T> struct A {
   typedef B<T> U; // expected-note {{in instantiation of template type alias 'B' requested here}}
 };
-B<short> b;
+B<short> b; // expected-note {{in instantiation of template type alias 'B' requested here}}
 
 template<typename T> using U = int;
 
diff --git a/clang/test/SemaCXX/alias-template.cpp b/clang/test/SemaCXX/alias-template.cpp
index 5189405e23db56..dca63e15f5bb8a 100644
--- a/clang/test/SemaCXX/alias-template.cpp
+++ b/clang/test/SemaCXX/alias-template.cpp
@@ -192,3 +192,68 @@ int g = sfinae_me<int>(); // expected-error{{no matching function for call to 's
 namespace NullExceptionDecl {
 template<int... I> auto get = []() { try { } catch(...) {}; return I; }; // expected-error{{initializer contains unexpanded parameter pack 'I'}}
 }
+
+namespace GH41693 {
+// No errors when a type alias defined in a class or a friend of a class
+// accesses private members of the same class.
+struct S {
+private:
+  template <typename> static constexpr void Impl() {}
+
+public:
+  template <typename X> using U = decltype(Impl<X>());
+};
+
+using X = S::U<void>;
+struct Y {
+private:
+  static constexpr int x=0;
+
+  template <typename>
+  static constexpr int y=0;
+
+  template <typename>
+  static constexpr int foo();
+
+public:
+  template <typename U>
+  using bar1 = decltype(foo<U>());
+  using bar2 = decltype(x);
+  template <typename U>
+  using bar3 = decltype(y<U>);
+};
+
+
+using type1 = Y::bar1<float>;
+using type2 = Y::bar2;
+using type3 = Y::bar3<float>;
+
+struct theFriend{
+  template<class T>
+  using theAlias = decltype(&T::i);
+};
+
+class theC{
+  int i;
+  public:
+  friend struct theFriend;
+};
+
+int foo(){
+  (void)sizeof(theFriend::theAlias<theC>);
+}
+
+// Test case that regressed with the first iteration of the fix for GH41693.
+template <typename T> class SP {
+    T* data;
+};
+
+template <typename T> class A {
+    static SP<A> foo();
+};
+
+template<typename T> using TRet = SP<A<T>>;
+
+template<typename T> TRet<T> A<T>::foo() { return TRet<T>{};};
+
+}



More information about the cfe-commits mailing list