[cfe-commits] r90266 - in /cfe/trunk: include/clang/AST/ExprCXX.h lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtProfile.cpp lib/Sema/Sema.h lib/Sema/SemaExpr.cpp lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/SemaTemplate/instantiate-method.cpp test/SemaTemplate/qualified-id.cpp
John McCall
rjmccall at apple.com
Tue Dec 1 14:10:20 PST 2009
Author: rjmccall
Date: Tue Dec 1 16:10:20 2009
New Revision: 90266
URL: http://llvm.org/viewvc/llvm-project?rev=90266&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/ExprCXX.h
cfe/trunk/lib/AST/ExprCXX.cpp
cfe/trunk/lib/AST/StmtPrinter.cpp
cfe/trunk/lib/AST/StmtProfile.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/TreeTransform.h
cfe/trunk/test/SemaTemplate/instantiate-method.cpp
cfe/trunk/test/SemaTemplate/qualified-id.cpp
Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Tue Dec 1 16:10:20 2009
@@ -1410,18 +1410,26 @@
/// \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 @@
/// \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 @@
}
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1477,7 +1483,8 @@
public:
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -1485,15 +1492,15 @@
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 @@
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 @@
/// \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 @@
};
/// \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 @@
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 @@
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 @@
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 @@
}
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
Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Tue Dec 1 16:10:20 2009
@@ -518,7 +518,8 @@
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -527,8 +528,8 @@
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::Create(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
@@ -548,22 +549,22 @@
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_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 @@
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::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 @@
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_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Tue Dec 1 16:10:20 2009
@@ -1145,17 +1145,19 @@
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::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);
Modified: cfe/trunk/lib/AST/StmtProfile.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtProfile.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/AST/StmtProfile.cpp (original)
+++ cfe/trunk/lib/AST/StmtProfile.cpp Tue Dec 1 16:10:20 2009
@@ -554,18 +554,24 @@
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());
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Dec 1 16:10:20 2009
@@ -1023,7 +1023,7 @@
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 @@
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 @@
SourceLocation RLoc);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
const CXXScopeSpec &SS,
@@ -1534,6 +1536,7 @@
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
LookupResult &R,
@@ -1551,6 +1554,7 @@
const LookupResult &R);
OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+ QualType BaseType,
bool IsArrow,
SourceLocation OpLoc,
const CXXScopeSpec &SS,
@@ -1592,6 +1596,11 @@
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,
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Dec 1 16:10:20 2009
@@ -703,18 +703,173 @@
// 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;
- return CurRecord && !IsFullyFormedScope(SemaRef, CurRecord);
+ 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
+};
+
+/// 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 @@
}
}
- // &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 @@
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,
+ bool IsKnownInstance) {
assert(!R.empty() && !R.isAmbiguous());
SourceLocation Loc = R.getNameLoc();
@@ -1082,44 +1235,18 @@
if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
return BuildAnonymousStructUnionMemberReference(Loc, FD);
- QualType ThisType;
- if (isImplicitMemberReference(R, ThisType)) {
- Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
- return BuildMemberReferenceExpr(ExprArg(*this, This),
- /*OpLoc*/ SourceLocation(),
- /*IsArrow*/ true,
- SS, R, TemplateArgs);
+ // If this is known to be an instance access, go ahead and build a
+ // 'this' expression now.
+ QualType ThisType = cast<CXXMethodDecl>(CurContext)->getThisType(Context);
+ Expr *This = 0; // null signifies implicit access
+ if (IsKnownInstance) {
+ This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
}
- // Diagnose now if none of the available methods are static.
- if (IsOnlyInstanceMethods(R))
- return ExprError(Diag(Loc, diag::err_member_call_without_object));
-
- if (R.getAsSingle<FieldDecl>()) {
- if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
- if (MD->isStatic()) {
- // "invalid use of member 'x' in static member function"
- Diag(Loc, diag::err_invalid_member_use_in_static_method)
- << R.getLookupName();
- return ExprError();
- }
- }
-
- // Any other ways we could have found the field in a well-formed
- // program would have been turned into implicit member expressions
- // above.
- Diag(Loc, diag::err_invalid_non_static_member_use)
- << R.getLookupName();
- return ExprError();
- }
-
- // We're not in an implicit member-reference context, but the lookup
- // results might not require an instance. Try to build a non-member
- // decl reference.
- if (TemplateArgs)
- return BuildTemplateIdExpr(SS, R, /* ADL */ false, *TemplateArgs);
-
- return BuildDeclarationNameExpr(SS, R, /*ADL*/ false);
+ return BuildMemberReferenceExpr(ExprArg(*this, This), ThisType,
+ /*OpLoc*/ SourceLocation(),
+ /*IsArrow*/ true,
+ SS, R, TemplateArgs);
}
bool Sema::UseArgumentDependentLookup(const CXXScopeSpec &SS,
@@ -1205,8 +1332,6 @@
Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R,
bool NeedsADL) {
- assert(R.getResultKind() != LookupResult::FoundUnresolvedValue);
-
// If this isn't an overloaded result and we don't need ADL, just
// build an ordinary singleton decl ref.
if (!NeedsADL && !R.isOverloadedResult())
@@ -1968,7 +2093,8 @@
}
Sema::OwningExprResult
-Sema::ActOnDependentMemberExpr(ExprArg Base, bool IsArrow, SourceLocation OpLoc,
+Sema::ActOnDependentMemberExpr(ExprArg Base, QualType BaseType,
+ bool IsArrow, SourceLocation OpLoc,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
DeclarationName Name, SourceLocation NameLoc,
@@ -1985,20 +2111,21 @@
// accessing the 'f' property if T is an Obj-C interface. The extra check
// allows this, while still reporting an error if T is a struct pointer.
if (!IsArrow) {
- const PointerType *PT = BaseExpr->getType()->getAs<PointerType>();
+ const PointerType *PT = BaseType->getAs<PointerType>();
if (PT && (!getLangOptions().ObjC1 ||
PT->getPointeeType()->isRecordType())) {
+ assert(BaseExpr && "cannot happen with implicit member accesses");
Diag(NameLoc, diag::err_typecheck_member_reference_struct_union)
- << BaseExpr->getType() << BaseExpr->getSourceRange();
+ << BaseType << BaseExpr->getSourceRange();
return ExprError();
}
}
- assert(BaseExpr->getType()->isDependentType());
+ assert(BaseType->isDependentType());
// 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.
- return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr,
+ return Owned(CXXDependentScopeMemberExpr::Create(Context, BaseExpr, BaseType,
IsArrow, OpLoc,
static_cast<NestedNameSpecifier*>(SS.getScopeRep()),
SS.getRange(),
@@ -2041,34 +2168,71 @@
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
const LookupResult &R) {
- QualType BaseTypeCanon
- = Context.getCanonicalType(BaseType).getUnqualifiedType();
-
- bool FoundValid = false;
+ const RecordType *BaseRT = BaseType->getAs<RecordType>();
+ if (!BaseRT) {
+ // We can't check this yet because the base type is still
+ // dependent.
+ assert(BaseType->isDependentType());
+ return false;
+ }
+ CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseRT->getDecl());
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
- TypeDecl* TyD = cast<TypeDecl>((*I)->getUnderlyingDecl()->getDeclContext());
- CanQualType MemberTypeCanon
- = Context.getCanonicalType(Context.getTypeDeclType(TyD));
-
- if (BaseTypeCanon == MemberTypeCanon ||
- IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) {
- FoundValid = true;
- break;
- }
+ // If this is an implicit member reference and we find a
+ // non-instance member, it's not an error.
+ if (!BaseExpr && !IsInstanceMember((*I)->getUnderlyingDecl()))
+ return false;
+
+ // Note that we use the DC of the decl, not the underlying decl.
+ CXXRecordDecl *RecordD = cast<CXXRecordDecl>((*I)->getDeclContext());
+ while (RecordD->isAnonymousStructOrUnion())
+ RecordD = cast<CXXRecordDecl>(RecordD->getParent());
+
+ llvm::SmallPtrSet<CXXRecordDecl*,4> MemberRecord;
+ MemberRecord.insert(RecordD->getCanonicalDecl());
+
+ if (!IsProvablyNotDerivedFrom(*this, BaseRecord, MemberRecord))
+ return false;
}
- if (!FoundValid) {
- DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
+ DiagnoseQualifiedMemberReference(*this, BaseExpr, BaseType,
Qualifier, QualifierRange, R);
+ return true;
+}
+
+static bool
+LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
+ SourceRange BaseRange, const RecordType *RTy,
+ SourceLocation OpLoc, const CXXScopeSpec &SS) {
+ RecordDecl *RDecl = RTy->getDecl();
+ if (SemaRef.RequireCompleteType(OpLoc, QualType(RTy, 0),
+ PDiag(diag::err_typecheck_incomplete_tag)
+ << BaseRange))
return true;
+
+ DeclContext *DC = RDecl;
+ if (SS.isSet()) {
+ // If the member name was a qualified-id, look into the
+ // nested-name-specifier.
+ DC = SemaRef.computeDeclContext(SS, false);
+
+ assert(DC && "Cannot handle non-computable dependent contexts in lookup");
+
+ if (!isa<TypeDecl>(DC)) {
+ SemaRef.Diag(R.getNameLoc(), diag::err_qualified_member_nonclass)
+ << DC << SS.getRange();
+ return true;
+ }
}
+ // The record definition is complete, now look up the member.
+ SemaRef.LookupQualifiedName(R, DC);
+
return false;
}
Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg BaseArg,
+Sema::BuildMemberReferenceExpr(ExprArg BaseArg, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
NamedDecl *FirstQualifierInScope,
@@ -2076,38 +2240,52 @@
const TemplateArgumentListInfo *TemplateArgs) {
Expr *Base = BaseArg.takeAs<Expr>();
- if (Base->getType()->isDependentType())
- return ActOnDependentMemberExpr(ExprArg(*this, Base),
+ if (BaseType->isDependentType())
+ return ActOnDependentMemberExpr(ExprArg(*this, Base), BaseType,
IsArrow, OpLoc,
SS, FirstQualifierInScope,
Name, NameLoc,
TemplateArgs);
LookupResult R(*this, Name, NameLoc, LookupMemberName);
- OwningExprResult Result =
- LookupMemberExpr(R, Base, IsArrow, OpLoc,
- SS, FirstQualifierInScope,
- /*ObjCImpDecl*/ DeclPtrTy());
- if (Result.isInvalid()) {
- Owned(Base);
- return ExprError();
- }
+ // Implicit member accesses.
+ if (!Base) {
+ QualType RecordTy = BaseType;
+ if (IsArrow) RecordTy = RecordTy->getAs<PointerType>()->getPointeeType();
+ if (LookupMemberExprInRecord(*this, R, SourceRange(),
+ RecordTy->getAs<RecordType>(),
+ OpLoc, SS))
+ return ExprError();
- if (Result.get())
- return move(Result);
+ // Explicit member accesses.
+ } else {
+ OwningExprResult Result =
+ LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ /*ObjCImpDecl*/ DeclPtrTy());
- return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
- IsArrow, SS, R, TemplateArgs);
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+ }
+
+ return BuildMemberReferenceExpr(ExprArg(*this, Base), BaseType,
+ OpLoc, IsArrow, SS, R, TemplateArgs);
}
Sema::OwningExprResult
-Sema::BuildMemberReferenceExpr(ExprArg Base, SourceLocation OpLoc,
- bool IsArrow, const CXXScopeSpec &SS,
+Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType,
+ SourceLocation OpLoc, bool IsArrow,
+ const CXXScopeSpec &SS,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
Expr *BaseExpr = Base.takeAs<Expr>();
- QualType BaseType = BaseExpr->getType();
+ QualType BaseType = BaseExprType;
if (IsArrow) {
assert(BaseType->isPointerType());
BaseType = BaseType->getAs<PointerType>()->getPointeeType();
@@ -2128,7 +2306,8 @@
: BaseType->getAs<RecordType>()->getDecl());
Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC << BaseExpr->getSourceRange();
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
return ExprError();
}
@@ -2142,15 +2321,15 @@
// Construct an unresolved result if we in fact got an unresolved
// result.
if (R.isOverloadedResult() || R.isUnresolvableResult()) {
- bool Dependent = R.isUnresolvableResult();
- Dependent = Dependent ||
- UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(),
- TemplateArgs);
+ bool Dependent =
+ R.isUnresolvableResult() ||
+ UnresolvedLookupExpr::ComputeDependence(R.begin(), R.end(), TemplateArgs);
UnresolvedMemberExpr *MemExpr
= UnresolvedMemberExpr::Create(Context, Dependent,
R.isUnresolvableResult(),
- BaseExpr, IsArrow, OpLoc,
+ BaseExpr, BaseExprType,
+ IsArrow, OpLoc,
Qualifier, SS.getRange(),
MemberName, MemberLoc,
TemplateArgs);
@@ -2171,6 +2350,15 @@
if (MemberDecl->isInvalidDecl())
return ExprError();
+ // Handle the implicit-member-access case.
+ if (!BaseExpr) {
+ // If this is not an instance member, convert to a non-member access.
+ if (!IsInstanceMember(MemberDecl))
+ return BuildDeclarationNameExpr(SS, R.getNameLoc(), MemberDecl);
+
+ BaseExpr = new (Context) CXXThisExpr(SourceLocation(), BaseExprType);
+ }
+
bool ShouldCheckUse = true;
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MemberDecl)) {
// Don't diagnose the use of a virtual member function unless it's
@@ -2403,31 +2591,9 @@
// Handle field access to simple records. This also handles access
// to fields of the ObjC 'id' struct.
if (const RecordType *RTy = BaseType->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
- if (RequireCompleteType(OpLoc, BaseType,
- PDiag(diag::err_typecheck_incomplete_tag)
- << BaseExpr->getSourceRange()))
+ if (LookupMemberExprInRecord(*this, R, BaseExpr->getSourceRange(),
+ RTy, OpLoc, SS))
return ExprError();
-
- DeclContext *DC = RDecl;
- if (SS.isSet()) {
- // If the member name was a qualified-id, look into the
- // nested-name-specifier.
- DC = computeDeclContext(SS, false);
-
- if (!isa<TypeDecl>(DC)) {
- Diag(MemberLoc, diag::err_qualified_member_nonclass)
- << DC << SS.getRange();
- return ExprError();
- }
-
- // FIXME: If DC is not computable, we should build a
- // CXXDependentScopeMemberExpr.
- assert(DC && "Cannot handle non-computable dependent contexts in lookup");
- }
-
- // The record definition is complete, now make sure the member is valid.
- LookupQualifiedName(R, DC);
return Owned((Expr*) 0);
}
@@ -2739,7 +2905,7 @@
Expr *Base = BaseArg.takeAs<Expr>();
OwningExprResult Result(*this);
if (Base->getType()->isDependentType()) {
- Result = ActOnDependentMemberExpr(ExprArg(*this, Base),
+ Result = ActOnDependentMemberExpr(ExprArg(*this, Base), Base->getType(),
IsArrow, OpLoc,
SS, FirstQualifierInScope,
Name, NameLoc,
@@ -2772,8 +2938,8 @@
}
}
- Result = BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
- IsArrow, SS, R, TemplateArgs);
+ Result = BuildMemberReferenceExpr(ExprArg(*this, Base), Base->getType(),
+ OpLoc, IsArrow, SS, R, TemplateArgs);
}
return move(Result);
@@ -3070,16 +3236,16 @@
isa<FunctionTemplateDecl>(*MemE->decls_begin()));
(void)MemE;
- return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- CommaLocs, RParenLoc));
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
}
// Determine whether this is a call to a member function.
if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(NakedFn)) {
NamedDecl *MemDecl = MemExpr->getMemberDecl();
if (isa<CXXMethodDecl>(MemDecl))
- return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
- CommaLocs, RParenLoc));
+ return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
+ CommaLocs, RParenLoc);
}
// Determine whether this is a call to a pointer-to-member function.
@@ -3171,13 +3337,28 @@
} else {
assert(Fns.size() <= 1 && "overloaded without Overloaded flag");
if (Fns.empty())
- NDecl = FDecl = 0;
+ NDecl = 0;
else {
NDecl = Fns[0];
- FDecl = dyn_cast<FunctionDecl>(NDecl);
}
}
+ return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc);
+}
+
+/// BuildCallExpr - Build a call to a resolved expression, i.e. an
+/// expression not of \p OverloadTy. The expression should
+/// unary-convert to an expression of function-pointer or
+/// block-pointer type.
+///
+/// \param NDecl the declaration being called, if available
+Sema::OwningExprResult
+Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
+ SourceLocation LParenLoc,
+ Expr **Args, unsigned NumArgs,
+ SourceLocation RParenLoc) {
+ FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
+
// Promote the function operand.
UsualUnaryConversions(Fn);
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Dec 1 16:10:20 2009
@@ -5122,7 +5122,7 @@
/// parameter). The caller needs to validate that the member
/// expression refers to a member function or an overloaded member
/// function.
-Sema::ExprResult
+Sema::OwningExprResult
Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
@@ -5131,22 +5131,35 @@
// argument and the member function we're referring to.
Expr *NakedMemExpr = MemExprE->IgnoreParens();
- // Extract the object argument.
- Expr *ObjectArg;
-
MemberExpr *MemExpr;
CXXMethodDecl *Method = 0;
if (isa<MemberExpr>(NakedMemExpr)) {
MemExpr = cast<MemberExpr>(NakedMemExpr);
- ObjectArg = MemExpr->getBase();
Method = cast<CXXMethodDecl>(MemExpr->getMemberDecl());
} else {
UnresolvedMemberExpr *UnresExpr = cast<UnresolvedMemberExpr>(NakedMemExpr);
- ObjectArg = UnresExpr->getBase();
+
+ // Mock up an object argument.
+ Expr *ObjectArg;
+ if (UnresExpr->isImplicitAccess()) {
+ // It would be nice to avoid creating this, but the overload APIs are written
+ // to work on expressions.
+ ObjectArg = new(Context) CXXThisExpr(SourceLocation(),
+ UnresExpr->getBaseType());
+ } else {
+ ObjectArg = UnresExpr->getBase();
+ }
// Add overload candidates
OverloadCandidateSet CandidateSet;
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ if (UnresExpr->hasExplicitTemplateArgs()) {
+ UnresExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
+ }
+
for (UnresolvedMemberExpr::decls_iterator I = UnresExpr->decls_begin(),
E = UnresExpr->decls_end(); I != E; ++I) {
@@ -5156,20 +5169,14 @@
if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
// If explicit template arguments were provided, we can't call a
// non-template member function.
- if (UnresExpr->hasExplicitTemplateArgs())
+ if (TemplateArgs)
continue;
AddMethodCandidate(Method, ObjectArg, Args, NumArgs, CandidateSet,
/*SuppressUserConversions=*/false);
} else {
- // FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (UnresExpr->hasExplicitTemplateArgs())
- UnresExpr->copyTemplateArgumentsInto(TemplateArgs);
-
AddMethodTemplateCandidate(cast<FunctionTemplateDecl>(Func),
- (UnresExpr->hasExplicitTemplateArgs()
- ? &TemplateArgs : 0),
+ TemplateArgs,
ObjectArg, Args, NumArgs,
CandidateSet,
/*SuppressUsedConversions=*/false);
@@ -5190,14 +5197,14 @@
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
case OR_Ambiguous:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_ambiguous_member_call)
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
case OR_Deleted:
Diag(UnresExpr->getMemberLoc(), diag::err_ovl_deleted_member_call)
@@ -5205,16 +5212,29 @@
<< DeclName << MemExprE->getSourceRange();
PrintOverloadCandidates(CandidateSet, /*OnlyViable=*/false);
// FIXME: Leaking incoming expressions!
- return true;
+ return ExprError();
}
MemExprE = FixOverloadedFunctionReference(MemExprE, Method);
+
+ // Clean up the 'this' expression we created above; FixOFR doesn't
+ // actually use it.
+ if (UnresExpr->isImplicitAccess())
+ Owned(ObjectArg);
+
+ // If overload resolution picked a static member, build a
+ // non-member call based on that function.
+ if (Method->isStatic()) {
+ return BuildResolvedCallExpr(MemExprE, Method, LParenLoc,
+ Args, NumArgs, RParenLoc);
+ }
+
MemExpr = cast<MemberExpr>(MemExprE->IgnoreParens());
}
assert(Method && "Member call to something that isn't a method?");
ExprOwningPtr<CXXMemberCallExpr>
- TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExpr, Args,
+ TheCall(this, new (Context) CXXMemberCallExpr(Context, MemExprE, Args,
NumArgs,
Method->getResultType().getNonReferenceType(),
RParenLoc));
@@ -5222,24 +5242,25 @@
// Check for a valid return type.
if (CheckCallReturnType(Method->getResultType(), MemExpr->getMemberLoc(),
TheCall.get(), Method))
- return true;
+ return ExprError();
// Convert the object argument (for a non-static member function call).
+ Expr *ObjectArg = MemExpr->getBase();
if (!Method->isStatic() &&
PerformObjectArgumentInitialization(ObjectArg, Method))
- return true;
+ return ExprError();
MemExpr->setBase(ObjectArg);
// Convert the rest of the arguments
const FunctionProtoType *Proto = cast<FunctionProtoType>(Method->getType());
if (ConvertArgumentsForCall(&*TheCall, MemExpr, Method, Proto, Args, NumArgs,
RParenLoc))
- return true;
+ return ExprError();
if (CheckFunctionCall(Method, TheCall.get()))
- return true;
+ return ExprError();
- return MaybeBindToTemporary(TheCall.release()).release();
+ return MaybeBindToTemporary(TheCall.release());
}
/// BuildCallToObjectOfClassType - Build a call to an object of class
@@ -5632,19 +5653,11 @@
}
if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
+ // FIXME: avoid copy.
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
if (ULE->hasExplicitTemplateArgs()) {
- // FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (ULE->hasExplicitTemplateArgs())
- ULE->copyTemplateArgumentsInto(TemplateArgs);
-
- return DeclRefExpr::Create(Context,
- ULE->getQualifier(),
- ULE->getQualifierRange(),
- Fn,
- ULE->getNameLoc(),
- Fn->getType(),
- &TemplateArgs);
+ ULE->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
}
return DeclRefExpr::Create(Context,
@@ -5652,23 +5665,43 @@
ULE->getQualifierRange(),
Fn,
ULE->getNameLoc(),
- Fn->getType());
+ Fn->getType(),
+ TemplateArgs);
}
if (UnresolvedMemberExpr *MemExpr = dyn_cast<UnresolvedMemberExpr>(E)) {
// FIXME: avoid copy.
- TemplateArgumentListInfo TemplateArgs;
- if (MemExpr->hasExplicitTemplateArgs())
- MemExpr->copyTemplateArgumentsInto(TemplateArgs);
+ TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = 0;
+ if (MemExpr->hasExplicitTemplateArgs()) {
+ MemExpr->copyTemplateArgumentsInto(TemplateArgsBuffer);
+ TemplateArgs = &TemplateArgsBuffer;
+ }
+
+ Expr *Base;
+
+ // If we're filling in
+ if (MemExpr->isImplicitAccess()) {
+ if (cast<CXXMethodDecl>(Fn)->isStatic()) {
+ return DeclRefExpr::Create(Context,
+ MemExpr->getQualifier(),
+ MemExpr->getQualifierRange(),
+ Fn,
+ MemExpr->getMemberLoc(),
+ Fn->getType(),
+ TemplateArgs);
+ } else
+ Base = new (Context) CXXThisExpr(SourceLocation(),
+ MemExpr->getBaseType());
+ } else
+ Base = MemExpr->getBase()->Retain();
- return MemberExpr::Create(Context, MemExpr->getBase()->Retain(),
+ return MemberExpr::Create(Context, Base,
MemExpr->isArrow(),
MemExpr->getQualifier(),
MemExpr->getQualifierRange(),
Fn,
MemExpr->getMemberLoc(),
- (MemExpr->hasExplicitTemplateArgs()
- ? &TemplateArgs : 0),
+ TemplateArgs,
Fn->getType());
}
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Dec 1 16:10:20 2009
@@ -361,13 +361,13 @@
QualType ThisType;
if (CheckForImplicitMember &&
IsImplicitDependentMemberReference(*this, Qualifier, ThisType)) {
- Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
-
// Since the 'this' expression is synthesized, we don't need to
// perform the double-lookup check.
NamedDecl *FirstQualifierInScope = 0;
- return Owned(CXXDependentScopeMemberExpr::Create(Context, This, true,
+ return Owned(CXXDependentScopeMemberExpr::Create(Context,
+ /*This*/ 0, ThisType,
+ /*IsArrow*/ true,
/*Op*/ SourceLocation(),
Qualifier, SS.getRange(),
FirstQualifierInScope,
Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Dec 1 16:10:20 2009
@@ -863,11 +863,14 @@
SS.setScopeRep(Qualifier);
}
+ QualType BaseType = ((Expr*) Base.get())->getType();
+
DeclarationName Name
= SemaRef.Context.DeclarationNames.getCXXDestructorName(
SemaRef.Context.getCanonicalType(DestroyedType));
- return getSema().BuildMemberReferenceExpr(move(Base), OperatorLoc, isArrow,
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+ OperatorLoc, isArrow,
SS, /*FIXME: FirstQualifier*/ 0,
Name, DestroyedTypeLoc,
/*TemplateArgs*/ 0);
@@ -964,7 +967,11 @@
SS.setScopeRep(Qualifier);
}
- return getSema().BuildMemberReferenceExpr(move(Base), OpLoc, isArrow,
+ QualType BaseType = ((Expr*) Base.get())->getType();
+
+ // FIXME: wait, this is re-performing lookup?
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
+ OpLoc, isArrow,
SS, FirstQualifierInScope,
Member->getDeclName(), MemberLoc,
ExplicitTemplateArgs);
@@ -1042,8 +1049,10 @@
SourceLocation OpLoc,
SourceLocation AccessorLoc,
IdentifierInfo &Accessor) {
+
CXXScopeSpec SS;
- return getSema().BuildMemberReferenceExpr(move(Base),
+ QualType BaseType = ((Expr*) Base.get())->getType();
+ return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
OpLoc, /*IsArrow*/ false,
SS, /*FirstQualifierInScope*/ 0,
DeclarationName(&Accessor),
@@ -1522,6 +1531,7 @@
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildCXXDependentScopeMemberExpr(ExprArg BaseE,
+ QualType BaseType,
bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
@@ -1534,7 +1544,8 @@
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- return SemaRef.BuildMemberReferenceExpr(move(BaseE), OperatorLoc, IsArrow,
+ return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+ OperatorLoc, IsArrow,
SS, FirstQualifierInScope,
Name, MemberLoc, TemplateArgs);
}
@@ -1544,19 +1555,19 @@
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
OwningExprResult RebuildUnresolvedMemberExpr(ExprArg BaseE,
+ QualType BaseType,
SourceLocation OperatorLoc,
bool IsArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs) {
- OwningExprResult Base = move(BaseE);
-
CXXScopeSpec SS;
SS.setRange(QualifierRange);
SS.setScopeRep(Qualifier);
- return SemaRef.BuildMemberReferenceExpr(move(Base), OperatorLoc, IsArrow,
+ return SemaRef.BuildMemberReferenceExpr(move(BaseE), BaseType,
+ OperatorLoc, IsArrow,
SS, R, TemplateArgs);
}
@@ -4819,18 +4830,32 @@
CXXDependentScopeMemberExpr *E,
bool isAddressOfOperand) {
// Transform the base of the expression.
- OwningExprResult Base = getDerived().TransformExpr(E->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ OwningExprResult Base(SemaRef, (Expr*) 0);
+ Expr *OldBase;
+ QualType BaseType;
+ QualType ObjectType;
+ if (!E->isImplicitAccess()) {
+ OldBase = E->getBase();
+ Base = getDerived().TransformExpr(OldBase);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
- // Start the member reference and compute the object's type.
- Sema::TypeTy *ObjectType = 0;
- Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
- E->getOperatorLoc(),
+ // Start the member reference and compute the object's type.
+ Sema::TypeTy *ObjectTy = 0;
+ Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
+ E->getOperatorLoc(),
E->isArrow()? tok::arrow : tok::period,
- ObjectType);
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ ObjectTy);
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+
+ ObjectType = QualType::getFromOpaquePtr(ObjectTy);
+ BaseType = ((Expr*) Base.get())->getType();
+ } else {
+ OldBase = 0;
+ BaseType = getDerived().TransformType(E->getBaseType());
+ ObjectType = BaseType->getAs<PointerType>()->getPointeeType();
+ }
// Transform the first part of the nested-name-specifier that qualifies
// the member name.
@@ -4843,29 +4868,31 @@
if (E->getQualifier()) {
Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange(),
- QualType::getFromOpaquePtr(ObjectType),
- FirstQualifierInScope);
+ ObjectType,
+ FirstQualifierInScope);
if (!Qualifier)
return SemaRef.ExprError();
}
DeclarationName Name
= getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(),
- QualType::getFromOpaquePtr(ObjectType));
+ ObjectType);
if (!Name)
return SemaRef.ExprError();
- if (!E->hasExplicitTemplateArgumentList()) {
+ if (!E->hasExplicitTemplateArgs()) {
// This is a reference to a member without an explicitly-specified
// template argument list. Optimize for this common case.
if (!getDerived().AlwaysRebuild() &&
- Base.get() == E->getBase() &&
+ Base.get() == OldBase &&
+ BaseType == E->getBaseType() &&
Qualifier == E->getQualifier() &&
Name == E->getMember() &&
FirstQualifierInScope == E->getFirstQualifierFoundInScope())
return SemaRef.Owned(E->Retain());
return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+ BaseType,
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
@@ -4885,6 +4912,7 @@
}
return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+ BaseType,
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
@@ -4900,9 +4928,16 @@
TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old,
bool isAddressOfOperand) {
// Transform the base of the expression.
- OwningExprResult Base = getDerived().TransformExpr(Old->getBase());
- if (Base.isInvalid())
- return SemaRef.ExprError();
+ OwningExprResult Base(SemaRef, (Expr*) 0);
+ QualType BaseType;
+ if (!Old->isImplicitAccess()) {
+ Base = getDerived().TransformExpr(Old->getBase());
+ if (Base.isInvalid())
+ return SemaRef.ExprError();
+ BaseType = ((Expr*) Base.get())->getType();
+ } else {
+ BaseType = getDerived().TransformType(Old->getBaseType());
+ }
NestedNameSpecifier *Qualifier = 0;
if (Old->getQualifier()) {
@@ -4951,6 +4986,7 @@
}
return getDerived().RebuildUnresolvedMemberExpr(move(Base),
+ BaseType,
Old->getOperatorLoc(),
Old->isArrow(),
Qualifier,
Modified: cfe/trunk/test/SemaTemplate/instantiate-method.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-method.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-method.cpp (original)
+++ cfe/trunk/test/SemaTemplate/instantiate-method.cpp Tue Dec 1 16:10:20 2009
@@ -95,9 +95,7 @@
template<typename U>
struct X1 : X0<U> {
int &f2() {
- // FIXME: We should be able to do this lookup and diagnose the error
- // *despite* the fact that we can't decide the relationship yet.
- return X0Base::f(); // expected-FIXME-error{{call to non-static member function without an object argument}}
+ return X0Base::f();
}
};
Modified: cfe/trunk/test/SemaTemplate/qualified-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/qualified-id.cpp?rev=90266&r1=90265&r2=90266&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/qualified-id.cpp (original)
+++ cfe/trunk/test/SemaTemplate/qualified-id.cpp Tue Dec 1 16:10:20 2009
@@ -18,3 +18,14 @@
}
};
}
+
+namespace test2 {
+ class Impl {
+ int foo();
+ };
+ template <class T> class Magic : public Impl {
+ int foo() {
+ return Impl::foo();
+ }
+ };
+}
More information about the cfe-commits
mailing list