Handle substitutions into the "first qualifier in scope" of a

qualified member access expression (e.g., t->U::member) when that
first qualifier refers to a template parameters.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84612 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2009-10-20 05:58:46 +00:00
Родитель 8f99993856
Коммит 6cd219879f
3 изменённых файлов: 49 добавлений и 7 удалений

Просмотреть файл

@ -400,6 +400,10 @@ namespace {
/// instantiating it.
Decl *TransformDefinition(Decl *D);
/// \bried Transform the first qualifier within a scope by instantiating the
/// declaration.
NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc);
/// \brief Rebuild the exception declaration and register the declaration
/// as an instantiated local.
VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T,
@ -457,6 +461,31 @@ Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
return Inst;
}
NamedDecl *
TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
SourceLocation Loc) {
// If the first part of the nested-name-specifier was a template type
// parameter, instantiate that type parameter down to a tag type.
if (TemplateTypeParmDecl *TTPD = dyn_cast_or_null<TemplateTypeParmDecl>(D)) {
const TemplateTypeParmType *TTP
= cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD));
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType();
if (T.isNull())
return cast_or_null<NamedDecl>(TransformDecl(D));
if (const TagType *Tag = T->getAs<TagType>())
return Tag->getDecl();
// The resulting type is not a tag; complain.
getSema().Diag(Loc, diag::err_nested_name_spec_non_tag) << T;
return 0;
}
}
return cast_or_null<NamedDecl>(TransformDecl(D));
}
VarDecl *
TemplateInstantiator::RebuildExceptionDecl(VarDecl *ExceptionDecl,
QualType T,

Просмотреть файл

@ -236,6 +236,19 @@ public:
/// Subclasses may override this function to provide alternate behavior.
Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); }
/// \brief Transform the given declaration, which was the first part of a
/// nested-name-specifier in a member access expression.
///
/// This specific declaration transformation only applies to the first
/// identifier in a nested-name-specifier of a member access expression, e.g.,
/// the \c T in \c x->T::member
///
/// By default, invokes TransformDecl() to transform the declaration.
/// Subclasses may override this function to provide alternate behavior.
NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc) {
return cast_or_null<NamedDecl>(getDerived().TransformDecl(D));
}
/// \brief Transform the given nested-name-specifier.
///
/// By default, transforms all of the types and declarations within the
@ -4195,6 +4208,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
if (Base.isInvalid())
return SemaRef.ExprError();
// Start the member reference and compute the object's type.
Sema::TypeTy *ObjectType = 0;
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
E->getOperatorLoc(),
@ -4203,12 +4217,12 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
if (Base.isInvalid())
return SemaRef.ExprError();
// FIXME: The first qualifier found might be a template type parameter,
// in which case there is no transformed declaration to refer to (it might
// refer to a built-in type!).
// Transform the first part of the nested-name-specifier that qualifies
// the member name.
NamedDecl *FirstQualifierInScope
= cast_or_null<NamedDecl>(
getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
= getDerived().TransformFirstQualifierInScope(
E->getFirstQualifierFoundInScope(),
E->getQualifierRange().getBegin());
NestedNameSpecifier *Qualifier = 0;
if (E->getQualifier()) {

Просмотреть файл

@ -24,8 +24,7 @@ struct XDerived : public X {
};
void test_f1(XDerived xd) {
// FIXME: Not quite functional yet.
// int &ir = f1<X>(xd);
int &ir = f1<X>(xd);
}
// PR5213