aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-09-03 16:14:30 +0000
committerDouglas Gregor <dgregor@apple.com>2009-09-03 16:14:30 +0000
commita38c687ef5354678b9d76a7b29354159f2b83736 (patch)
treeffbe4e528040593d2e2e41d63b44108fb6630af0
parentaf08ddc8f1c53fed8d8d0ad82aa2a0bb7d654bd1 (diff)
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80925 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ExprCXX.h22
-rw-r--r--lib/AST/StmtPrinter.cpp2
-rw-r--r--lib/AST/StmtProfile.cpp1
-rw-r--r--lib/Sema/SemaExpr.cpp30
-rw-r--r--lib/Sema/TreeTransform.h71
-rw-r--r--test/SemaCXX/qual-id-test.cpp23
6 files changed, 100 insertions, 49 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 6e9df9128f..a308889af0 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -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; }
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index f10a5e0473..cde4cdc416 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -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();
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 2545d34818..19d313b420 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -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());
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index c01097e363..394bc97927 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -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,29 +2086,29 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
LookupResult Result
= LookupQualifiedName(DC, MemberName, LookupMemberName, false);
+ if (!Result)
+ return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
+ << MemberName << BaseExpr->getSourceRange());
+ if (Result.isAmbiguous()) {
+ DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
+ BaseExpr->getSourceRange());
+ return ExprError();
+ }
+
if (SS && SS->isSet()) {
QualType BaseTypeCanon
= Context.getCanonicalType(BaseType).getUnqualifiedType();
QualType MemberTypeCanon
= Context.getCanonicalType(
- Context.getTypeDeclType(
- dyn_cast<TypeDecl>(Result.getAsDecl()->getDeclContext())));
-
+ 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());
- if (Result.isAmbiguous()) {
- DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
- BaseExpr->getSourceRange());
- return ExprError();
- }
NamedDecl *MemberDecl = Result;
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 8fe28a46bf..20259a7f79 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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));
}
diff --git a/test/SemaCXX/qual-id-test.cpp b/test/SemaCXX/qual-id-test.cpp
index 10f1a47a9d..9032d0e956 100644
--- a/test/SemaCXX/qual-id-test.cpp
+++ b/test/SemaCXX/qual-id-test.cpp
@@ -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