diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 066e4ac5b9e54b..05d59d0da264f3 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -685,6 +685,9 @@ Bug Fixes in This Version (`#62157 `_) and (`#64885 `_) and (`#65568 `_) +- Fixed false positive error emitted when templated alias inside a class + used private members of the same class. + Fixes (`#41693 `_) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 1d7b4c729ce84e..7e89e74733a090 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8737,7 +8737,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(Ty)) { + if (auto *Record = dyn_cast(CurContext)) { + if (isa(Record) || + Record->getDescribedClassTemplate()) { + const Type *ICNT = Record->getTypeForDecl(); + QualType Injected = + cast(ICNT)->getInjectedSpecializationType(); + + if (Ty == Injected->getCanonicalTypeInternal().getTypePtr()) + return Record; + } + } + } + if (const RecordType *RecordTy = dyn_cast(Ty)) { CXXRecordDecl *Record = cast(RecordTy->getDecl()); if (!Record->isDependentContext() || @@ -37,10 +51,12 @@ static CXXRecordDecl *getCurrentInstantiationOf(QualType T, return Record; return nullptr; - } else if (isa(Ty)) - return cast(Ty)->getDecl(); - else - return nullptr; + } + + if (auto *ICNT = dyn_cast(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..cca7d613061564 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 #include @@ -3990,9 +3991,14 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Inst.isInvalid()) return QualType(); - CanonType = SubstType(Pattern->getUnderlyingType(), - TemplateArgLists, AliasTemplate->getLocation(), - AliasTemplate->getDeclName()); + { + Sema::ContextRAII SavedContext(*this, Pattern->getDeclContext()); + if (RebuildingTypesInCurrentInstantiation) + SavedContext.pop(); + 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 +11398,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 struct A; -template using B = typename A::U; // expected-error {{no type named 'U' in 'A'}} +template using B = typename A::U; // expected-error {{no type named 'U' in 'A'}} + // expected-note@-1 {{in instantiation of template class 'A' requested here}} template struct A { typedef B U; // expected-note {{in instantiation of template type alias 'B' requested here}} }; -B b; +B b; // expected-note {{in instantiation of template type alias 'B' requested here}} template 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(); // expected-error{{no matching function for call to 's namespace NullExceptionDecl { template 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 static constexpr void Impl() {} + +public: + template using U = decltype(Impl()); +}; + +using X = S::U; +struct Y { +private: + static constexpr int x=0; + + template + static constexpr int y=0; + + template + static constexpr int foo(); + +public: + template + using bar1 = decltype(foo()); + using bar2 = decltype(x); + template + using bar3 = decltype(y); +}; + + +using type1 = Y::bar1; +using type2 = Y::bar2; +using type3 = Y::bar3; + +struct theFriend{ + template + using theAlias = decltype(&T::i); +}; + +class theC{ + int i; + public: + friend struct theFriend; +}; + +int foo(){ + (void)sizeof(theFriend::theAlias); +} + +// Test case that regressed with the first iteration of the fix for GH41693. +template class SP { + T* data; +}; + +template class A { + static SP foo(); +}; + +template using TRet = SP>; + +template TRet A::foo() { return TRet{};}; + +}