aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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