diff options
-rw-r--r-- | include/clang/AST/Expr.h | 47 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 51 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 25 | ||||
-rw-r--r-- | lib/Sema/SemaCXXCast.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 8 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 130 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaInit.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaInit.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 68 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 41 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 20 | ||||
-rw-r--r-- | test/CXX/class.access/p4.cpp | 18 |
16 files changed, 338 insertions, 149 deletions
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<int>. 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<NameQualifier *> (this + 1); + MemberNameQualifier *getMemberQualifier() { + assert(HasQualifierOrFoundDecl); + return reinterpret_cast<MemberNameQualifier *> (this + 1); } /// \brief Retrieve the qualifier that preceded the member name, if any. - const NameQualifier *getMemberQualifier() const { + const MemberNameQualifier *getMemberQualifier() const { return const_cast<MemberExpr *>(this)->getMemberQualifier(); } @@ -1308,7 +1312,7 @@ class MemberExpr : public Expr { if (!HasExplicitTemplateArgumentList) return 0; - if (!HasQualifier) + if (!HasQualifierOrFoundDecl) return reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1); return reinterpret_cast<ExplicitTemplateArgumentList *>( @@ -1321,26 +1325,22 @@ class MemberExpr : public Expr { return const_cast<MemberExpr *>(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<MemberExpr>()); - 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<CXXRecordDecl>(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<CXXMethodDecl>(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<CXXRecordDecl>(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<RecordType>()) { - 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<RecordType>(), 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<UsingShadowDecl>(FoundDecl)); + QualType URecordType = Context.getTypeDeclType( + cast<CXXRecordDecl>(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<VarDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, Var); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - Var, MemberLoc, + Var, FoundDecl, MemberLoc, Var->getType().getNonReferenceType())); } if (FunctionDecl *MemberFn = dyn_cast<FunctionDecl>(MemberDecl)) { MarkDeclarationReferenced(MemberLoc, MemberDecl); return Owned(BuildMemberExpr(Context, BaseExpr, IsArrow, SS, - MemberFn, MemberLoc, + MemberFn, FoundDecl, MemberLoc, MemberFn->getType())); } if (EnumConstantDecl *Enum = dyn_cast<EnumConstantDecl>(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<Expr>(); } 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<PointerType>()) @@ -5059,9 +5064,10 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType, return 0; else if ( |