forked from OSchip/llvm-project
Improve template instantiation for member access expressions that
involve qualified names, e.g., x->Base::f. We now maintain enough information in the AST to compare the results of the name lookup of "Base" in the scope of the postfix-expression (determined at template definition time) and in the type of the object expression. llvm-svn: 80953
This commit is contained in:
parent
59a1cd4a06
commit
2b6ca46c6b
|
@ -1306,6 +1306,15 @@ class CXXUnresolvedMemberExpr : public Expr {
|
||||||
/// \brief The source range covering the nested name specifier.
|
/// \brief The source range covering the nested name specifier.
|
||||||
SourceRange QualifierRange;
|
SourceRange QualifierRange;
|
||||||
|
|
||||||
|
/// \brief In a qualified member access expression such as t->Base::f, this
|
||||||
|
/// member stores the resolves of name lookup in the context of the member
|
||||||
|
/// access expression, to be used at instantiation time.
|
||||||
|
///
|
||||||
|
/// FIXME: This member, along with the Qualifier and QualifierRange, could
|
||||||
|
/// be stuck into a structure that is optionally allocated at the end of
|
||||||
|
/// the CXXUnresolvedMemberExpr, to save space in the common case.
|
||||||
|
NamedDecl *FirstQualifierFoundInScope;
|
||||||
|
|
||||||
/// \brief The member to which this member expression refers, which
|
/// \brief The member to which this member expression refers, which
|
||||||
/// can be name, overloaded operator, or destructor.
|
/// can be name, overloaded operator, or destructor.
|
||||||
/// FIXME: could also be a template-id
|
/// FIXME: could also be a template-id
|
||||||
|
@ -1320,11 +1329,13 @@ public:
|
||||||
SourceLocation OperatorLoc,
|
SourceLocation OperatorLoc,
|
||||||
NestedNameSpecifier *Qualifier,
|
NestedNameSpecifier *Qualifier,
|
||||||
SourceRange QualifierRange,
|
SourceRange QualifierRange,
|
||||||
|
NamedDecl *FirstQualifierFoundInScope,
|
||||||
DeclarationName Member,
|
DeclarationName Member,
|
||||||
SourceLocation MemberLoc)
|
SourceLocation MemberLoc)
|
||||||
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
||||||
Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
|
Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
|
||||||
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
||||||
|
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
|
||||||
Member(Member), MemberLoc(MemberLoc) { }
|
Member(Member), MemberLoc(MemberLoc) { }
|
||||||
|
|
||||||
/// \brief Retrieve the base object of this member expressions,
|
/// \brief Retrieve the base object of this member expressions,
|
||||||
|
@ -1349,6 +1360,21 @@ public:
|
||||||
/// that qualifies the member name.
|
/// that qualifies the member name.
|
||||||
SourceRange getQualifierRange() const { return QualifierRange; }
|
SourceRange getQualifierRange() const { return QualifierRange; }
|
||||||
|
|
||||||
|
/// \brief Retrieve the first part of the nested-name-specifier that was
|
||||||
|
/// found in the scope of the member access expression when the member access
|
||||||
|
/// was initially parsed.
|
||||||
|
///
|
||||||
|
/// This function only returns a useful result when member access expression
|
||||||
|
/// uses a qualified member name, e.g., "x.Base::f". Here, the declaration
|
||||||
|
/// returned by this function describes what was found by unqualified name
|
||||||
|
/// lookup for the identifier "Base" within the scope of the member access
|
||||||
|
/// expression itself. At template instantiation time, this information is
|
||||||
|
/// combined with the results of name lookup into the type of the object
|
||||||
|
/// expression itself (the class type of x).
|
||||||
|
NamedDecl *getFirstQualifierFoundInScope() const {
|
||||||
|
return FirstQualifierFoundInScope;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the name of the member that this expression
|
/// \brief Retrieve the name of the member that this expression
|
||||||
/// refers to.
|
/// refers to.
|
||||||
DeclarationName getMember() const { return Member; }
|
DeclarationName getMember() const { return Member; }
|
||||||
|
|
|
@ -1610,13 +1610,15 @@ public:
|
||||||
SourceLocation MemberLoc,
|
SourceLocation MemberLoc,
|
||||||
DeclarationName MemberName,
|
DeclarationName MemberName,
|
||||||
DeclPtrTy ImplDecl,
|
DeclPtrTy ImplDecl,
|
||||||
const CXXScopeSpec *SS = 0) {
|
const CXXScopeSpec *SS = 0,
|
||||||
|
NamedDecl *FirstQualifierInScope = 0) {
|
||||||
// FIXME: Temporary helper while we migrate existing calls to
|
// FIXME: Temporary helper while we migrate existing calls to
|
||||||
// BuildMemberReferenceExpr to support explicitly-specified template
|
// BuildMemberReferenceExpr to support explicitly-specified template
|
||||||
// arguments.
|
// arguments.
|
||||||
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
|
return BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, MemberLoc,
|
||||||
MemberName, false, SourceLocation(), 0, 0,
|
MemberName, false, SourceLocation(), 0, 0,
|
||||||
SourceLocation(), ImplDecl, SS);
|
SourceLocation(), ImplDecl, SS,
|
||||||
|
FirstQualifierInScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
|
OwningExprResult BuildMemberReferenceExpr(Scope *S, ExprArg Base,
|
||||||
|
@ -1630,7 +1632,8 @@ public:
|
||||||
unsigned NumExplicitTemplateArgs,
|
unsigned NumExplicitTemplateArgs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
DeclPtrTy ImplDecl,
|
DeclPtrTy ImplDecl,
|
||||||
const CXXScopeSpec *SS = 0);
|
const CXXScopeSpec *SS,
|
||||||
|
NamedDecl *FirstQualifierInScope = 0);
|
||||||
|
|
||||||
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
|
virtual OwningExprResult ActOnMemberReferenceExpr(Scope *S, ExprArg Base,
|
||||||
SourceLocation OpLoc,
|
SourceLocation OpLoc,
|
||||||
|
@ -2047,12 +2050,18 @@ public:
|
||||||
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
|
||||||
SourceLocation CCLoc);
|
SourceLocation CCLoc);
|
||||||
|
|
||||||
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
|
NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
|
||||||
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
|
|
||||||
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
|
|
||||||
/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
|
CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
|
||||||
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
|
const CXXScopeSpec &SS,
|
||||||
/// Returns a CXXScopeTy* object representing the C++ scope.
|
SourceLocation IdLoc,
|
||||||
|
SourceLocation CCLoc,
|
||||||
|
IdentifierInfo &II,
|
||||||
|
QualType ObjectType,
|
||||||
|
NamedDecl *ScopeLookupResult,
|
||||||
|
bool EnteringContext);
|
||||||
|
|
||||||
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
|
virtual CXXScopeTy *ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
const CXXScopeSpec &SS,
|
const CXXScopeSpec &SS,
|
||||||
SourceLocation IdLoc,
|
SourceLocation IdLoc,
|
||||||
|
|
|
@ -288,18 +288,45 @@ bool isAcceptableNestedNameSpecifier(ASTContext &Context, NamedDecl *SD) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
|
/// \brief If the given nested-name-specifier begins with a bare identifier
|
||||||
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
|
/// (e.g., Base::), perform name lookup for that identifier as a
|
||||||
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
|
/// nested-name-specifier within the given scope, and return the result of that
|
||||||
/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
|
/// name lookup.
|
||||||
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
|
NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) {
|
||||||
/// Returns a CXXScopeTy* object representing the C++ scope.
|
if (!S || !NNS)
|
||||||
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
return 0;
|
||||||
|
|
||||||
|
while (NNS->getPrefix())
|
||||||
|
NNS = NNS->getPrefix();
|
||||||
|
|
||||||
|
if (NNS->getKind() != NestedNameSpecifier::Identifier)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
LookupResult Found
|
||||||
|
= LookupName(S, NNS->getAsIdentifier(), LookupNestedNameSpecifierName);
|
||||||
|
assert(!Found.isAmbiguous() && "Cannot handle ambiguities here yet");
|
||||||
|
|
||||||
|
NamedDecl *Result = Found;
|
||||||
|
if (isAcceptableNestedNameSpecifier(Context, Result))
|
||||||
|
return Result;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Build a new nested-name-specifier for "identifier::", as described
|
||||||
|
/// by ActOnCXXNestedNameSpecifier.
|
||||||
|
///
|
||||||
|
/// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
|
||||||
|
/// that it contains an extra parameter \p ScopeLookupResult, which provides
|
||||||
|
/// the result of name lookup within the scope of the nested-name-specifier
|
||||||
|
/// that was computed at template definitino time.
|
||||||
|
Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
|
||||||
const CXXScopeSpec &SS,
|
const CXXScopeSpec &SS,
|
||||||
SourceLocation IdLoc,
|
SourceLocation IdLoc,
|
||||||
SourceLocation CCLoc,
|
SourceLocation CCLoc,
|
||||||
IdentifierInfo &II,
|
IdentifierInfo &II,
|
||||||
TypeTy *ObjectTypePtr,
|
QualType ObjectType,
|
||||||
|
NamedDecl *ScopeLookupResult,
|
||||||
bool EnteringContext) {
|
bool EnteringContext) {
|
||||||
NestedNameSpecifier *Prefix
|
NestedNameSpecifier *Prefix
|
||||||
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
|
= static_cast<NestedNameSpecifier *>(SS.getScopeRep());
|
||||||
|
@ -307,11 +334,10 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
// Determine where to perform name lookup
|
// Determine where to perform name lookup
|
||||||
DeclContext *LookupCtx = 0;
|
DeclContext *LookupCtx = 0;
|
||||||
bool isDependent = false;
|
bool isDependent = false;
|
||||||
if (ObjectTypePtr) {
|
if (!ObjectType.isNull()) {
|
||||||
// This nested-name-specifier occurs in a member access expression, e.g.,
|
// This nested-name-specifier occurs in a member access expression, e.g.,
|
||||||
// x->B::f, and we are looking into the type of the object.
|
// x->B::f, and we are looking into the type of the object.
|
||||||
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
|
assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
|
||||||
QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
|
|
||||||
LookupCtx = computeDeclContext(ObjectType);
|
LookupCtx = computeDeclContext(ObjectType);
|
||||||
isDependent = ObjectType->isDependentType();
|
isDependent = ObjectType->isDependentType();
|
||||||
} else if (SS.isSet()) {
|
} else if (SS.isSet()) {
|
||||||
|
@ -336,7 +362,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName,
|
Found = LookupQualifiedName(LookupCtx, &II, LookupNestedNameSpecifierName,
|
||||||
false);
|
false);
|
||||||
|
|
||||||
if (ObjectTypePtr && Found.getKind() == LookupResult::NotFound && S) {
|
if (!ObjectType.isNull() && Found.getKind() == LookupResult::NotFound) {
|
||||||
// C++ [basic.lookup.classref]p4:
|
// C++ [basic.lookup.classref]p4:
|
||||||
// If the id-expression in a class member access is a qualified-id of
|
// If the id-expression in a class member access is a qualified-id of
|
||||||
// the form
|
// the form
|
||||||
|
@ -354,12 +380,14 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
// Qualified name lookup into a class will not find a namespace-name,
|
// Qualified name lookup into a class will not find a namespace-name,
|
||||||
// so we do not need to diagnoste that case specifically. However,
|
// so we do not need to diagnoste that case specifically. However,
|
||||||
// this qualified name lookup may find nothing. In that case, perform
|
// this qualified name lookup may find nothing. In that case, perform
|
||||||
// unqualified name lookup in the given scope.
|
// unqualified name lookup in the given scope (if available) or
|
||||||
|
// reconstruct the result from when name lookup was performed at template
|
||||||
// FIXME: When we're instantiating a template, do we actually have to
|
// definition time.
|
||||||
// look in the scope of the template? Both EDG and GCC do it; GCC
|
if (S)
|
||||||
// requires the lookup to be successful, EDG doesn't.
|
|
||||||
Found = LookupName(S, &II, LookupNestedNameSpecifierName);
|
Found = LookupName(S, &II, LookupNestedNameSpecifierName);
|
||||||
|
else
|
||||||
|
Found = LookupResult::CreateLookupResult(Context, ScopeLookupResult);
|
||||||
|
|
||||||
ObjectTypeSearchedInScope = true;
|
ObjectTypeSearchedInScope = true;
|
||||||
}
|
}
|
||||||
} else if (isDependent) {
|
} else if (isDependent) {
|
||||||
|
@ -379,16 +407,21 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
// FIXME: Deal with ambiguities cleanly.
|
// FIXME: Deal with ambiguities cleanly.
|
||||||
NamedDecl *SD = Found;
|
NamedDecl *SD = Found;
|
||||||
if (isAcceptableNestedNameSpecifier(Context, SD)) {
|
if (isAcceptableNestedNameSpecifier(Context, SD)) {
|
||||||
if (ObjectTypePtr && !ObjectTypeSearchedInScope && S) {
|
if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) {
|
||||||
// C++ [basic.lookup.classref]p4:
|
// C++ [basic.lookup.classref]p4:
|
||||||
// [...] If the name is found in both contexts, the
|
// [...] If the name is found in both contexts, the
|
||||||
// class-name-or-namespace-name shall refer to the same entity.
|
// class-name-or-namespace-name shall refer to the same entity.
|
||||||
//
|
//
|
||||||
// We already found the name in the scope of the object. Now, look
|
// We already found the name in the scope of the object. Now, look
|
||||||
// into the current scope (the scope of the postfix-expression) to
|
// into the current scope (the scope of the postfix-expression) to
|
||||||
// see if we can find the same name there.
|
// see if we can find the same name there. As above, if there is no
|
||||||
LookupResult FoundOuter
|
// scope, reconstruct the result from the template instantiation itself.
|
||||||
= LookupName(S, &II, LookupNestedNameSpecifierName);
|
LookupResult FoundOuter;
|
||||||
|
if (S)
|
||||||
|
FoundOuter = LookupName(S, &II, LookupNestedNameSpecifierName);
|
||||||
|
else
|
||||||
|
FoundOuter = LookupResult::CreateLookupResult(Context,
|
||||||
|
ScopeLookupResult);
|
||||||
|
|
||||||
// FIXME: Handle ambiguities in FoundOuter!
|
// FIXME: Handle ambiguities in FoundOuter!
|
||||||
NamedDecl *OuterDecl = FoundOuter;
|
NamedDecl *OuterDecl = FoundOuter;
|
||||||
|
@ -401,7 +434,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
|
Diag(IdLoc, diag::err_nested_name_member_ref_lookup_ambiguous)
|
||||||
<< &II;
|
<< &II;
|
||||||
Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
|
Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type)
|
||||||
<< QualType::getFromOpaquePtr(ObjectTypePtr);
|
<< ObjectType;
|
||||||
Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
|
Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope);
|
||||||
|
|
||||||
// Fall through so that we'll pick the name we found in the object type,
|
// Fall through so that we'll pick the name we found in the object type,
|
||||||
|
@ -450,6 +483,24 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// ActOnCXXNestedNameSpecifier - Called during parsing of a
|
||||||
|
/// nested-name-specifier. e.g. for "foo::bar::" we parsed "foo::" and now
|
||||||
|
/// we want to resolve "bar::". 'SS' is empty or the previously parsed
|
||||||
|
/// nested-name part ("foo::"), 'IdLoc' is the source location of 'bar',
|
||||||
|
/// 'CCLoc' is the location of '::' and 'II' is the identifier for 'bar'.
|
||||||
|
/// Returns a CXXScopeTy* object representing the C++ scope.
|
||||||
|
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
|
const CXXScopeSpec &SS,
|
||||||
|
SourceLocation IdLoc,
|
||||||
|
SourceLocation CCLoc,
|
||||||
|
IdentifierInfo &II,
|
||||||
|
TypeTy *ObjectTypePtr,
|
||||||
|
bool EnteringContext) {
|
||||||
|
return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II,
|
||||||
|
QualType::getFromOpaquePtr(ObjectTypePtr),
|
||||||
|
/*ScopeLookupResult=*/0, EnteringContext);
|
||||||
|
}
|
||||||
|
|
||||||
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
||||||
const CXXScopeSpec &SS,
|
const CXXScopeSpec &SS,
|
||||||
TypeTy *Ty,
|
TypeTy *Ty,
|
||||||
|
|
|
@ -1989,7 +1989,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
const TemplateArgument *ExplicitTemplateArgs,
|
const TemplateArgument *ExplicitTemplateArgs,
|
||||||
unsigned NumExplicitTemplateArgs,
|
unsigned NumExplicitTemplateArgs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS) {
|
DeclPtrTy ObjCImpDecl, const CXXScopeSpec *SS,
|
||||||
|
NamedDecl *FirstQualifierInScope) {
|
||||||
if (SS && SS->isInvalid())
|
if (SS && SS->isInvalid())
|
||||||
return ExprError();
|
return ExprError();
|
||||||
|
|
||||||
|
@ -2022,14 +2023,23 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
|
// Get the type being accessed in BaseType. If this is an arrow, the BaseExpr
|
||||||
// must have pointer type, and the accessed type is the pointee.
|
// must have pointer type, and the accessed type is the pointee.
|
||||||
if (OpKind == tok::arrow) {
|
if (OpKind == tok::arrow) {
|
||||||
if (BaseType->isDependentType())
|
if (BaseType->isDependentType()) {
|
||||||
|
NestedNameSpecifier *Qualifier = 0;
|
||||||
|
if (SS) {
|
||||||
|
Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
|
||||||
|
if (!FirstQualifierInScope)
|
||||||
|
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
||||||
|
}
|
||||||
|
|
||||||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||||
BaseExpr, true,
|
BaseExpr, true,
|
||||||
OpLoc,
|
OpLoc,
|
||||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
Qualifier,
|
||||||
SS? SS->getRange() : SourceRange(),
|
SS? SS->getRange() : SourceRange(),
|
||||||
|
FirstQualifierInScope,
|
||||||
MemberName,
|
MemberName,
|
||||||
MemberLoc));
|
MemberLoc));
|
||||||
|
}
|
||||||
else if (const PointerType *PT = BaseType->getAs<PointerType>())
|
else if (const PointerType *PT = BaseType->getAs<PointerType>())
|
||||||
BaseType = PT->getPointeeType();
|
BaseType = PT->getPointeeType();
|
||||||
else if (BaseType->isObjCObjectPointerType())
|
else if (BaseType->isObjCObjectPointerType())
|
||||||
|
@ -2051,16 +2061,25 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
const PointerType *PT = BaseType->getAs<PointerType>();
|
const PointerType *PT = BaseType->getAs<PointerType>();
|
||||||
|
|
||||||
if (!PT || (getLangOptions().ObjC1 &&
|
if (!PT || (getLangOptions().ObjC1 &&
|
||||||
!PT->getPointeeType()->isRecordType()))
|
!PT->getPointeeType()->isRecordType())) {
|
||||||
|
NestedNameSpecifier *Qualifier = 0;
|
||||||
|
if (SS) {
|
||||||
|
Qualifier = static_cast<NestedNameSpecifier *>(SS->getScopeRep());
|
||||||
|
if (!FirstQualifierInScope)
|
||||||
|
FirstQualifierInScope = FindFirstQualifierInScope(S, Qualifier);
|
||||||
|
}
|
||||||
|
|
||||||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||||
BaseExpr, false,
|
BaseExpr, false,
|
||||||
OpLoc,
|
OpLoc,
|
||||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
Qualifier,
|
||||||
SS? SS->getRange() : SourceRange(),
|
SS? SS->getRange() : SourceRange(),
|
||||||
|
FirstQualifierInScope,
|
||||||
MemberName,
|
MemberName,
|
||||||
MemberLoc));
|
MemberLoc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle field access to simple records. This also handles access to fields
|
// Handle field access to simple records. This also handles access to fields
|
||||||
// of the ObjC 'id' struct.
|
// of the ObjC 'id' struct.
|
||||||
|
|
|
@ -1789,9 +1789,20 @@ Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
// We could end up with various non-record types here, such as extended
|
// We could end up with various non-record types here, such as extended
|
||||||
// vector types or Objective-C interfaces. Just return early and let
|
// vector types or Objective-C interfaces. Just return early and let
|
||||||
// ActOnMemberReferenceExpr do the work.
|
// ActOnMemberReferenceExpr do the work.
|
||||||
if (!BaseType->isRecordType())
|
if (!BaseType->isRecordType()) {
|
||||||
|
// C++ [basic.lookup.classref]p2:
|
||||||
|
// [...] If the type of the object expression is of pointer to scalar
|
||||||
|
// type, the unqualified-id is looked up in the context of the complete
|
||||||
|
// postfix-expression.
|
||||||
|
ObjectType = 0;
|
||||||
return move(Base);
|
return move(Base);
|
||||||
|
}
|
||||||
|
|
||||||
|
// C++ [basic.lookup.classref]p2:
|
||||||
|
// If the id-expression in a class member access (5.2.5) is an
|
||||||
|
// unqualified-id, and the type of the object expres- sion is of a class
|
||||||
|
// type C (or of pointer to a class type C), the unqualified-id is looked
|
||||||
|
// up in the scope of class C. [...]
|
||||||
ObjectType = BaseType.getAsOpaquePtr();
|
ObjectType = BaseType.getAsOpaquePtr();
|
||||||
return move(Base);
|
return move(Base);
|
||||||
}
|
}
|
||||||
|
|
|
@ -359,8 +359,10 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *TemplateInstantiator::TransformDecl(Decl *D) {
|
Decl *TemplateInstantiator::TransformDecl(Decl *D) {
|
||||||
if (TemplateTemplateParmDecl *TTP
|
if (!D)
|
||||||
= dyn_cast_or_null<TemplateTemplateParmDecl>(D)) {
|
return 0;
|
||||||
|
|
||||||
|
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
|
||||||
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
|
if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
|
||||||
assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
|
assert(TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsDecl() &&
|
||||||
"Wrong kind of template template argument");
|
"Wrong kind of template template argument");
|
||||||
|
@ -381,7 +383,7 @@ Decl *TemplateInstantiator::TransformDecl(Decl *D) {
|
||||||
"Reducing depth of template template parameters is not yet implemented");
|
"Reducing depth of template template parameters is not yet implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
return SemaRef.FindInstantiatedDecl(cast_or_null<NamedDecl>(D));
|
return SemaRef.FindInstantiatedDecl(cast<NamedDecl>(D));
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
|
Decl *TemplateInstantiator::TransformDefinition(Decl *D) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "Sema.h"
|
#include "Sema.h"
|
||||||
#include "clang/Sema/SemaDiagnostic.h"
|
#include "clang/Sema/SemaDiagnostic.h"
|
||||||
|
#include "clang/AST/Decl.h"
|
||||||
#include "clang/AST/Expr.h"
|
#include "clang/AST/Expr.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
|
@ -243,7 +244,8 @@ public:
|
||||||
/// alternate behavior.
|
/// alternate behavior.
|
||||||
NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||||
SourceRange Range,
|
SourceRange Range,
|
||||||
QualType ObjectType = QualType());
|
QualType ObjectType = QualType(),
|
||||||
|
NamedDecl *FirstQualifierInScope = 0);
|
||||||
|
|
||||||
/// \brief Transform the given template name.
|
/// \brief Transform the given template name.
|
||||||
///
|
///
|
||||||
|
@ -499,7 +501,8 @@ public:
|
||||||
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
||||||
SourceRange Range,
|
SourceRange Range,
|
||||||
IdentifierInfo &II,
|
IdentifierInfo &II,
|
||||||
QualType ObjectType);
|
QualType ObjectType,
|
||||||
|
NamedDecl *FirstQualifierInScope);
|
||||||
|
|
||||||
/// \brief Build a new nested-name-specifier given the prefix and the
|
/// \brief Build a new nested-name-specifier given the prefix and the
|
||||||
/// namespace named in the next step in the nested-name-specifier.
|
/// namespace named in the next step in the nested-name-specifier.
|
||||||
|
@ -1454,7 +1457,8 @@ public:
|
||||||
NestedNameSpecifier *Qualifier,
|
NestedNameSpecifier *Qualifier,
|
||||||
SourceRange QualifierRange,
|
SourceRange QualifierRange,
|
||||||
DeclarationName Name,
|
DeclarationName Name,
|
||||||
SourceLocation MemberLoc) {
|
SourceLocation MemberLoc,
|
||||||
|
NamedDecl *FirstQualifierInScope) {
|
||||||
OwningExprResult Base = move(BaseE);
|
OwningExprResult Base = move(BaseE);
|
||||||
tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
|
tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
|
||||||
|
|
||||||
|
@ -1467,7 +1471,8 @@ public:
|
||||||
MemberLoc,
|
MemberLoc,
|
||||||
Name,
|
Name,
|
||||||
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
|
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
|
||||||
&SS);
|
&SS,
|
||||||
|
FirstQualifierInScope);
|
||||||
return move(Base);
|
return move(Base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1591,7 +1596,8 @@ template<typename Derived>
|
||||||
NestedNameSpecifier *
|
NestedNameSpecifier *
|
||||||
TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||||
SourceRange Range,
|
SourceRange Range,
|
||||||
QualType ObjectType) {
|
QualType ObjectType,
|
||||||
|
NamedDecl *FirstQualifierInScope) {
|
||||||
if (!NNS)
|
if (!NNS)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -1599,13 +1605,15 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||||
NestedNameSpecifier *Prefix = NNS->getPrefix();
|
NestedNameSpecifier *Prefix = NNS->getPrefix();
|
||||||
if (Prefix) {
|
if (Prefix) {
|
||||||
Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
|
Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
|
||||||
ObjectType);
|
ObjectType,
|
||||||
|
FirstQualifierInScope);
|
||||||
if (!Prefix)
|
if (!Prefix)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Clear out the object type; it only applies to the first element in
|
// Clear out the object type and the first qualifier in scope; they only
|
||||||
// the nested-name-specifier.
|
// apply to the first element in the nested-name-specifier.
|
||||||
ObjectType = QualType();
|
ObjectType = QualType();
|
||||||
|
FirstQualifierInScope = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (NNS->getKind()) {
|
switch (NNS->getKind()) {
|
||||||
|
@ -1618,7 +1626,8 @@ TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||||
|
|
||||||
return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
|
return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
|
||||||
*NNS->getAsIdentifier(),
|
*NNS->getAsIdentifier(),
|
||||||
ObjectType);
|
ObjectType,
|
||||||
|
FirstQualifierInScope);
|
||||||
|
|
||||||
case NestedNameSpecifier::Namespace: {
|
case NestedNameSpecifier::Namespace: {
|
||||||
NamespaceDecl *NS
|
NamespaceDecl *NS
|
||||||
|
@ -4055,11 +4064,16 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
||||||
if (Base.isInvalid())
|
if (Base.isInvalid())
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
|
|
||||||
|
NamedDecl *FirstQualifierInScope
|
||||||
|
= cast_or_null<NamedDecl>(
|
||||||
|
getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
|
||||||
|
|
||||||
NestedNameSpecifier *Qualifier = 0;
|
NestedNameSpecifier *Qualifier = 0;
|
||||||
if (E->getQualifier()) {
|
if (E->getQualifier()) {
|
||||||
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
|
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
|
||||||
E->getQualifierRange(),
|
E->getQualifierRange(),
|
||||||
QualType::getFromOpaquePtr(ObjectType));
|
QualType::getFromOpaquePtr(ObjectType),
|
||||||
|
FirstQualifierInScope);
|
||||||
if (!Qualifier)
|
if (!Qualifier)
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
}
|
}
|
||||||
|
@ -4070,7 +4084,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
||||||
if (!getDerived().AlwaysRebuild() &&
|
if (!getDerived().AlwaysRebuild() &&
|
||||||
Base.get() == E->getBase() &&
|
Base.get() == E->getBase() &&
|
||||||
Qualifier == E->getQualifier() &&
|
Qualifier == E->getQualifier() &&
|
||||||
Name == E->getMember())
|
Name == E->getMember() &&
|
||||||
|
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
|
||||||
return SemaRef.Owned(E->Retain());
|
return SemaRef.Owned(E->Retain());
|
||||||
|
|
||||||
return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
|
return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
|
||||||
|
@ -4079,7 +4094,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
||||||
Qualifier,
|
Qualifier,
|
||||||
E->getQualifierRange(),
|
E->getQualifierRange(),
|
||||||
Name,
|
Name,
|
||||||
E->getMemberLoc());
|
E->getMemberLoc(),
|
||||||
|
FirstQualifierInScope);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Derived>
|
template<typename Derived>
|
||||||
|
@ -4435,15 +4451,17 @@ NestedNameSpecifier *
|
||||||
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
||||||
SourceRange Range,
|
SourceRange Range,
|
||||||
IdentifierInfo &II,
|
IdentifierInfo &II,
|
||||||
QualType ObjectType) {
|
QualType ObjectType,
|
||||||
|
NamedDecl *FirstQualifierInScope) {
|
||||||
CXXScopeSpec SS;
|
CXXScopeSpec SS;
|
||||||
// FIXME: The source location information is all wrong.
|
// FIXME: The source location information is all wrong.
|
||||||
SS.setRange(Range);
|
SS.setRange(Range);
|
||||||
SS.setScopeRep(Prefix);
|
SS.setScopeRep(Prefix);
|
||||||
return static_cast<NestedNameSpecifier *>(
|
return static_cast<NestedNameSpecifier *>(
|
||||||
SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(),
|
SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(),
|
||||||
Range.getEnd(), II,
|
Range.getEnd(), II,
|
||||||
ObjectType.getAsOpaquePtr(),
|
ObjectType,
|
||||||
|
FirstQualifierInScope,
|
||||||
false));
|
false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,18 +107,26 @@ namespace C
|
||||||
a.A::B::base::x();
|
a.A::B::base::x();
|
||||||
a->A::member::foo();
|
a->A::member::foo();
|
||||||
|
|
||||||
a.bad::x(); // xpected-error{{direct or virtual}}
|
a.bad::x(); // expected-error{{direct or virtual}}
|
||||||
a.sub::x();
|
|
||||||
a.base::x();
|
|
||||||
a.B::base::x(); // xpected-error{{use of undeclared identifier 'B'}}
|
|
||||||
a->member::foo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_fun5() {
|
void test_fun5() {
|
||||||
// FIXME: Enable the following once we get the nested-name-specifier lookup
|
fun5<A::sub>(); // expected-note{{instantiation}}
|
||||||
// right during template instantiation.
|
|
||||||
// fun5<A::sub>(); // xpected-note 2{{instantiation}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void fun6() {
|
||||||
|
T a;
|
||||||
|
a.sub::x();
|
||||||
|
a.base::x();
|
||||||
|
a->member::foo();
|
||||||
|
a.B::base::x(); // expected-error{{use of undeclared identifier 'B'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_fun6() {
|
||||||
|
fun6<A::sub>(); // expected-note{{instantiation}}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PR4703
|
// PR4703
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
// RUN: clang-cc -fsyntax-only -verify %s
|
// RUN: clang-cc -fsyntax-only -verify %s
|
||||||
// XFAIL
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void call_f0(T x) {
|
void call_f0(T x) {
|
||||||
x.Base::f0();
|
x.Base::f0();
|
||||||
|
@ -30,7 +29,8 @@ void test_f0_through_typedef(X0 x0) {
|
||||||
template<typename TheBase, typename T>
|
template<typename TheBase, typename T>
|
||||||
void call_f0_through_typedef2(T x) {
|
void call_f0_through_typedef2(T x) {
|
||||||
typedef TheBase CrazyBase; // expected-note{{current scope}}
|
typedef TheBase CrazyBase; // expected-note{{current scope}}
|
||||||
x.CrazyBase::f0(); // expected-error{{ambiguous}}
|
x.CrazyBase::f0(); // expected-error{{ambiguous}} \
|
||||||
|
// expected-error 2{{no member named}}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct OtherBase { };
|
struct OtherBase { };
|
||||||
|
@ -41,8 +41,8 @@ struct X1 : Base, OtherBase {
|
||||||
|
|
||||||
void test_f0_through_typedef2(X0 x0, X1 x1) {
|
void test_f0_through_typedef2(X0 x0, X1 x1) {
|
||||||
call_f0_through_typedef2<Base>(x0);
|
call_f0_through_typedef2<Base>(x0);
|
||||||
call_f0_through_typedef2<OtherBase>(x1);
|
call_f0_through_typedef2<OtherBase>(x1); // expected-note{{instantiation}}
|
||||||
call_f0_through_typedef2<Base>(x1); // expected-note{{here}}
|
call_f0_through_typedef2<Base>(x1); // expected-note{{instantiation}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -380,7 +380,14 @@ welcome!</p>
|
||||||
<td></td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr><td> 3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr><td> 3.4.4 [basic.lookup.elab]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||||
<tr><td> 3.4.5 [basic.lookup.classref]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr>
|
||||||
|
<td> 3.4.5 [basic.lookup.classref]</td>
|
||||||
|
<td class="na">N/A</td>
|
||||||
|
<td class="na">N/A</td>
|
||||||
|
<td class="advanced"></td>
|
||||||
|
<td class="na">N/A</td>
|
||||||
|
<td>Missing ambiguity/consistency checks for paragraphs 3 (~type-name) and 7 (conversion-type-id)</td>
|
||||||
|
</tr>
|
||||||
<tr><td> 3.4.6 [basic.lookup.udir]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr><td> 3.4.6 [basic.lookup.udir]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||||
<tr><td> 3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr><td> 3.5 [basic.link]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||||
<tr><td> 3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
<tr><td> 3.6 [basic.start]</td><td></td><td></td><td></td><td></td><td></td></tr>
|
||||||
|
|
Loading…
Reference in New Issue