forked from OSchip/llvm-project
Improved handling for dependent, qualified member access expressions, e.g.,
t->Base::f where t has a dependent type. We save the nested-name-specifier in the CXXUnresolvedMemberExpr then, during instantiation, substitute into the nested-name-specifier with the (transformed) object type of t, so that we get name lookup into the type of the object expression. Note that we do not yet retain information about name lookup into the lexical scope of the member access expression, so several regression tests are still disabled. llvm-svn: 80925
This commit is contained in:
parent
a7326b5ba5
commit
c26e0f626b
|
@ -1300,23 +1300,31 @@ class CXXUnresolvedMemberExpr : public Expr {
|
|||
/// \brief The location of the '->' or '.' operator.
|
||||
SourceLocation OperatorLoc;
|
||||
|
||||
/// \brief The nested-name-specifier that precedes the member name, if any.
|
||||
NestedNameSpecifier *Qualifier;
|
||||
|
||||
/// \brief The source range covering the nested name specifier.
|
||||
SourceRange QualifierRange;
|
||||
|
||||
/// \brief The member to which this member expression refers, which
|
||||
/// can be name, overloaded operator, or destructor.
|
||||
/// FIXME: could also be a template-id, and we might have a
|
||||
/// nested-name-specifier as well.
|
||||
/// FIXME: could also be a template-id
|
||||
DeclarationName Member;
|
||||
|
||||
/// \brief The location of the member name.
|
||||
SourceLocation MemberLoc;
|
||||
|
||||
|
||||
public:
|
||||
CXXUnresolvedMemberExpr(ASTContext &C,
|
||||
Expr *Base, bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
DeclarationName Member,
|
||||
SourceLocation MemberLoc)
|
||||
: Expr(CXXUnresolvedMemberExprClass, C.DependentTy, true, true),
|
||||
Base(Base), IsArrow(IsArrow), OperatorLoc(OperatorLoc),
|
||||
Qualifier(Qualifier), QualifierRange(QualifierRange),
|
||||
Member(Member), MemberLoc(MemberLoc) { }
|
||||
|
||||
/// \brief Retrieve the base object of this member expressions,
|
||||
|
@ -1333,6 +1341,14 @@ public:
|
|||
SourceLocation getOperatorLoc() const { return OperatorLoc; }
|
||||
void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
|
||||
|
||||
/// \brief Retrieve the nested-name-specifier that qualifies the member
|
||||
/// name.
|
||||
NestedNameSpecifier *getQualifier() const { return Qualifier; }
|
||||
|
||||
/// \brief Retrieve the source range covering the nested-name-specifier
|
||||
/// that qualifies the member name.
|
||||
SourceRange getQualifierRange() const { return QualifierRange; }
|
||||
|
||||
/// \brief Retrieve the name of the member that this expression
|
||||
/// refers to.
|
||||
DeclarationName getMember() const { return Member; }
|
||||
|
|
|
@ -1138,6 +1138,8 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
|
|||
void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) {
|
||||
PrintExpr(Node->getBase());
|
||||
OS << (Node->isArrow() ? "->" : ".");
|
||||
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
|
||||
Qualifier->print(OS, Policy);
|
||||
OS << Node->getMember().getAsString();
|
||||
}
|
||||
|
||||
|
|
|
@ -550,6 +550,7 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
|
|||
void StmtProfiler::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *S) {
|
||||
VisitExpr(S);
|
||||
ID.AddBoolean(S->isArrow());
|
||||
VisitNestedNameSpecifier(S->getQualifier());
|
||||
VisitName(S->getMember());
|
||||
}
|
||||
|
||||
|
|
|
@ -2025,7 +2025,9 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
if (BaseType->isDependentType())
|
||||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||
BaseExpr, true,
|
||||
OpLoc,
|
||||
OpLoc,
|
||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
MemberName,
|
||||
MemberLoc));
|
||||
else if (const PointerType *PT = BaseType->getAs<PointerType>())
|
||||
|
@ -2053,6 +2055,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
return Owned(new (Context) CXXUnresolvedMemberExpr(Context,
|
||||
BaseExpr, false,
|
||||
OpLoc,
|
||||
(NestedNameSpecifier *)(SS? SS->getScopeRep() : 0),
|
||||
SS? SS->getRange() : SourceRange(),
|
||||
MemberName,
|
||||
MemberLoc));
|
||||
}
|
||||
|
@ -2082,21 +2086,6 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
LookupResult Result
|
||||
= LookupQualifiedName(DC, MemberName, LookupMemberName, false);
|
||||
|
||||
if (SS && SS->isSet()) {
|
||||
QualType BaseTypeCanon
|
||||
= Context.getCanonicalType(BaseType).getUnqualifiedType();
|
||||
QualType MemberTypeCanon
|
||||
= Context.getCanonicalType(
|
||||
Context.getTypeDeclType(
|
||||
dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext())));
|
||||
|
||||
if (BaseTypeCanon != MemberTypeCanon &&
|
||||
!IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
|
||||
return ExprError(Diag(SS->getBeginLoc(),
|
||||
diag::err_not_direct_base_or_virtual)
|
||||
<< MemberTypeCanon << BaseTypeCanon);
|
||||
}
|
||||
|
||||
if (!Result)
|
||||
return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
|
||||
<< MemberName << BaseExpr->getSourceRange());
|
||||
|
@ -2106,6 +2095,21 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
|||
return ExprError();
|
||||
}
|
||||
|
||||
if (SS && SS->isSet()) {
|
||||
QualType BaseTypeCanon
|
||||
= Context.getCanonicalType(BaseType).getUnqualifiedType();
|
||||
QualType MemberTypeCanon
|
||||
= Context.getCanonicalType(
|
||||
Context.getTypeDeclType(
|
||||
dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext())));
|
||||
|
||||
if (BaseTypeCanon != MemberTypeCanon &&
|
||||
!IsDerivedFrom(BaseTypeCanon, MemberTypeCanon))
|
||||
return ExprError(Diag(SS->getBeginLoc(),
|
||||
diag::err_not_direct_base_or_virtual)
|
||||
<< MemberTypeCanon << BaseTypeCanon);
|
||||
}
|
||||
|
||||
NamedDecl *MemberDecl = Result;
|
||||
|
||||
// If the decl being referenced had an error, return an error for this
|
||||
|
|
|
@ -242,7 +242,8 @@ public:
|
|||
/// nested-name-specifier. Subclasses may override this function to provide
|
||||
/// alternate behavior.
|
||||
NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||
SourceRange Range);
|
||||
SourceRange Range,
|
||||
QualType ObjectType = QualType());
|
||||
|
||||
/// \brief Transform the given template name.
|
||||
///
|
||||
|
@ -497,7 +498,8 @@ public:
|
|||
/// different behavior.
|
||||
NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
||||
SourceRange Range,
|
||||
IdentifierInfo &II);
|
||||
IdentifierInfo &II,
|
||||
QualType ObjectType);
|
||||
|
||||
/// \brief Build a new nested-name-specifier given the prefix and the
|
||||
/// namespace named in the next step in the nested-name-specifier.
|
||||
|
@ -1449,23 +1451,23 @@ public:
|
|||
OwningExprResult RebuildCXXUnresolvedMemberExpr(ExprArg BaseE,
|
||||
bool IsArrow,
|
||||
SourceLocation OperatorLoc,
|
||||
NestedNameSpecifier *Qualifier,
|
||||
SourceRange QualifierRange,
|
||||
DeclarationName Name,
|
||||
SourceLocation MemberLoc) {
|
||||
OwningExprResult Base = move(BaseE);
|
||||
tok::TokenKind OpKind = IsArrow? tok::arrow : tok::period;
|
||||
|
||||
CXXScopeSpec SS;
|
||||
Sema::TypeTy *ObjectType = 0;
|
||||
|
||||
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), OperatorLoc,
|
||||
OpKind, ObjectType);
|
||||
if (Base.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
SS.setRange(QualifierRange);
|
||||
SS.setScopeRep(Qualifier);
|
||||
|
||||
Base = SemaRef.BuildMemberReferenceExpr(/*Scope=*/0,
|
||||
move(Base), OperatorLoc, OpKind,
|
||||
MemberLoc,
|
||||
Name,
|
||||
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0));
|
||||
/*FIXME?*/Sema::DeclPtrTy::make((Decl*)0),
|
||||
&SS);
|
||||
return move(Base);
|
||||
}
|
||||
|
||||
|
@ -1588,27 +1590,35 @@ Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
|
|||
template<typename Derived>
|
||||
NestedNameSpecifier *
|
||||
TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
|
||||
SourceRange Range) {
|
||||
SourceRange Range,
|
||||
QualType ObjectType) {
|
||||
if (!NNS)
|
||||
return 0;
|
||||
|
||||
// Transform the prefix of this nested name specifier.
|
||||
NestedNameSpecifier *Prefix = NNS->getPrefix();
|
||||
if (Prefix) {
|
||||
Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range);
|
||||
Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range,
|
||||
ObjectType);
|
||||
if (!Prefix)
|
||||
return 0;
|
||||
|
||||
// Clear out the object type; it only applies to the first element in
|
||||
// the nested-name-specifier.
|
||||
ObjectType = QualType();
|
||||
}
|
||||
|
||||
switch (NNS->getKind()) {
|
||||
case NestedNameSpecifier::Identifier:
|
||||
assert(Prefix &&
|
||||
"Can't have an identifier nested-name-specifier with no prefix");
|
||||
if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix())
|
||||
assert((Prefix || !ObjectType.isNull()) &&
|
||||
"Identifier nested-name-specifier with no prefix or object type");
|
||||
if (!getDerived().AlwaysRebuild() && Prefix == NNS->getPrefix() &&
|
||||
ObjectType.isNull())
|
||||
return NNS;
|
||||
|
||||
return getDerived().RebuildNestedNameSpecifier(Prefix, Range,
|
||||
*NNS->getAsIdentifier());
|
||||
*NNS->getAsIdentifier(),
|
||||
ObjectType);
|
||||
|
||||
case NestedNameSpecifier::Namespace: {
|
||||
NamespaceDecl *NS
|
||||
|
@ -4037,18 +4047,38 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
|
|||
if (Base.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
Sema::TypeTy *ObjectType = 0;
|
||||
Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
|
||||
E->getOperatorLoc(),
|
||||
E->isArrow()? tok::arrow : tok::period,
|
||||
ObjectType);
|
||||
if (Base.isInvalid())
|
||||
return SemaRef.ExprError();
|
||||
|
||||
NestedNameSpecifier *Qualifier = 0;
|
||||
if (E->getQualifier()) {
|
||||
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
|
||||
E->getQualifierRange(),
|
||||
QualType::getFromOpaquePtr(ObjectType));
|
||||
if (!Qualifier)
|
||||
return SemaRef.ExprError();
|
||||
}
|
||||
|
||||
// FIXME: Transform the declaration name
|
||||
DeclarationName Name = E->getMember();
|
||||
|
||||
if (!getDerived().AlwaysRebuild() &&
|
||||
Base.get() == E->getBase() &&
|
||||
Qualifier == E->getQualifier() &&
|
||||
Name == E->getMember())
|
||||
return SemaRef.Owned(E->Retain());
|
||||
|
||||
|
||||
return getDerived().RebuildCXXUnresolvedMemberExpr(move(Base),
|
||||
E->isArrow(),
|
||||
E->getOperatorLoc(),
|
||||
E->getMember(),
|
||||
Qualifier,
|
||||
E->getQualifierRange(),
|
||||
Name,
|
||||
E->getMemberLoc());
|
||||
}
|
||||
|
||||
|
@ -4404,7 +4434,8 @@ template<typename Derived>
|
|||
NestedNameSpecifier *
|
||||
TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
||||
SourceRange Range,
|
||||
IdentifierInfo &II) {
|
||||
IdentifierInfo &II,
|
||||
QualType ObjectType) {
|
||||
CXXScopeSpec SS;
|
||||
// FIXME: The source location information is all wrong.
|
||||
SS.setRange(Range);
|
||||
|
@ -4412,7 +4443,7 @@ TreeTransform<Derived>::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix,
|
|||
return static_cast<NestedNameSpecifier *>(
|
||||
SemaRef.ActOnCXXNestedNameSpecifier(0, SS, Range.getEnd(),
|
||||
Range.getEnd(), II,
|
||||
/*FIXME:ObjectType=*/0,
|
||||
ObjectType.getAsOpaquePtr(),
|
||||
false));
|
||||
}
|
||||
|
||||
|
|
|
@ -103,25 +103,22 @@ namespace C
|
|||
a.x();
|
||||
a->foo();
|
||||
|
||||
#if 0
|
||||
// FIXME: We need the notion of identifiers as dependent
|
||||
// nested-name-specifiers without a prefix for this code to work.
|
||||
|
||||
// Things that work for the wrong reason
|
||||
a.A::sub::x();
|
||||
a.A::B::base::x();
|
||||
a->A::member::foo();
|
||||
|
||||
// Things that work, but shouldn't
|
||||
a.bad::x();
|
||||
|
||||
// Things that fail, but shouldn't
|
||||
a.sub::x(); // xpected-error{{use of undeclared identifier 'sub'}}
|
||||
a.base::x(); // xpected-error{{use of undeclared identifier 'base'}}
|
||||
a.bad::x(); // xpected-error{{direct or virtual}}
|
||||
a.sub::x();
|
||||
a.base::x();
|
||||
a.B::base::x(); // xpected-error{{use of undeclared identifier 'B'}}
|
||||
a->member::foo(); // xpected-error{{use of undeclared identifier 'member'}}
|
||||
#endif
|
||||
a->member::foo();
|
||||
}
|
||||
|
||||
void test_fun5() {
|
||||
// FIXME: Enable the following once we get the nested-name-specifier lookup
|
||||
// right during template instantiation.
|
||||
// fun5<A::sub>(); // xpected-note 2{{instantiation}}
|
||||
}
|
||||
}
|
||||
|
||||
// PR4703
|
||||
|
|
Loading…
Reference in New Issue