From: John McCall Date: Tue, 30 Mar 2010 21:47:33 +0000 (+0000) Subject: Propagate the "found declaration" (i.e. the using declaration instead of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6bb8017bb9e828d118e15e59d71c66bba323c364;p=clang Propagate the "found declaration" (i.e. the using declaration instead of the underlying/instantiated decl) through a lot of API, including "intermediate" MemberExprs required for (e.g.) template instantiation. This is necessary because of the access semantics of member accesses to using declarations: only the base class *containing the using decl* need be accessible from the naming class. This allows us to complete an access-controlled selfhost, if there are no recent regressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@99936 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 39530dba36..96436f511b 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -1263,6 +1263,11 @@ public: /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr : public Expr { + /// Extra data stored in some member expressions. + struct MemberNameQualifier : public NameQualifier { + NamedDecl *FoundDecl; + }; + /// Base - the expression for the base pointer or structure references. In /// X.F, this is "X". Stmt *Base; @@ -1278,27 +1283,26 @@ class MemberExpr : public Expr { bool IsArrow : 1; /// \brief True if this member expression used a nested-name-specifier to - /// refer to the member, e.g., "x->Base::f". When true, a NameQualifier + /// refer to the member, e.g., "x->Base::f", or found its member via a using + /// declaration. When true, a MemberNameQualifier /// structure is allocated immediately after the MemberExpr. - bool HasQualifier : 1; + bool HasQualifierOrFoundDecl : 1; /// \brief True if this member expression specified a template argument list /// explicitly, e.g., x->f. When true, an ExplicitTemplateArgumentList /// structure (and its TemplateArguments) are allocated immediately after /// the MemberExpr or, if the member expression also has a qualifier, after - /// the NameQualifier structure. + /// the MemberNameQualifier structure. bool HasExplicitTemplateArgumentList : 1; /// \brief Retrieve the qualifier that preceded the member name, if any. - NameQualifier *getMemberQualifier() { - if (!HasQualifier) - return 0; - - return reinterpret_cast (this + 1); + MemberNameQualifier *getMemberQualifier() { + assert(HasQualifierOrFoundDecl); + return reinterpret_cast (this + 1); } /// \brief Retrieve the qualifier that preceded the member name, if any. - const NameQualifier *getMemberQualifier() const { + const MemberNameQualifier *getMemberQualifier() const { return const_cast(this)->getMemberQualifier(); } @@ -1308,7 +1312,7 @@ class MemberExpr : public Expr { if (!HasExplicitTemplateArgumentList) return 0; - if (!HasQualifier) + if (!HasQualifierOrFoundDecl) return reinterpret_cast(this + 1); return reinterpret_cast( @@ -1321,26 +1325,22 @@ class MemberExpr : public Expr { return const_cast(this)->getExplicitTemplateArgumentList(); } - MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, ValueDecl *memberdecl, SourceLocation l, - const TemplateArgumentListInfo *targs, QualType ty); - public: MemberExpr(Expr *base, bool isarrow, ValueDecl *memberdecl, SourceLocation l, QualType ty) : Expr(MemberExprClass, ty, base->isTypeDependent(), base->isValueDependent()), Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(false), HasExplicitTemplateArgumentList(false) {} + HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) {} /// \brief Build an empty member reference expression. explicit MemberExpr(EmptyShell Empty) - : Expr(MemberExprClass, Empty), HasQualifier(false), + : Expr(MemberExprClass, Empty), HasQualifierOrFoundDecl(false), HasExplicitTemplateArgumentList(false) { } static MemberExpr *Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, - ValueDecl *memberdecl, + ValueDecl *memberdecl, NamedDecl *founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty); @@ -1355,16 +1355,23 @@ public: ValueDecl *getMemberDecl() const { return MemberDecl; } void setMemberDecl(ValueDecl *D) { MemberDecl = D; } + /// \brief Retrieves the declaration found by lookup. + NamedDecl *getFoundDecl() const { + if (!HasQualifierOrFoundDecl) + return getMemberDecl(); + return getMemberQualifier()->FoundDecl; + } + /// \brief Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. - bool hasQualifier() const { return HasQualifier; } + bool hasQualifier() const { return getQualifier() != 0; } /// \brief If the member name was qualified, retrieves the source range of /// the nested-name-specifier that precedes the member name. Otherwise, /// returns an empty source range. SourceRange getQualifierRange() const { - if (!HasQualifier) + if (!HasQualifierOrFoundDecl) return SourceRange(); return getMemberQualifier()->Range; @@ -1374,7 +1381,7 @@ public: /// nested-name-specifier that precedes the member name. Otherwise, returns /// NULL. NestedNameSpecifier *getQualifier() const { - if (!HasQualifier) + if (!HasQualifierOrFoundDecl) return 0; return getMemberQualifier()->NNS; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 935a2080dc..a9b5f36a98 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -499,44 +499,45 @@ QualType CallExpr::getCallReturnType() const { return FnType->getResultType(); } -MemberExpr::MemberExpr(Expr *base, bool isarrow, NestedNameSpecifier *qual, - SourceRange qualrange, ValueDecl *memberdecl, - SourceLocation l, const TemplateArgumentListInfo *targs, - QualType ty) - : Expr(MemberExprClass, ty, - base->isTypeDependent() || (qual && qual->isDependent()), - base->isValueDependent() || (qual && qual->isDependent())), - Base(base), MemberDecl(memberdecl), MemberLoc(l), IsArrow(isarrow), - HasQualifier(qual != 0), HasExplicitTemplateArgumentList(targs) { - // Initialize the qualifier, if any. - if (HasQualifier) { - NameQualifier *NQ = getMemberQualifier(); - NQ->NNS = qual; - NQ->Range = qualrange; - } - - // Initialize the explicit template argument list, if any. - if (targs) - getExplicitTemplateArgumentList()->initializeFrom(*targs); -} - MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, NestedNameSpecifier *qual, SourceRange qualrange, ValueDecl *memberdecl, + NamedDecl *founddecl, SourceLocation l, const TemplateArgumentListInfo *targs, QualType ty) { std::size_t Size = sizeof(MemberExpr); - if (qual != 0) - Size += sizeof(NameQualifier); + + bool hasQualOrFound = (qual != 0 || founddecl != memberdecl); + if (hasQualOrFound) + Size += sizeof(MemberNameQualifier); if (targs) Size += ExplicitTemplateArgumentList::sizeFor(*targs); void *Mem = C.Allocate(Size, llvm::alignof()); - return new (Mem) MemberExpr(base, isarrow, qual, qualrange, memberdecl, l, - targs, ty); + MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, l, ty); + + if (hasQualOrFound) { + if (qual && qual->isDependent()) { + E->setValueDependent(true); + E->setTypeDependent(true); + } + E->HasQualifierOrFoundDecl = true; + + MemberNameQualifier *NQ = E->getMemberQualifier(); + NQ->NNS = qual; + NQ->Range = qualrange; + NQ->FoundDecl = founddecl; + } + + if (targs) { + E->HasExplicitTemplateArgumentList = true; + E->getExplicitTemplateArgumentList()->initializeFrom(*targs); + } + + return E; } const char *CastExpr::getCastKindName() const { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 859e497576..d3e55f381e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1119,6 +1119,7 @@ public: CXXRecordDecl *ActingContext); bool PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method); ImplicitConversionSequence TryContextuallyConvertToBool(Expr *From); @@ -1126,6 +1127,7 @@ public: bool PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. @@ -1246,11 +1248,15 @@ public: const PartialDiagnostic &PDiag); FunctionDecl *ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain); + bool Complain, + DeclAccessPair &Found); FunctionDecl *ResolveSingleFunctionTemplateSpecialization(Expr *From); - Expr *FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn); + Expr *FixOverloadedFunctionReference(Expr *E, + NamedDecl *FoundDecl, + FunctionDecl *Fn); OwningExprResult FixOverloadedFunctionReference(OwningExprResult, + NamedDecl *FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, @@ -2395,7 +2401,9 @@ public: Expr *BuildObjCEncodeExpression(SourceLocation AtLoc, QualType EncodedType, SourceLocation RParenLoc); - CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, CXXMethodDecl *Method); + CXXMemberCallExpr *BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, + CXXMethodDecl *Method); virtual ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, @@ -2640,6 +2648,8 @@ public: Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); + AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index e7ea204137..e356c52a68 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -907,6 +907,31 @@ Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc, return CheckAccess(*this, OpLoc, Entity); } +Sema::AccessResult Sema::CheckAddressOfMemberAccess(Expr *OvlExpr, + DeclAccessPair Found) { + if (!getLangOptions().AccessControl || + Found.getAccess() == AS_public) + return AR_accessible; + + OverloadExpr *Ovl = OverloadExpr::find(OvlExpr).getPointer(); + NestedNameSpecifier *Qualifier = Ovl->getQualifier(); + assert(Qualifier && "address of overloaded member without qualifier"); + + CXXScopeSpec SS; + SS.setScopeRep(Qualifier); + SS.setRange(Ovl->getQualifierRange()); + DeclContext *DC = computeDeclContext(SS); + assert(DC && DC->isRecord() && "scope did not resolve to record"); + CXXRecordDecl *NamingClass = cast(DC); + + AccessedEntity Entity(Context, AccessedEntity::Member, NamingClass, Found); + Entity.setDiag(diag::err_access) + << Ovl->getSourceRange(); + + return CheckAccess(*this, Ovl->getNameLoc(), Entity); +} + + /// Checks access for a hierarchy conversion. /// /// \param IsBaseToDerived whether this is a base-to-derived conversion (true) diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 2b93d38e2a..11c8e6ddab 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -808,8 +808,10 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, return TC_NotApplicable; bool WasOverloadedFunction = false; + DeclAccessPair FoundOverload; if (FunctionDecl *Fn - = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) { + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false, + FoundOverload)) { CXXMethodDecl *M = cast(Fn); SrcType = Self.Context.getMemberPointerType(Fn->getType(), Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); @@ -870,13 +872,14 @@ TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType, // allowing complaints if something goes wrong. FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, - true); + true, + FoundOverload); if (!Fn) { msg = 0; return TC_Failed; } - SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn); + SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, FoundOverload, Fn); if (!SrcExpr) { msg = 0; return TC_Failed; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 49352b5f4e..dfaa85559b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -4409,16 +4409,18 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (Context.getCanonicalType(T2) == Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Init, DeclType, - ICS != 0); + ICS != 0, Found); if (Fn) { // Since we're performing this reference-initialization for // real, update the initializer with the resulting function. if (!ICS) { if (DiagnoseUseOfDecl(Fn, DeclLoc)) - return true; + return true; - Init = FixOverloadedFunctionReference(Init, Fn); + CheckAddressOfMemberAccess(Init, Found); + Init = FixOverloadedFunctionReference(Init, Found, Fn); } T2 = Fn->getType(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 0c9b3bd44b..406b8201a3 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -635,7 +635,7 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc, MemberType = Context.getQualifiedType(MemberType, NewQuals); MarkDeclarationReferenced(Loc, *FI); - PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI); + PerformObjectMemberConversion(Result, /*FIXME:Qualifier=*/0, *FI, *FI); // FIXME: Might this end up being a qualified name? Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI, OpLoc, MemberType); @@ -1355,10 +1355,27 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, return Owned((Expr*) 0); } -/// \brief Cast member's object to its own class if necessary. +/// \brief Cast a base object to a member's actual type. +/// +/// Logically this happens in three phases: +/// +/// * First we cast from the base type to the naming class. +/// The naming class is the class into which we were looking +/// when we found the member; it's the qualifier type if a +/// qualifier was provided, and otherwise it's the base type. +/// +/// * Next we cast from the naming class to the declaring class. +/// If the member we found was brought into a class's scope by +/// a using declaration, this is that class; otherwise it's +/// the class declaring the member. +/// +/// * Finally we cast from the declaring class to the "true" +/// declaring class of the member. This conversion does not +/// obey access control. bool Sema::PerformObjectMemberConversion(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, NamedDecl *Member) { CXXRecordDecl *RD = dyn_cast(Member->getDeclContext()); if (!RD) @@ -1406,6 +1423,9 @@ Sema::PerformObjectMemberConversion(Expr *&From, if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) return false; + SourceRange FromRange = From->getSourceRange(); + SourceLocation FromLoc = FromRange.getBegin(); + // C++ [class.member.lookup]p8: // [...] Ambiguities can often be resolved by qualifying a name with its // class name. @@ -1424,51 +1444,89 @@ Sema::PerformObjectMemberConversion(Expr *&From, // x = 17; // error: ambiguous base subobjects // Derived1::x = 17; // okay, pick the Base subobject of Derived1 // } - QualType IntermediateRecordType; - QualType IntermediateType; if (Qualifier) { - if (const RecordType *IntermediateRecord - = Qualifier->getAsType()->getAs()) { - IntermediateRecordType = QualType(IntermediateRecord, 0); - IntermediateType = IntermediateRecordType; + QualType QType = QualType(Qualifier->getAsType(), 0); + assert(!QType.isNull() && "lookup done with dependent qualifier?"); + assert(QType->isRecordType() && "lookup done with non-record type"); + + QualType QRecordType = QualType(QType->getAs(), 0); + + // In C++98, the qualifier type doesn't actually have to be a base + // type of the object type, in which case we just ignore it. + // Otherwise build the appropriate casts. + if (IsDerivedFrom(FromRecordType, QRecordType)) { + if (CheckDerivedToBaseConversion(FromRecordType, QRecordType, + FromLoc, FromRange)) + return true; + if (PointerConversions) - IntermediateType = Context.getPointerType(IntermediateType); + QType = Context.getPointerType(QType); + ImpCastExprToType(From, QType, CastExpr::CK_DerivedToBase, + /*isLvalue*/ !PointerConversions); + + FromType = QType; + FromRecordType = QRecordType; + + // If the qualifier type was the same as the destination type, + // we're done. + if (Context.hasSameUnqualifiedType(FromRecordType, DestRecordType)) + return false; } } - if (!IntermediateType.isNull() && - IsDerivedFrom(FromRecordType, IntermediateRecordType) && - IsDerivedFrom(IntermediateRecordType, DestRecordType)) { - if (CheckDerivedToBaseConversion(FromRecordType, IntermediateRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange()) || - CheckDerivedToBaseConversion(IntermediateRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) - return true; + bool IgnoreAccess = false; - ImpCastExprToType(From, IntermediateType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/!PointerConversions); - return false; + // If we actually found the member through a using declaration, cast + // down to the using declaration's type. + // + // Pointer equality is fine here because only one declaration of a + // class ever has member declarations. + if (FoundDecl->getDeclContext() != Member->getDeclContext()) { + assert(isa(FoundDecl)); + QualType URecordType = Context.getTypeDeclType( + cast(FoundDecl->getDeclContext())); + + // We only need to do this if the naming-class to declaring-class + // conversion is non-trivial. + if (!Context.hasSameUnqualifiedType(FromRecordType, URecordType)) { + assert(IsDerivedFrom(FromRecordType, URecordType)); + if (CheckDerivedToBaseConversion(FromRecordType, URecordType, + FromLoc, FromRange)) + return true; + + QualType UType = URecordType; + if (PointerConversions) + UType = Context.getPointerType(UType); + ImpCastExprToType(From, UType, CastExpr::CK_DerivedToBase, + /*isLvalue*/ !PointerConversions); + FromType = UType; + FromRecordType = URecordType; + } + + // We don't do access control for the conversion from the + // declaring class to the true declaring class. + IgnoreAccess = true; } if (CheckDerivedToBaseConversion(FromRecordType, DestRecordType, - From->getSourceRange().getBegin(), - From->getSourceRange())) + FromLoc, + FromRange, + IgnoreAccess)) return true; + // FIXME: isLvalue should be !PointerConversions here, but codegen + // does very silly things. ImpCastExprToType(From, DestType, CastExpr::CK_DerivedToBase, - /*isLvalue=*/true); + /*isLvalue=*/ true); return false; } /// \brief Build a MemberExpr AST node. static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, const CXXScopeSpec &SS, ValueDecl *Member, - SourceLocation Loc, QualType Ty, + NamedDecl *FoundDecl, SourceLocation Loc, + QualType Ty, const TemplateArgumentListInfo *TemplateArgs = 0) { NestedNameSpecifier *Qualifier = 0; SourceRange QualifierRange; @@ -1478,7 +1536,7 @@ static MemberExpr *BuildMemberExpr(ASTContext &C, Expr *Base, bool isArrow, } return MemberExpr::Create(C, Base, isArrow, Qualifier, QualifierRange, - Member, Loc, TemplateArgs, Ty); + Member, FoundDecl, Loc, TemplateArgs, Ty); } /// Builds an implicit member access expression. The current context @@ -2692,6 +2750,7 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } assert(R.isSingleResult()); + NamedDecl *FoundDecl = *R.begin(); NamedDecl *MemberDecl = R.getFoundDecl(); // FIXME: diagnose the presence of template arguments now. @@ -2754,30 +2813,30 @@ Sema::BuildMemberReferenceExpr(ExprArg Base, QualType BaseExprType, } MarkDeclarationReferenced(MemberLoc, FD); - if (PerformObjectMemberConversion(BaseExpr, Qualifier, FD)) + if (PerformObjectMemberConversion(BaseExpr, Qualifier, FoundDecl, FD)) return ExprError(); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - FD, MemberLoc, MemberType)); + FD, FoundDecl, MemberLoc, MemberType)); } if (VarDecl *Var = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, MemberLoc, + Var, FoundDecl, MemberLoc, Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, MemberLoc, + MemberFn, FoundDecl, MemberLoc, MemberFn->getType())); } if (EnumConstantDecl *Enum = dyn_cast(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Enum, MemberLoc, Enum->getType())); + Enum, FoundDecl, MemberLoc, Enum->getType())); } Owned(BaseExpr); @@ -6752,7 +6811,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, Res = BuildAnonymousStructUnionMemberReference( OC.LocEnd, MemberDecl, Res, OC.LocEnd).takeAs(); } else { - PerformObjectMemberConversion(Res, /*Qualifier=*/0, MemberDecl); + PerformObjectMemberConversion(Res, /*Qualifier=*/0, + *R.begin(), MemberDecl); // MemberDecl->getType() doesn't get the right qualifiers, but it // doesn't matter here. Res = new (Context) MemberExpr(Res, false, MemberDecl, OC.LocEnd, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index c31d93416d..9baa6ac079 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1650,14 +1650,16 @@ Sema::PerformImplicitConversion(Expr *&From, QualType ToType, case ICK_Function_To_Pointer: if (Context.getCanonicalType(FromType) == Context.OverloadTy) { - FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true); + DeclAccessPair Found; + FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, + true, Found); if (!Fn) return true; if (DiagnoseUseOfDecl(Fn, From->getSourceRange().getBegin())) return true; - From = FixOverloadedFunctionReference(From, Fn); + From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); // If there's already an address-of operator in the expression, we have @@ -2847,8 +2849,10 @@ Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base, } CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { - if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Exp, /*Qualifier=*/0, + FoundDecl, Method)) assert(0 && "Calling BuildCXXMemberCallExpr with invalid call?"); MemberExpr *ME = @@ -2892,7 +2896,8 @@ Sema::OwningExprResult Sema::BuildCXXCastArgument(SourceLocation CastLoc, assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); // Create an implicit call expr that calls it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method); + // FIXME: pass the FoundDecl for the user-defined conversion here + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(From, Method, Method); return MaybeBindToTemporary(CE); } } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 0b2e1db6a0..4612bda7b2 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -2036,13 +2036,13 @@ bool InitializationSequence::isAmbiguous() const { } void InitializationSequence::AddAddressOverloadResolutionStep( - FunctionDecl *Function) { + FunctionDecl *Function, + DeclAccessPair Found) { Step S; S.Kind = SK_ResolveAddressOfOverloadedFunction; S.Type = Function->getType(); - // Access is currently ignored for these. S.Function.Function = Function; - S.Function.FoundDecl = DeclAccessPair::make(Function, AS_none); + S.Function.FoundDecl = Found; Steps.push_back(S); } @@ -2375,15 +2375,17 @@ static void TryReferenceInitialization(Sema &S, // to resolve the overloaded function. If all goes well, T2 is the // type of the resulting function. if (S.Context.getCanonicalType(T2) == S.Context.OverloadTy) { + DeclAccessPair Found; FunctionDecl *Fn = S.ResolveAddressOfOverloadedFunction(Initializer, T1, - false); + false, + Found); if (!Fn) { Sequence.SetFailed(InitializationSequence::FK_AddressOfOverloadFailed); return; } - Sequence.AddAddressOverloadResolutionStep(Fn); + Sequence.AddAddressOverloadResolutionStep(Fn, Found); cv2T2 = Fn->getType(); T2 = cv2T2.getUnqualifiedType(); } @@ -3348,8 +3350,9 @@ InitializationSequence::Perform(Sema &S, case SK_ResolveAddressOfOverloadedFunction: // Overload resolution determined which function invoke; update the // initializer to reflect that choice. - // Access control was done in overload resolution. + S.CheckAddressOfMemberAccess(CurInitExpr, Step->Function.FoundDecl); CurInit = S.FixOverloadedFunctionReference(move(CurInit), + Step->Function.FoundDecl, Step->Function.Function); break; @@ -3457,7 +3460,7 @@ InitializationSequence::Perform(Sema &S, // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. if (S.PerformObjectArgumentInitialization(CurInitExpr, /*Qualifier=*/0, - Conversion)) + FoundFn, Conversion)) return S.ExprError(); // Do a little dance to make sure that CurInit has the proper @@ -3465,7 +3468,8 @@ InitializationSequence::Perform(Sema &S, CurInit.release(); // Build the actual call to the conversion function. - CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, Conversion)); + CurInit = S.Owned(S.BuildCXXMemberCallExpr(CurInitExpr, FoundFn, + Conversion)); if (CurInit.isInvalid() || !CurInit.get()) return S.ExprError(); @@ -3649,11 +3653,14 @@ bool InitializationSequence::Diagnose(Sema &S, << (Failure == FK_ArrayNeedsInitListOrStringLiteral); break; - case FK_AddressOfOverloadFailed: + case FK_AddressOfOverloadFailed: { + DeclAccessPair Found; S.ResolveAddressOfOverloadedFunction(Args[0], DestType.getNonReferenceType(), - true); + true, + Found); break; + } case FK_ReferenceInitOverloadFailed: case FK_UserConversionOverloadFailed: diff --git a/lib/Sema/SemaInit.h b/lib/Sema/SemaInit.h index d57679ab75..7c6327f8c7 100644 --- a/lib/Sema/SemaInit.h +++ b/lib/Sema/SemaInit.h @@ -611,7 +611,8 @@ public: /// /// \param Function the function to which the overloaded function reference /// resolves. - void AddAddressOverloadResolutionStep(FunctionDecl *Function); + void AddAddressOverloadResolutionStep(FunctionDecl *Function, + DeclAccessPair Found); /// \brief Add a new step in the initialization that performs a derived-to- /// base cast. diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 58d7d67508..8d3313982c 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -567,6 +567,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // array-to-pointer conversion, or function-to-pointer conversion // (C++ 4p1). + DeclAccessPair AccessPair; + // Lvalue-to-rvalue conversion (C++ 4.1): // An lvalue (3.10) of a non-function, non-array type T can be // converted to an rvalue. @@ -612,7 +614,8 @@ Sema::IsStandardConversion(Expr* From, QualType ToType, // function. (C++ 4.3p1). FromType = Context.getPointerType(FromType); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(From, ToType, false)) { + = ResolveAddressOfOverloadedFunction(From, ToType, false, + AccessPair)) { // Address of overloaded function (C++ [over.over]). SCS.First = ICK_Function_To_Pointer; @@ -2278,6 +2281,7 @@ Sema::TryObjectArgumentInitialization(QualType OrigFromType, bool Sema::PerformObjectArgumentInitialization(Expr *&From, NestedNameSpecifier *Qualifier, + NamedDecl *FoundDecl, CXXMethodDecl *Method) { QualType FromRecordType, DestType; QualType ImplicitParamRecordType = @@ -2302,7 +2306,7 @@ Sema::PerformObjectArgumentInitialization(Expr *&From, << ImplicitParamRecordType << FromRecordType << From->getSourceRange(); if (ICS.Standard.Second == ICK_Derived_To_Base) - return PerformObjectMemberConversion(From, Qualifier, Method); + return PerformObjectMemberConversion(From, Qualifier, FoundDecl, Method); if (!Context.hasSameType(From->getType(), DestType)) ImpCastExprToType(From, DestType, CastExpr::CK_NoOp, @@ -4942,7 +4946,8 @@ static bool CheckUnresolvedAccess(Sema &S, OverloadExpr *E, DeclAccessPair D) { /// routine will emit diagnostics if there is an error. FunctionDecl * Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, - bool Complain) { + bool Complain, + DeclAccessPair &FoundResult) { QualType FunctionType = ToType; bool IsMember = false; if (const PointerType *ToTypePtr = ToType->getAs()) @@ -5059,9 +5064,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; else if (Matches.size() == 1) { FunctionDecl *Result = Matches[0].second; + FoundResult = Matches[0].first; MarkDeclarationReferenced(From->getLocStart(), Result); if (Complain) - CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); + CheckAddressOfMemberAccess(OvlExpr, Matches[0].first); return Result; } @@ -5093,10 +5099,9 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, << (unsigned) oc_function_template); assert(Result != MatchesCopy.end() && "no most-specialized template"); MarkDeclarationReferenced(From->getLocStart(), *Result); - if (Complain) { - DeclAccessPair FoundDecl = Matches[Result - MatchesCopy.begin()].first; - CheckUnresolvedAccess(*this, OvlExpr, FoundDecl); - } + FoundResult = Matches[Result - MatchesCopy.begin()].first; + if (Complain) + CheckUnresolvedAccess(*this, OvlExpr, FoundResult); return cast(*Result); } @@ -5115,6 +5120,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, // selected function. if (Matches.size() == 1) { MarkDeclarationReferenced(From->getLocStart(), Matches[0].second); + FoundResult = Matches[0].first; if (Complain) CheckUnresolvedAccess(*this, OvlExpr, Matches[0].first); return cast(Matches[0].second); @@ -5395,7 +5401,7 @@ Sema::BuildOverloadedCallExpr(Expr *Fn, UnresolvedLookupExpr *ULE, case OR_Success: { FunctionDecl *FDecl = Best->Function; CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - Fn = FixOverloadedFunctionReference(Fn, FDecl); + Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc); } @@ -5522,7 +5528,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { CheckMemberOperatorAccess(OpLoc, Args[0], 0, Best->FoundDecl); - if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); } else { // Convert the arguments. @@ -5716,7 +5723,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return ExprError(); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); Args[1] = RHS = Arg1.takeAs(); @@ -5883,7 +5890,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Convert the arguments. CXXMethodDecl *Method = cast(FnDecl); if (PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/0, - Method)) + Best->FoundDecl, Method)) return ExprError(); // Convert the arguments. @@ -5988,10 +5995,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemberExpr *MemExpr; CXXMethodDecl *Method = 0; + NamedDecl *FoundDecl = 0; NestedNameSpecifier *Qualifier = 0; if (isa(NakedMemExpr)) { MemExpr = cast(NakedMemExpr); Method = cast(MemExpr->getMemberDecl()); + FoundDecl = MemExpr->getFoundDecl(); Qualifier = MemExpr->getQualifier(); } else { UnresolvedMemberExpr *UnresExpr = cast(NakedMemExpr); @@ -6041,6 +6050,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, switch (BestViableFunction(CandidateSet, UnresExpr->getLocStart(), Best)) { case OR_Success: Method = cast(Best->Function); + FoundDecl = Best->FoundDecl; CheckUnresolvedMemberAccess(UnresExpr, Best->FoundDecl); break; @@ -6068,7 +6078,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); } - MemExprE = FixOverloadedFunctionReference(MemExprE, Method); + MemExprE = FixOverloadedFunctionReference(MemExprE, FoundDecl, Method); // If overload resolution picked a static member, build a // non-member call based on that function. @@ -6093,9 +6103,12 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, return ExprError(); // Convert the object argument (for a non-static member function call). + // We only need to do this if there was actually an overload; otherwise + // it was done at lookup. Expr *ObjectArg = MemExpr->getBase(); if (!Method->isStatic() && - PerformObjectArgumentInitialization(ObjectArg, Qualifier, Method)) + PerformObjectArgumentInitialization(ObjectArg, Qualifier, + FoundDecl, Method)) return ExprError(); MemExpr->setBase(ObjectArg); @@ -6255,7 +6268,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Create an implicit member expr to refer to the conversion operator. // and then call it. - CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Conv); + CXXMemberCallExpr *CE = BuildCXXMemberCallExpr(Object, Best->FoundDecl, + Conv); return ActOnCallExpr(S, ExprArg(*this, CE), LParenLoc, MultiExprArg(*this, (ExprTy**)Args, NumArgs), @@ -6315,7 +6329,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object, // Initialize the implicit object parameter. IsError |= PerformObjectArgumentInitialization(Object, /*Qualifier=*/0, - Method); + Best->FoundDecl, Method); TheCall->setArg(0, Object); @@ -6436,7 +6450,8 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { // Convert the object parameter. CXXMethodDecl *Method = cast(Best->Function); - if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, Method)) + if (PerformObjectArgumentInitialization(Base, /*Qualifier=*/0, + Best->FoundDecl, Method)) return ExprError(); // No concerns about early exits now. @@ -6463,9 +6478,11 @@ Sema::BuildOverloadedArrowExpr(Scope *S, ExprArg BaseIn, SourceLocation OpLoc) { /// perhaps a '&' around it). We have resolved the overloaded function /// to the function declaration Fn, so patch up the expression E to /// refer (possibly indirectly) to Fn. Returns the new expr. -Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { +Expr *Sema::FixOverloadedFunctionReference(Expr *E, NamedDecl *Found, + FunctionDecl *Fn) { if (ParenExpr *PE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(PE->getSubExpr(), + Found, Fn); if (SubExpr == PE->getSubExpr()) return PE->Retain(); @@ -6473,7 +6490,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } if (ImplicitCastExpr *ICE = dyn_cast(E)) { - Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(ICE->getSubExpr(), + Found, Fn); assert(Context.hasSameType(ICE->getSubExpr()->getType(), SubExpr->getType()) && "Implicit cast type cannot be determined from overload"); @@ -6497,7 +6515,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { // Fix the sub expression, which really has to be an // UnresolvedLookupExpr holding an overloaded member function // or template. - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6518,7 +6537,8 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemPtrType, UnOp->getOperatorLoc()); } } - Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), Fn); + Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), + Found, Fn); if (SubExpr == UnOp->getSubExpr()) return UnOp->Retain(); @@ -6580,6 +6600,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { MemExpr->getQualifier(), MemExpr->getQualifierRange(), Fn, + Found, MemExpr->getMemberLoc(), TemplateArgs, Fn->getType()); @@ -6590,8 +6611,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, FunctionDecl *Fn) { } Sema::OwningExprResult Sema::FixOverloadedFunctionReference(OwningExprResult E, + NamedDecl *Found, FunctionDecl *Fn) { - return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Fn)); + return Owned(FixOverloadedFunctionReference((Expr *)E.get(), Found, Fn)); } } // end namespace clang diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 1e37bb00c4..fd30a5360e 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -437,32 +437,35 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, << CondExpr->getSourceRange())) return true; - llvm::SmallVector ViableConversions; - llvm::SmallVector ExplicitConversions; + UnresolvedSet<4> ViableConversions; + UnresolvedSet<4> ExplicitConversions; if (const RecordType *RecordTy = CondType->getAs()) { const UnresolvedSetImpl *Conversions = cast(RecordTy->getDecl()) ->getVisibleConversionFunctions(); for (UnresolvedSetImpl::iterator I = Conversions->begin(), E = Conversions->end(); I != E; ++I) { - if (CXXConversionDecl *Conversion = dyn_cast(*I)) + if (CXXConversionDecl *Conversion + = dyn_cast((*I)->getUnderlyingDecl())) if (Conversion->getConversionType().getNonReferenceType() ->isIntegralType()) { if (Conversion->isExplicit()) - ExplicitConversions.push_back(Conversion); + ExplicitConversions.addDecl(I.getDecl(), I.getAccess()); else - ViableConversions.push_back(Conversion); + ViableConversions.addDecl(I.getDecl(), I.getAccess()); } } switch (ViableConversions.size()) { case 0: if (ExplicitConversions.size() == 1) { + DeclAccessPair Found = ExplicitConversions[0]; + CXXConversionDecl *Conversion = + cast(Found->getUnderlyingDecl()); // The user probably meant to invoke the given explicit // conversion; use it. QualType ConvTy - = ExplicitConversions[0]->getConversionType() - .getNonReferenceType(); + = Conversion->getConversionType().getNonReferenceType(); std::string TypeStr; ConvTy.getAsStringInternal(TypeStr, S.Context.PrintingPolicy); @@ -473,8 +476,7 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, << CodeModificationHint::CreateInsertion( S.PP.getLocForEndOfToken(CondExpr->getLocEnd()), ")"); - S.Diag(ExplicitConversions[0]->getLocation(), - diag::note_switch_conversion) + S.Diag(Conversion->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; // If we aren't in a SFINAE context, build a call to the @@ -482,25 +484,32 @@ static bool CheckCXXSwitchCondition(Sema &S, SourceLocation SwitchLoc, if (S.isSFINAEContext()) return true; - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ExplicitConversions[0]); + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, Conversion); } // We'll complain below about a non-integral condition type. break; - case 1: + case 1: { // Apply this conversion. - CondExpr = S.BuildCXXMemberCallExpr(CondExpr, ViableConversions[0]); + DeclAccessPair Found = ViableConversions[0]; + S.CheckMemberOperatorAccess(CondExpr->getExprLoc(), + CondExpr, 0, Found); + CondExpr = S.BuildCXXMemberCallExpr(CondExpr, Found, + cast(Found->getUnderlyingDecl())); break; + } default: S.Diag(SwitchLoc, diag::err_switch_multiple_conversions) << CondType << CondExpr->getSourceRange(); for (unsigned I = 0, N = ViableConversions.size(); I != N; ++I) { - QualType ConvTy - = ViableConversions[I]->getConversionType().getNonReferenceType(); - S.Diag(ViableConversions[I]->getLocation(), - diag::note_switch_conversion) + CXXConversionDecl *Conv + = cast(ViableConversions[I]->getUnderlyingDecl()); + QualType ConvTy = Conv->getConversionType().getNonReferenceType(); + S.Diag(Conv->getLocation(), diag::note_switch_conversion) << ConvTy->isEnumeralType() << ConvTy; } return true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d1f0815eae..4507e64868 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2617,6 +2617,8 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return false; } + DeclAccessPair FoundResult; // temporary for ResolveOverloadedFunction + // Handle pointer-to-function, reference-to-function, and // pointer-to-member-function all in (roughly) the same way. if (// -- For a non-type template-parameter of type pointer to @@ -2656,11 +2658,12 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ArgType = Context.getPointerType(ArgType); ImpCastExprToType(Arg, ArgType, CastExpr::CK_FunctionToPointerDecay); } else if (FunctionDecl *Fn - = ResolveAddressOfOverloadedFunction(Arg, ParamType, true)) { + = ResolveAddressOfOverloadedFunction(Arg, ParamType, true, + FoundResult)) { if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) return true; - Arg = FixOverloadedFunctionReference(Arg, Fn); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); ArgType = Arg->getType(); if (ArgType->isFunctionType() && ParamType->isPointerType()) { ArgType = Context.getPointerType(Arg->getType()); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 099d30a44f..ce410a7605 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -2004,7 +2004,7 @@ QualType Sema::BuildTypeofExprType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { @@ -2024,7 +2024,7 @@ QualType Sema::BuildDecltypeType(Expr *E) { // function template specialization wherever deduction cannot occur. if (FunctionDecl *Specialization = ResolveSingleFunctionTemplateSpecialization(E)) { - E = FixOverloadedFunctionReference(E, Specialization); + E = FixOverloadedFunctionReference(E, Specialization, Specialization); if (!E) return QualType(); } else { diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index d6f3352266..c7ea17fde6 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -977,6 +977,7 @@ public: SourceRange QualifierRange, SourceLocation MemberLoc, ValueDecl *Member, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *ExplicitTemplateArgs, NamedDecl *FirstQualifierInScope) { if (!Member->getDeclName()) { @@ -984,7 +985,8 @@ public: assert(!Qualifier && "Can't have an unnamed field with a qualifier!"); Expr *BaseExpr = Base.takeAs(); - if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, Member)) + if (getSema().PerformObjectMemberConversion(BaseExpr, Qualifier, + FoundDecl, Member)) return getSema().ExprError(); MemberExpr *ME = @@ -1002,9 +1004,11 @@ public: QualType BaseType = ((Expr*) Base.get())->getType(); + // FIXME: this involves duplicating earlier analysis in a lot of + // cases; we should avoid this when possible. LookupResult R(getSema(), Member->getDeclName(), MemberLoc, Sema::LookupMemberName); - R.addDecl(Member); + R.addDecl(FoundDecl); R.resolveKind(); return getSema().BuildMemberReferenceExpr(move(Base), BaseType, @@ -3868,10 +3872,21 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { if (!Member) return SemaRef.ExprError(); + NamedDecl *FoundDecl = E->getFoundDecl(); + if (FoundDecl == E->getMemberDecl()) { + FoundDecl = Member; + } else { + FoundDecl = cast_or_null( + getDerived().TransformDecl(E->getMemberLoc(), FoundDecl)); + if (!FoundDecl) + return SemaRef.ExprError(); + } + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && Qualifier == E->getQualifier() && Member == E->getMemberDecl() && + FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgumentList()) { // Mark it referenced in the new context regardless. @@ -3908,6 +3923,7 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { E->getQualifierRange(), E->getMemberLoc(), Member, + FoundDecl, (E->hasExplicitTemplateArgumentList() ? &TransArgs : 0), FirstQualifierInScope); diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp index 0ef6e3abfb..3bbdbab8d5 100644 --- a/test/CXX/class.access/p4.cpp +++ b/test/CXX/class.access/p4.cpp @@ -309,3 +309,21 @@ namespace test12 { } }; } + +namespace test13 { + struct A { + int x; + unsigned foo() const; + }; + + struct B : protected A { + using A::foo; + using A::x; + }; + + void test() { + A *d; + d->foo(); + (void) d->x; + } +}