/// \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;
/// \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);
}
}
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
public:
CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
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,
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; }
/// \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) {
};
/// \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;
UnresolvedMemberExpr(QualType T, bool Dependent,
bool HasUnresolvedUsing,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
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,
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; }
}
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
}
CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType,
+ bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
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),
CXXDependentScopeMemberExpr *
CXXDependentScopeMemberExpr::Create(ASTContext &C,
- Expr *Base, bool IsArrow,
+ Expr *Base, QualType BaseType, bool IsArrow,
SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
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() {
}
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,
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),
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,
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);
}
}
Stmt::child_iterator UnresolvedMemberExpr::child_end() {
+ if (isImplicitAccess())
+ return child_iterator(&Base);
return child_iterator(&Base + 1);
}
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(),
}
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);
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());
SourceLocation RLoc,
ExprArg Base,ExprArg Idx);
- ExprResult
+ OwningExprResult
BuildCallToMemberFunction(Scope *S, Expr *MemExpr,
SourceLocation LParenLoc, Expr **Args,
unsigned NumArgs, SourceLocation *CommaLocs,
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);
SourceLocation RLoc);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc,
bool IsArrow,
const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs);
OwningExprResult BuildMemberReferenceExpr(ExprArg Base,
+ QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
const CXXScopeSpec &SS,
LookupResult &R,
const LookupResult &R);
OwningExprResult ActOnDependentMemberExpr(ExprArg Base,
+ QualType BaseType,
bool IsArrow,
SourceLocation OpLoc,
const CXXScopeSpec &SS,
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,
// 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,
}
}
- // &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();
+ }
}
}
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();
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,
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())
}
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,
// 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(),
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 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;
- if (BaseTypeCanon == MemberTypeCanon ||
- IsDerivedFrom(BaseTypeCanon, MemberTypeCanon)) {
- FoundValid = true;
- break;
- }
+ // 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,
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();
+
+ // Explicit member accesses.
+ } else {
+ OwningExprResult Result =
+ LookupMemberExpr(R, Base, IsArrow, OpLoc,
+ SS, FirstQualifierInScope,
+ /*ObjCImpDecl*/ DeclPtrTy());
- if (Result.get())
- return move(Result);
+ if (Result.isInvalid()) {
+ Owned(Base);
+ return ExprError();
+ }
+
+ if (Result.get())
+ return move(Result);
+ }
- return BuildMemberReferenceExpr(ExprArg(*this, Base), OpLoc,
- IsArrow, SS, R, TemplateArgs);
+ 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();
: BaseType->getAs<RecordType>()->getDecl());
Diag(R.getNameLoc(), diag::err_no_member)
- << MemberName << DC << BaseExpr->getSourceRange();
+ << MemberName << DC
+ << (BaseExpr ? BaseExpr->getSourceRange() : SourceRange());
return ExprError();
}
// 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);
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
// 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);
}
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,
}
}
- 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);
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.
} 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);
/// 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,
// 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) {
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);
<< 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)
<< 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));
// 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
}
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,
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());
}
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,
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);
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);
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),
/// 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,
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);
}
/// 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);
}
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.
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,
}
return getDerived().RebuildCXXDependentScopeMemberExpr(move(Base),
+ BaseType,
E->isArrow(),
E->getOperatorLoc(),
Qualifier,
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()) {
}
return getDerived().RebuildUnresolvedMemberExpr(move(Base),
+ BaseType,
Old->getOperatorLoc(),
Old->isArrow(),
Qualifier,
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();
}
};
}
};
}
+
+namespace test2 {
+ class Impl {
+ int foo();
+ };
+ template <class T> class Magic : public Impl {
+ int foo() {
+ return Impl::foo();
+ }
+ };
+}