зеркало из 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"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
using namespace clang;
|
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.
|
/// \brief Compute the DeclContext that is associated with the given type.
|
||||||
///
|
///
|
||||||
/// \param T the type for which we are attempting to find a DeclContext.
|
/// \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>())
|
if (const TagType *Tag = T->getAs<TagType>())
|
||||||
return Tag->getDecl();
|
return Tag->getDecl();
|
||||||
|
|
||||||
return 0;
|
return ::getCurrentInstantiationOf(Context, CurContext, T);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Compute the DeclContext that is associated with the given
|
/// \brief Compute the DeclContext that is associated with the given
|
||||||
|
@ -156,68 +222,7 @@ CXXRecordDecl *Sema::getCurrentInstantiationOf(NestedNameSpecifier *NNS) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
QualType T = QualType(NNS->getAsType(), 0);
|
QualType T = QualType(NNS->getAsType(), 0);
|
||||||
// If the nested name specifier does not refer to a type, then it
|
return ::getCurrentInstantiationOf(Context, CurContext, T);
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Require that the context specified by SS be complete.
|
/// \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();
|
QualType BaseType = BaseExpr->getType();
|
||||||
if (BaseType->isDependentType()) {
|
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();
|
ObjectType = BaseType.getAsOpaquePtr();
|
||||||
return move(Base);
|
return move(Base);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,3 +93,13 @@ void f(X4<X3<int> > x4i) {
|
||||||
X2<sizeof(int)> x2;
|
X2<sizeof(int)> x2;
|
||||||
x4i.f<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*>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче