aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2009-12-01 22:10:20 +0000
committerJohn McCall <rjmccall@apple.com>2009-12-01 22:10:20 +0000
commitaa81e1658d87b9011125c632aa902d154ae4b02c (patch)
tree2461221c4e0c971892fa37bfe369eaa16445b704
parentfcb91afaf2823d62453d7c19f66d30bb8dbb7c55 (diff)
Rework how we support C++ implicit member accesses. If we can resolve an
implicit member access to a specific declaration, go ahead and create it as a DeclRefExpr or a MemberExpr (with implicit CXXThisExpr base) as appropriate. Otherwise, create an UnresolvedMemberExpr or DependentScopeMemberExpr with a null base expression. By representing implicit accesses directly in the AST, we get the ability to correctly delay the decision about whether it's actually an instance member access or not until resolution is complete. This permits us to correctly avoid diagnosing the 'problem' of 'MyType::foo()' where the relationship to the type isn't really known until instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90266 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ExprCXX.h125
-rw-r--r--lib/AST/ExprCXX.cpp45
-rw-r--r--lib/AST/StmtPrinter.cpp16
-rw-r--r--lib/AST/StmtProfile.cpp18
-rw-r--r--lib/Sema/Sema.h17
-rw-r--r--lib/Sema/SemaExpr.cpp517
-rw-r--r--lib/Sema/SemaOverload.cpp117
-rw-r--r--lib/Sema/SemaTemplate.cpp6
-rw-r--r--lib/Sema/TreeTransform.h86
-rw-r--r--test/SemaTemplate/instantiate-method.cpp4
-rw-r--r--test/SemaTemplate/qualified-id.cpp11
11 files changed, 647 insertions, 315 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 23844ce5d9..66f4b5d2b5 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -1410,18 +1410,26 @@ public:
/// \brief Represents a C++ member access expression where the actual
/// member referenced could not be resolved because the base
/// expression or the member name was dependent.
+///
+/// Like UnresolvedMemberExprs, these can be either implicit or
+/// explicit accesses. It is only possible to get one of these with
+/// an implicit access if a qualifier is provided.
class CXXDependentScopeMemberExpr : public Expr {
/// \brief The expression for the base pointer or class reference,
- /// e.g., the \c x in x.f.
+ /// e.g., the \c x in x.f. Can be null in implicit accesses.
Stmt *Base;
+ /// \brief The type of the base expression. Never null, even for
+ /// implicit accesses.
+ QualType BaseType;
+
/// \brief Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow : 1;
/// \brief Whether this member expression has explicitly-specified template
/// arguments.
- bool HasExplicitTemplateArgumentList : 1;
+ bool HasExplicitTemplateArgs : 1;
/// \brief The location of the '->' or '.' operator.
SourceLocation OperatorLoc;
@@ -1452,9 +1460,7 @@ class CXXDependentScopeMemberExpr : public Expr {
/// \brief Retrieve the explicit template argument list that followed the
/// member template name, if any.
ExplicitTemplateArgumentList *getExplicitTemplateArgumentList() {
- if (!HasExplicitTemplateArgumentList)
- return 0;
-
+ assert(HasExplicitTemplateArgs);
return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
}
@@ -1466,7 +1472,7 @@ class CXXDependentScopeMemberExpr : public Expr {
}
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1477,7 +1483,8 @@ class CXXDependentScopeMemberExpr : public Expr {
public:
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1485,15 +1492,15 @@ public:
DeclarationName Member,
SourceLocation MemberLoc)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
- Base(Base), IsArrow(IsArrow), HasExplicitTemplateArgumentList(false),
- OperatorLoc(OperatorLoc),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
Member(Member), MemberLoc(MemberLoc) { }
static CXXDependentScopeMemberExpr *
Create(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1502,11 +1509,21 @@ public:
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs);
+ /// \brief True if this is an implicit access, i.e. one in which the
+ /// member being accessed was not written in the source. The source
+ /// location of the operator is invalid in this case.
+ bool isImplicitAccess() const { return Base == 0; }
+
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
- Expr *getBase() { return cast<Expr>(Base); }
+ Expr *getBase() const {
+ assert(!isImplicitAccess());
+ return cast<Expr>(Base);
+ }
void setBase(Expr *E) { Base = E; }
+ QualType getBaseType() const { return BaseType; }
+
/// \brief Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
@@ -1551,60 +1568,59 @@ public:
/// \brief Determines whether this member expression actually had a C++
/// template argument list explicitly specified, e.g., x.f<int>.
- bool hasExplicitTemplateArgumentList() const {
- return HasExplicitTemplateArgumentList;
+ bool hasExplicitTemplateArgs() const {
+ return HasExplicitTemplateArgs;
}
/// \brief Copies the template arguments (if present) into the given
/// structure.
void copyTemplateArgumentsInto(TemplateArgumentListInfo &List) const {
- if (hasExplicitTemplateArgumentList())
- getExplicitTemplateArgumentList()->copyInto(List);
+ assert(HasExplicitTemplateArgs);
+ getExplicitTemplateArgumentList()->copyInto(List);
}
/// \brief Retrieve the location of the left angle bracket following the
/// member name ('<'), if any.
SourceLocation getLAngleLoc() const {
- if (!HasExplicitTemplateArgumentList)
- return SourceLocation();
-
+ assert(HasExplicitTemplateArgs);
return getExplicitTemplateArgumentList()->LAngleLoc;
}
/// \brief Retrieve the template arguments provided as part of this
/// template-id.
const TemplateArgumentLoc *getTemplateArgs() const {
- if (!HasExplicitTemplateArgumentList)
- return 0;
-
+ assert(HasExplicitTemplateArgs);
return getExplicitTemplateArgumentList()->getTemplateArgs();
}
/// \brief Retrieve the number of template arguments provided as part of this
/// template-id.
unsigned getNumTemplateArgs() const {
- if (!HasExplicitTemplateArgumentList)
- return 0;
-
+ assert(HasExplicitTemplateArgs);
return getExplicitTemplateArgumentList()->NumTemplateArgs;
}
/// \brief Retrieve the location of the right angle bracket following the
/// template arguments ('>').
SourceLocation getRAngleLoc() const {
- if (!HasExplicitTemplateArgumentList)
- return SourceLocation();
-
+ assert(HasExplicitTemplateArgs);
return getExplicitTemplateArgumentList()->RAngleLoc;
}
virtual SourceRange getSourceRange() const {
- if (HasExplicitTemplateArgumentList)
- return SourceRange(Base->getSourceRange().getBegin(),
- getRAngleLoc());
+ SourceRange Range;
+ if (!isImplicitAccess())
+ Range.setBegin(Base->getSourceRange().getBegin());
+ else if (getQualifier())
+ Range.setBegin(getQualifierRange().getBegin());
+ else
+ Range.setBegin(MemberLoc);
- return SourceRange(Base->getSourceRange().getBegin(),
- MemberLoc);
+ if (hasExplicitTemplateArgs())
+ Range.setEnd(getRAngleLoc());
+ else
+ Range.setEnd(MemberLoc);
+ return Range;
}
static bool classof(const Stmt *T) {
@@ -1618,17 +1634,31 @@ public:
};
/// \brief Represents a C++ member access expression for which lookup
-/// produced a set of overloaded functions. These are replaced with
-/// MemberExprs in the final AST.
+/// produced a set of overloaded functions.
+///
+/// The member access may be explicit or implicit:
+/// struct A {
+/// int a, b;
+/// int explicitAccess() { return this->a + this->A::b; }
+/// int implicitAccess() { return a + A::b; }
+/// };
+///
+/// In the final AST, an explicit access always becomes a MemberExpr.
+/// An implicit access may become either a MemberExpr or a
+/// DeclRefExpr, depending on whether the member is static.
class UnresolvedMemberExpr : public Expr {
/// The results. These are undesugared, which is to say, they may
/// include UsingShadowDecls.
UnresolvedSet Results;
/// \brief The expression for the base pointer or class reference,
- /// e.g., the \c x in x.f.
+ /// e.g., the \c x in x.f. This can be null if this is an 'unbased'
+ /// member expression
Stmt *Base;
+ /// \brief The type of the base expression; never null.
+ QualType BaseType;
+
/// \brief Whether this member expression used the '->' operator or
/// the '.' operator.
bool IsArrow : 1;
@@ -1672,7 +1702,7 @@ class UnresolvedMemberExpr : public Expr {
UnresolvedMemberExpr(QualType T, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1683,7 +1713,7 @@ class UnresolvedMemberExpr : public Expr {
public:
static UnresolvedMemberExpr *
Create(ASTContext &C, bool Dependent, bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1704,11 +1734,21 @@ public:
unsigned getNumDecls() const { return Results.size(); }
+ /// \brief True if this is an implicit access, i.e. one in which the
+ /// member being accessed was not written in the source. The source
+ /// location of the operator is invalid in this case.
+ bool isImplicitAccess() const { return Base == 0; }
+
/// \brief Retrieve the base object of this member expressions,
/// e.g., the \c x in \c x.m.
- Expr *getBase() { return cast<Expr>(Base); }
+ Expr *getBase() {
+ assert(!isImplicitAccess());
+ return cast<Expr>(Base);
+ }
void setBase(Expr *E) { Base = E; }
+ QualType getBaseType() const { return BaseType; }
+
/// \brief Determine whether this member expression used the '->'
/// operator; otherwise, it used the '.' operator.
bool isArrow() const { return IsArrow; }
@@ -1772,7 +1812,14 @@ public:
}
virtual SourceRange getSourceRange() const {
- SourceRange Range = Base->getSourceRange();
+ SourceRange Range;
+ if (!isImplicitAccess())
+ Range.setBegin(Base->getSourceRange().getBegin());
+ else if (getQualifier())
+ Range.setBegin(getQualifierRange().getBegin());
+ else
+ Range.setBegin(MemberLoc);
+
if (hasExplicitTemplateArgs())
Range.setEnd(getRAngleLoc());
else
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index d1a0390a0a..7a6fbdca8b 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -518,7 +518,8 @@ Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() {
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -527,8 +528,8 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(CXXDependentScopeMemberExprClass, C.DependentTy, true, true),
- Base(Base), IsArrow(IsArrow),
- HasExplicitTemplateArgumentList(TemplateArgs),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasExplicitTemplateArgs(TemplateArgs != 0),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
FirstQualifierFoundInScope(FirstQualifierFoundInScope),
@@ -539,7 +540,7 @@ CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -548,22 +549,22 @@ CXXDependentScopeMemberExpr::Create(ASTContext &C,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs) {
if (!TemplateArgs)
- return new (C) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
- FirstQualifierFoundInScope,
- Member, MemberLoc);
+ return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType,
+ IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member, MemberLoc);
std::size_t size = sizeof(CXXDependentScopeMemberExpr);
if (TemplateArgs)
size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
void *Mem = C.Allocate(size, llvm::alignof<CXXDependentScopeMemberExpr>());
- return new (Mem) CXXDependentScopeMemberExpr(C, Base, IsArrow, OperatorLoc,
- Qualifier, QualifierRange,
- FirstQualifierFoundInScope,
- Member,
- MemberLoc,
- TemplateArgs);
+ return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType,
+ IsArrow, OperatorLoc,
+ Qualifier, QualifierRange,
+ FirstQualifierFoundInScope,
+ Member, MemberLoc, TemplateArgs);
}
Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
@@ -571,12 +572,15 @@ Stmt::child_iterator CXXDependentScopeMemberExpr::child_begin() {
}
Stmt::child_iterator CXXDependentScopeMemberExpr::child_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -584,7 +588,8 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
SourceLocation MemberLoc,
const TemplateArgumentListInfo *TemplateArgs)
: Expr(UnresolvedMemberExprClass, T, Dependent, Dependent),
- Base(Base), IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing),
+ Base(Base), BaseType(BaseType), IsArrow(IsArrow),
+ HasUnresolvedUsing(HasUnresolvedUsing),
HasExplicitTemplateArgs(TemplateArgs != 0),
OperatorLoc(OperatorLoc),
Qualifier(Qualifier), QualifierRange(QualifierRange),
@@ -596,7 +601,7 @@ UnresolvedMemberExpr::UnresolvedMemberExpr(QualType T, bool Dependent,
UnresolvedMemberExpr *
UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -610,8 +615,8 @@ UnresolvedMemberExpr::Create(ASTContext &C, bool Dependent,
void *Mem = C.Allocate(size, llvm::alignof<UnresolvedMemberExpr>());
return new (Mem) UnresolvedMemberExpr(
Dependent ? C.DependentTy : C.OverloadTy,
- Dependent, HasUnresolvedUsing, Base, IsArrow,
- OperatorLoc, Qualifier, QualifierRange,
+ Dependent, HasUnresolvedUsing, Base, BaseType,
+ IsArrow, OperatorLoc, Qualifier, QualifierRange,
Member, MemberLoc, TemplateArgs);
}
@@ -620,5 +625,7 @@ Stmt::child_iterator UnresolvedMemberExpr::child_begin() {
}
Stmt::child_iterator UnresolvedMemberExpr::child_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 205ea0d182..a7e42af04d 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1145,17 +1145,19 @@ StmtPrinter::VisitCXXUnresolvedConstructExpr(
void StmtPrinter::VisitCXXDependentScopeMemberExpr(
CXXDependentScopeMemberExpr *Node) {
- PrintExpr(Node->getBase());
- OS << (Node->isArrow() ? "->" : ".");
+ if (!Node->isImplicitAccess()) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
- else if (Node->hasExplicitTemplateArgumentList())
+ else if (Node->hasExplicitTemplateArgs())
// FIXME: Track use of "template" keyword explicitly?
OS << "template ";
OS << Node->getMember().getAsString();
- if (Node->hasExplicitTemplateArgumentList()) {
+ if (Node->hasExplicitTemplateArgs()) {
OS << TemplateSpecializationType::PrintTemplateArgumentList(
Node->getTemplateArgs(),
Node->getNumTemplateArgs(),
@@ -1164,8 +1166,10 @@ void StmtPrinter::VisitCXXDependentScopeMemberExpr(
}
void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) {
- PrintExpr(Node->getBase());
- OS << (Node->isArrow() ? "->" : ".");
+ if (!Node->isImplicitAccess()) {
+ PrintExpr(Node->getBase());
+ OS << (Node->isArrow() ? "->" : ".");
+ }
if (NestedNameSpecifier *Qualifier = Node->getQualifier())
Qualifier->print(OS, Policy);
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d832a4649e..1b6b022901 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -554,18 +554,24 @@ StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) {
void
StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) {
- VisitExpr(S);
- ID.AddBoolean(S->isArrow());
+ ID.AddBoolean(S->isImplicitAccess());
+ if (!S->isImplicitAccess()) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ }
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMember());
- ID.AddBoolean(S->hasExplicitTemplateArgumentList());
- if (S->hasExplicitTemplateArgumentList())
+ ID.AddBoolean(S->hasExplicitTemplateArgs());
+ if (S->hasExplicitTemplateArgs())
VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs());
}
void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) {
- VisitExpr(S);
- ID.AddBoolean(S->isArrow());
+ ID.AddBoolean(S->isImplicitAccess());
+ if (!S->isImplicitAccess()) {
+ VisitExpr(S);
+ ID.AddBoolean(S->isArrow());
+ }
VisitNestedNameSpecifier(S->getQualifier());
VisitName(S->getMemberName());
ID.AddBoolean(S->hasExplicitTemplateArgs());
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f961406e3e..4b437995f1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1023,7 +1023,7 @@ public:
SourceLocation RLoc,
ExprArg Base,ExprArg Idx);
- ExprResult
+ OwningExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
@@ -1451,9 +1451,10 @@ public:
FieldDecl *Field,
Expr *BaseObjectExpr = 0,
SourceLocation OpLoc = SourceLocation());
- OwningExprResult BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs);
+ OwningExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+ bool IsDefiniteInstance);
bool UseArgumentDependentLookup(const CXXScopeSpec &SS,
const LookupResult &R,
bool HasTrailingLParen);
@@ -1525,6 +1526,7 @@ public:
SourceLocation RLoc);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
const CXXScopeSpec &SS,
@@ -1534,6 +1536,7 @@ public:
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
LookupResult &R,
@@ -1551,6 +1554,7 @@ public:
const LookupResult &R);
OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+ QualType BaseType,
bool IsArrow,
SourceLocation OpLoc,
const CXXScopeSpec &SS,
@@ -1592,6 +1596,11 @@ public:
MultiExprArg Args,
SourceLocation *CommaLocs,
SourceLocation RParenLoc);
+ OwningExprResult BuildResolvedCallExpr(Expr *Fn,
+ NamedDecl *NDecl,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc);
virtual OwningExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc,
TypeTy *Ty, SourceLocation RParenLoc,
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bf14d0d303..8e14fcdd6b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -703,18 +703,173 @@ static bool IsDependentIdExpression(Sema &SemaRef, const CXXScopeSpec &SS) {
// We can't look into record types unless they're fully-formed.
if (!IsFullyFormedScope(SemaRef, cast<CXXRecordDecl>(DC))) return true;
- // We can always look into fully-formed record types, but if we're
- // in a dependent but not fully-formed context, we can't decide
- // whether the qualifier names a base class. We shouldn't be trying
- // to decide that yet anyway, but we are, so we need to delay that
- // decision.
- CXXRecordDecl *CurRecord;
- if (CXXMethodDecl *CurMethod = dyn_cast<CXXMethodDecl>(SemaRef.CurContext))
- CurRecord = cast<CXXRecordDecl>(CurMethod->getParent());
- else
- CurRecord = dyn_cast<CXXRecordDecl>(SemaRef.CurContext);
+ return false;
+}
+
+/// Determines if the given class is provably not derived from all of
+/// the prospective base classes.
+static bool IsProvablyNotDerivedFrom(Sema &SemaRef,
+ CXXRecordDecl *Record,
+ const llvm::SmallPtrSet<CXXRecordDecl*, 4> &Bases) {
+ Record = Record->getCanonicalDecl();
+ if (Bases.count(Record))
+ return false;
+
+ for (CXXRecordDecl::base_class_iterator I = Record->bases_begin(),
+ E = Record->bases_end(); I != E; ++I) {
+ CanQualType BaseT = SemaRef.Context.getCanonicalType((*I).getType());
+ CanQual<RecordType> BaseRT = BaseT->getAs<RecordType>();
+ if (!BaseRT) return false;
+
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
+ if (!BaseRecord->isDefinition())
+ return false;
+
+ if (!IsProvablyNotDerivedFrom(SemaRef, BaseRecord, Bases))
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsInstanceMember(NamedDecl *D) {
+ assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
+ "checking whether non-member is instance member");
+
+ if (isa<FieldDecl>(D)) return true;
+
+ if (isa<CXXMethodDecl>(D))
+ return !cast<CXXMethodDecl>(D)->isStatic();
+
+ if (isa<FunctionTemplateDecl>(D)) {
+ D = cast<FunctionTemplateDecl>(D)->getTemplatedDecl();
+ return !cast<CXXMethodDecl>(D)->isStatic();
+ }
+
+ return false;
+}
+
+enum IMAKind {
+ /// The reference is definitely not an instance member access.
+ IMA_Static,
+
+ /// The reference may be an implicit instance member access.
+ IMA_Mixed,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is not an instance method.
+ IMA_Mixed_StaticContext,
+
+ /// The reference may be to an instance member, but it is invalid if
+ /// so, because the context is from an unrelated class.
+ IMA_Mixed_Unrelated,
+
+ /// The reference is definitely an implicit instance member access.
+ IMA_Instance,
+
+ /// The reference may be to an unresolved using declaration.
+ IMA_Unresolved,
+
+ /// The reference may be to an unresolved using declaration and the
+ /// context is not an instance method.
+ IMA_Unresolved_StaticContext,
+
+ /// The reference is to a member of an anonymous structure in a
+ /// non-class context.
+ IMA_AnonymousMember,
+
+ /// All possible referrents are instance members and the current
+ /// context is not an instance method.
+ IMA_Error_StaticContext,
+
+ /// All possible referrents are instance members of an unrelated
+ /// class.
+ IMA_Error_Unrelated
+};
- return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
+/// The given lookup names class member(s) and is not being used for
+/// an address-of-member expression. Classify the type of access
+/// according to whether it's possible that this reference names an
+/// instance member. This is best-effort; it is okay to
+/// conservatively answer "yes", in which case some errors will simply
+/// not be caught until template-instantiation.
+static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
+ const LookupResult &R) {
+ assert(!R.empty() && isa<CXXRecordDecl>((*R.begin())->getDeclContext()));
+
+ bool isStaticContext =
+ (!isa<CXXMethodDecl>(SemaRef.CurContext) ||
+ cast<CXXMethodDecl>(SemaRef.CurContext)->isStatic());
+
+ if (R.isUnresolvableResult())
+ return isStaticContext ? IMA_Unresolved_StaticContext : IMA_Unresolved;
+
+ // Collect all the declaring classes of instance members we find.
+ bool hasNonInstance = false;
+ llvm::SmallPtrSet<CXXRecordDecl*, 4> Classes;
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ NamedDecl *D = (*I)->getUnderlyingDecl();
+ if (IsInstanceMember(D)) {
+ CXXRecordDecl *R = cast<CXXRecordDecl>(D->getDeclContext());
+
+ // If this is a member of an anonymous record, move out to the
+ // innermost non-anonymous struct or union. If there isn't one,
+ // that's a special case.
+ while (R->isAnonymousStructOrUnion()) {
+ R = dyn_cast<CXXRecordDecl>(R->getParent());
+ if (!R) return IMA_AnonymousMember;
+ }
+ Classes.insert(R->getCanonicalDecl());
+ }
+ else
+ hasNonInstance = true;
+ }
+
+ // If we didn't find any instance members, it can't be an implicit
+ // member reference.
+ if (Classes.empty())
+ return IMA_Static;
+
+ // If the current context is not an instance method, it can't be
+ // an implicit member reference.
+ if (isStaticContext)
+ return (hasNonInstance ? IMA_Mixed_StaticContext : IMA_Error_StaticContext);
+
+ // If we can prove that the current context is unrelated to all the
+ // declaring classes, it can't be an implicit member reference (in
+ // which case it's an error if any of those members are selected).
+ if (IsProvablyNotDerivedFrom(SemaRef,
+ cast<CXXMethodDecl>(SemaRef.CurContext)->getParent(),
+ Classes))
+ return (hasNonInstance ? IMA_Mixed_Unrelated : IMA_Error_Unrelated);
+
+ return (hasNonInstance ? IMA_Mixed : IMA_Instance);
+}
+
+/// Diagnose a reference to a field with no object available.
+static void DiagnoseInstanceReference(Sema &SemaRef,
+ const CXXScopeSpec &SS,
+ const LookupResult &R) {
+ SourceLocation Loc = R.getNameLoc();
+ SourceRange Range(Loc);
+ if (SS.isSet()) Range.setBegin(SS.getRange().getBegin());
+
+ if (R.getAsSingle<FieldDecl>()) {
+ if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(SemaRef.CurContext)) {
+ if (MD->isStatic()) {
+ // "invalid use of member 'x' in static member function"
+ SemaRef.Diag(Loc, diag::err_invalid_member_use_in_static_method)
+ << Range << R.getLookupName();
+ return;
+ }
+ }
+
+ SemaRef.Diag(Loc, diag::err_invalid_non_static_member_use)
+ << R.getLookupName() << Range;
+ return;
+ }
+
+ SemaRef.Diag(Loc, diag::err_member_call_without_object) << Range;
}
Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
@@ -847,23 +1002,41 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S,
}
}
- // &SomeClass::foo is an abstract member reference, regardless of
- // the nature of foo, but &SomeClass::foo(...) is not. If this is
- // *not* an abstract member reference, and any of the results is a
- // class member (which necessarily means they're all class members),
- // then we make an implicit member reference instead.
- //
- // This check considers all the same information as the "needs ADL"
- // check, but there's no simple logical relationship other than the
- // fact that they can never be simultaneously true. We could
- // calculate them both in one pass if that proves important for
- // performance.
- if (!ADL) {
+ // Check whether this might be a C++ implicit instance member access.
+ // C++ [expr.prim.general]p6:
+ // Within the definition of a non-static member function, an
+ // identifier that names a non-static member is transformed to a
+ // class member access expression.
+ // But note that &SomeClass::foo is grammatically distinct, even
+ // though we don't parse it that way.
+ if (!R.empty() && (*R.begin())->getDeclContext()->isRecord()) {
bool isAbstractMemberPointer = (isAddressOfOperand && !SS.isEmpty());
- if (!isAbstractMemberPointer && !R.empty() &&
- isa<CXXRecordDecl>((*R.begin())->getDeclContext())) {
- return BuildImplicitMemberReferenceExpr(SS, R, TemplateArgs);
+ if (!isAbstractMemberPointer) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
+ case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, true);
+
+ case IMA_AnonymousMember:
+ assert(R.isSingleResult());
+ return BuildAnonymousStructUnionMemberReference(R.getNameLoc(),
+ R.getAsSingle<FieldDecl>());
+
+ case IMA_Mixed:
+ case IMA_Mixed_Unrelated:
+ case IMA_Unresolved:
+ return BuildImplicitMemberExpr(SS, R, TemplateArgs, false);
+
+ case IMA_Static:
+ case IMA_Mixed_StaticContext:
+ case IMA_Unresolved_StaticContext:
+ break;
+
+ case IMA_Error_StaticContext:
+ case IMA_Error_Unrelated:
+ DiagnoseInstanceReference(*this, SS, R);
+ return ExprError();
+ }
}
}
@@ -1041,35 +1214,15 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow,
Member, Loc, TemplateArgs, Ty);
}
-/// Return true if all the decls in the given result are instance
-/// methods.
-static bool IsOnlyInstanceMethods(const LookupResult &R) {
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- NamedDecl *D = (*I)->getUnderlyingDecl();
-
- CXXMethodDecl *Method;
- if (isa<FunctionTemplateDecl>(D))
- Method = cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D)
- ->getTemplatedDecl());
- else if (isa<CXXMethodDecl>(D))
- Method = cast<CXXMethodDecl>(D);
- else
- return false;
-
- if (Method->isStatic())
- return false;
- }
-
- return true;
-}
-
-/// Builds an implicit member access expression from the given
-/// unqualified lookup set, which is known to contain only class
-/// members.
+/// Builds an implicit member access expression. The current context
+/// is known to be an instance method, and the given unqualified lookup
+/// set is known to contain only instance members, at least one of which
+/// is from an appropriate type.
Sema::OwningExprResult
-Sema::BuildImplicitMemberReferenceExpr(const CXXScopeSpec &SS,
- LookupResult &R,
- const TemplateArgumentListInfo *TemplateArgs) {
+Sema::BuildImplicitMemberExpr(const CXXScopeSpec &SS,
+ LookupResult &R,
+ const TemplateArgumentListInfo *TemplateArgs,
+