зеркало из https://github.com/microsoft/clang-1.git
When starting a C++ member access expression, make sure to compute the
type of the object even when it is dependent. Specifically, this makes sure that we get the right type for "this->", which is important when performing name lookup into this scope to determine whether an identifier or operator-function-id is a template name. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86060 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
655fe9b0d9
Коммит
43d8863df9
|
@ -22,6 +22,72 @@
|
|||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace clang;
|
||||
|
||||
/// \brief Find the current instantiation that associated with the given type.
|
||||
static CXXRecordDecl *
|
||||
getCurrentInstantiationOf(ASTContext &Context, DeclContext *CurContext,
|
||||
QualType T) {
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
T = Context.getCanonicalType(T);
|
||||
|
||||
for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
|
||||
// If we've hit a namespace or the global scope, then the
|
||||
// nested-name-specifier can't refer to the current instantiation.
|
||||
if (Ctx->isFileContext())
|
||||
return 0;
|
||||
|
||||
// Skip non-class contexts.
|
||||
CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
|
||||
if (!Record)
|
||||
continue;
|
||||
|
||||
// If this record type is not dependent,
|
||||
if (!Record->isDependentType())
|
||||
return 0;
|
||||
|
||||
// C++ [temp.dep.type]p1:
|
||||
//
|
||||
// In the definition of a class template, a nested class of a
|
||||
// class template, a member of a class template, or a member of a
|
||||
// nested class of a class template, a name refers to the current
|
||||
// instantiation if it is
|
||||
// -- the injected-class-name (9) of the class template or
|
||||
// nested class,
|
||||
// -- in the definition of a primary class template, the name
|
||||
// of the class template followed by the template argument
|
||||
// list of the primary template (as described below)
|
||||
// enclosed in <>,
|
||||
// -- in the definition of a nested class of a class template,
|
||||
// the name of the nested class referenced as a member of
|
||||
// the current instantiation, or
|
||||
// -- in the definition of a partial specialization, the name
|
||||
// of the class template followed by the template argument
|
||||
// list of the partial specialization enclosed in <>. If
|
||||
// the nth template parameter is a parameter pack, the nth
|
||||
// template argument is a pack expansion (14.6.3) whose
|
||||
// pattern is the name of the parameter pack.
|
||||
// (FIXME: parameter packs)
|
||||
//
|
||||
// All of these options come down to having the
|
||||
// nested-name-specifier type that is equivalent to the
|
||||
// injected-class-name of one of the types that is currently in
|
||||
// our context.
|
||||
if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
|
||||
return Record;
|
||||
|
||||
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
|
||||
QualType InjectedClassName
|
||||
= Template->getInjectedClassNameType(Context);
|
||||
if (T == Context.getCanonicalType(InjectedClassName))
|
||||
return Template->getTemplatedDecl();
|
||||
}
|
||||
// FIXME: check for class template partial specializations
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \brief Compute the DeclContext that is associated with the given type.
|
||||
///
|
||||
/// \param T the type for which we are attempting to find a DeclContext.
|
||||
|
@ -33,7 +99,7 @@ DeclContext *Sema::computeDeclContext(QualType T) {
|
|||
if (const TagType *Tag = T->getAs<TagType>())
|
||||
return Tag->getDecl();
|
||||
|
||||
return 0;
|
||||
return ::getCurrentInstantiationOf(Context, CurContext, T);
|
||||
}
|
||||
|
||||
/// \brief Compute the DeclContext that is associated with the given
|
||||
|
@ -156,68 +222,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
|
|||
return 0;
|
||||
|
||||
QualType T = QualType(NNS->getAsType(), 0);
|
||||
// If the nested name specifier does not refer to a type, then it
|
||||
// does not refer to the current instantiation.
|
||||
if (T.isNull())
|
||||
return 0;
|
||||
|
||||
T = Context.getCanonicalType(T);
|
||||
|
||||
for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getParent()) {
|
||||
// If we've hit a namespace or the global scope, then the
|
||||
// nested-name-specifier can't refer to the current instantiation.
|
||||
if (Ctx->isFileContext())
|
||||
return 0;
|
||||
|
||||
// Skip non-class contexts.
|
||||
CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx);
|
||||
if (!Record)
|
||||
continue;
|
||||
|
||||
// If this record type is not dependent,
|
||||
if (!Record->isDependentType())
|
||||
return 0;
|
||||
|
||||
// C++ [temp.dep.type]p1:
|
||||
//
|
||||
// In the definition of a class template, a nested class of a
|
||||
// class template, a member of a class template, or a member of a
|
||||
// nested class of a class template, a name refers to the current
|
||||
// instantiation if it is
|
||||
// -- the injected-class-name (9) of the class template or
|
||||
// nested class,
|
||||
// -- in the definition of a primary class template, the name
|
||||
// of the class template followed by the template argument
|
||||
// list of the primary template (as described below)
|
||||
// enclosed in <>,
|
||||
// -- in the definition of a nested class of a class template,
|
||||
// the name of the nested class referenced as a member of
|
||||
// the current instantiation, or
|
||||
// -- in the definition of a partial specialization, the name
|
||||
// of the class template followed by the template argument
|
||||
// list of the partial specialization enclosed in <>. If
|
||||
// the nth template parameter is a parameter pack, the nth
|
||||
// template argument is a pack expansion (14.6.3) whose
|
||||
// pattern is the name of the parameter pack.
|
||||
// (FIXME: parameter packs)
|
||||
//
|
||||
// All of these options come down to having the
|
||||
// nested-name-specifier type that is equivalent to the
|
||||
// injected-class-name of one of the types that is currently in
|
||||
// our context.
|
||||
if (Context.getCanonicalType(Context.getTypeDeclType(Record)) == T)
|
||||
return Record;
|
||||
|
||||
if (ClassTemplateDecl *Template = Record->getDescribedClassTemplate()) {
|
||||
QualType InjectedClassName
|
||||
= Template->getInjectedClassNameType(Context);
|
||||
if (T == Context.getCanonicalType(InjectedClassName))
|
||||
return Template->getTemplatedDecl();
|
||||
}
|
||||
// FIXME: check for class template partial specializations
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ::getCurrentInstantiationOf(Context, CurContext, T);
|
||||
}
|
||||
|
||||
/// \brief Require that the context specified by SS be complete.
|
||||
|
|
|
@ -2030,7 +2030,13 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
|
||||
QualType BaseType = BaseExpr->getType();
|
||||
if (BaseType->isDependentType()) {
|
||||
// FIXME: member of the current instantiation
|
||||
// If we have a pointer to a dependent type and are using the -> operator,
|
||||
// the object type is the type that the pointer points to. We might still
|
||||
// have enough information about that type to do something useful.
|
||||
if (OpKind == tok::arrow)
|
||||
if (const PointerType *Ptr = BaseType->getAs<PointerType>())
|
||||
BaseType = Ptr->getPointeeType();
|
||||
|
||||
ObjectType = BaseType.getAsOpaquePtr();
|
||||
return move(Base);
|
||||
}
|
||||
|
|
|
@ -93,3 +93,13 @@ void f(X4<X3<int> > x4i) {
|
|||
X2<sizeof(int)> x2;
|
||||
x4i.f<X2<sizeof(int)> >(x2);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct X5 {
|
||||
template<typename U>
|
||||
void f();
|
||||
|
||||
void g() {
|
||||
this->f<T*>();
|
||||
}
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче