Skip to content

Commit

Permalink
[clang] Substitute alias templates from correct context (#75069)
Browse files Browse the repository at this point in the history
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 #41693
  • Loading branch information
Fznamznon committed Dec 13, 2023
1 parent a110e99 commit dbf67ea
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 10 deletions.
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8737,7 +8737,7 @@ class Sema final {
SourceLocation IILoc,
bool DeducedTSTContext = true);


bool RebuildingTypesInCurrentInstantiation = false;
TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T,
SourceLocation Loc,
DeclarationName Name);
Expand Down
24 changes: 20 additions & 4 deletions clang/lib/Sema/SemaCXXScopeSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,33 @@ 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() ||
Record->isCurrentInstantiation(CurContext))
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.
Expand Down
14 changes: 11 additions & 3 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 3 additions & 2 deletions clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
65 changes: 65 additions & 0 deletions clang/test/SemaCXX/alias-template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>{};};

}

0 comments on commit dbf67ea

Please sign in to comment.