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

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.

Fixes https://github.com/llvm/llvm-project/issues/41693
This commit is contained in:
Mariya Podchishchaeva
2023-12-06 13:14:17 +03:00
committed by GitHub
parent 6ed7a8eae6
commit 6b1aa31975
5 changed files with 85 additions and 8 deletions

View File

@@ -658,6 +658,9 @@ Bug Fixes in This Version
Fixes (`#64467 <https://github.com/llvm/llvm-project/issues/64467>`_)
- Clang's ``-Wchar-subscripts`` no longer warns on chars whose values are known non-negative constants.
Fixes (`#18763 <https://github.com/llvm/llvm-project/issues/18763>`_)
- 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

View File

@@ -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))
}
if (isa<InjectedClassNameType>(Ty))
return cast<InjectedClassNameType>(Ty)->getDecl();
else
return nullptr;
return nullptr;
}
/// Compute the DeclContext that is associated with the given type.

View File

@@ -3990,9 +3990,16 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
if (Inst.isInvalid())
return QualType();
CanonType = SubstType(Pattern->getUnderlyingType(),
TemplateArgLists, AliasTemplate->getLocation(),
AliasTemplate->getDeclName());
{
bool ForLambdaCallOperator = false;
if (const auto *Rec = dyn_cast<CXXRecordDecl>(Pattern->getDeclContext()))
ForLambdaCallOperator = Rec->isLambda();
Sema::ContextRAII SavedContext(*this, Pattern->getDeclContext(),
!ForLambdaCallOperator);
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

View File

@@ -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@-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;

View File

@@ -192,3 +192,53 @@ 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 {
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>);
}
}