Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3128,7 +3128,8 @@ // needs to be delayed for some constant variables when we build one of the // named expressions. void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse); - void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func); + void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, + bool CheckAccess = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E); void MarkMemberReferenced(MemberExpr *E); @@ -3738,7 +3739,8 @@ /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. - void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); + void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType, + bool CheckDtorAccess = true); /// \brief Helper class that collects exception specifications for /// implicitly-declared special member functions. @@ -3890,7 +3892,8 @@ /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, - CXXDestructorDecl *Destructor); + CXXDestructorDecl *Destructor, + bool CheckAccess = true); /// \brief Build an exception spec for destructors that don't have one. /// @@ -4718,7 +4721,8 @@ /// mark all the non-trivial destructors of its members and bases as /// referenced. void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, - CXXRecordDecl *Record); + CXXRecordDecl *Record, + bool CheckAccess = true); /// \brief The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -6197,8 +6197,12 @@ if (getLangOpts().CPlusPlus && Context.getTargetInfo() .getCXXABI() .areArgsDestroyedLeftToRightInCallee()) { - if (const RecordType *RT = Param->getType()->getAs()) - FinalizeVarWithDestructor(Param, RT); + if (const RecordType *RT = Param->getType()->getAs()) { + // Even though we use the dtor in the callee, the access check should only + // be done in the caller. + bool CheckDtorAccess = false; + FinalizeVarWithDestructor(Param, RT, CheckDtorAccess); + } } } Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -3953,9 +3953,9 @@ DiagnoseUninitializedFields(*this, Constructor); } -void -Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, - CXXRecordDecl *ClassDecl) { +void Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, + CXXRecordDecl *ClassDecl, + bool CheckAccess) { // Ignore dependent contexts. Also ignore unions, since their members never // have destructors implicitly called. if (ClassDecl->isDependentContext() || ClassDecl->isUnion()) @@ -4026,11 +4026,12 @@ assert(Dtor && "No dtor found for BaseClassDecl!"); // FIXME: caret should be on the start of the class name - CheckDestructorAccess(Base->getLocStart(), Dtor, - PDiag(diag::err_access_dtor_base) - << Base->getType() - << Base->getSourceRange(), - Context.getTypeDeclType(ClassDecl)); + if (CheckAccess) + CheckDestructorAccess(Base->getLocStart(), Dtor, + PDiag(diag::err_access_dtor_base) + << Base->getType() + << Base->getSourceRange(), + Context.getTypeDeclType(ClassDecl)); MarkFunctionReferenced(Location, Dtor); DiagnoseUseOfDecl(Dtor, Location); @@ -8697,7 +8698,8 @@ } void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, - CXXDestructorDecl *Destructor) { + CXXDestructorDecl *Destructor, + bool CheckAccess) { assert((Destructor->isDefaulted() && !Destructor->doesThisDeclarationHaveABody() && !Destructor->isDeleted()) && @@ -8712,7 +8714,8 @@ DiagnosticErrorTrap Trap(Diags); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), - Destructor->getParent()); + Destructor->getParent(), + CheckAccess); if (CheckDestructor(Destructor) || Trap.hasErrorOccurred()) { Diag(CurrentLocation, diag::note_member_synthesized_at) @@ -10560,7 +10563,8 @@ ParenRange)); } -void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { +void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record, + bool CheckDtorAccess) { if (VD->isInvalidDecl()) return; CXXRecordDecl *ClassDecl = cast(Record->getDecl()); @@ -10569,11 +10573,12 @@ if (ClassDecl->isDependentContext()) return; CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); - MarkFunctionReferenced(VD->getLocation(), Destructor); - CheckDestructorAccess(VD->getLocation(), Destructor, - PDiag(diag::err_access_dtor_var) - << VD->getDeclName() - << VD->getType()); + MarkFunctionReferenced(VD->getLocation(), Destructor, CheckAccess); + if (CheckDtorAccess) + CheckDestructorAccess(VD->getLocation(), Destructor, + PDiag(diag::err_access_dtor_var) + << VD->getDeclName() + << VD->getType()); DiagnoseUseOfDecl(Destructor, VD->getLocation()); if (!VD->hasGlobalStorage()) return; Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -11147,7 +11147,8 @@ /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) -void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { +void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, + bool CheckAccess) { assert(Func && "No function?"); Func->setReferenced(); @@ -11213,7 +11214,7 @@ dyn_cast(Func)) { Destructor = cast(Destructor->getFirstDecl()); if (Destructor->isDefaulted() && !Destructor->isDeleted()) - DefineImplicitDestructor(Loc, Destructor); + DefineImplicitDestructor(Loc, Destructor, CheckAccess); if (Destructor->isVirtual()) MarkVTableUsed(Loc, Destructor->getParent()); } else if (CXXMethodDecl *MethodDecl = dyn_cast(Func)) { Index: test/SemaCXX/microsoft-dtor-lookup.cpp =================================================================== --- test/SemaCXX/microsoft-dtor-lookup.cpp +++ test/SemaCXX/microsoft-dtor-lookup.cpp @@ -28,18 +28,14 @@ namespace Test2 { -// In the MSVC ABI, functions must destroy their aggregate arguments. foo -// requires a dtor for B, but we can't implicitly define it because ~A is -// private. bar should be able to call A's private dtor without error, even -// though MSVC rejects bar. - +// In the MSVC ABI, functions must destroy their aggregate arguments. class A { private: - ~A(); // expected-note 2{{declared private here}} + ~A(); int a; }; -struct B : public A { // expected-error {{base class 'Test2::A' has private destructor}} +struct B : public A { int b; }; @@ -53,8 +49,8 @@ C o; }; -void foo(B b) { } // expected-note {{implicit destructor for 'Test2::B' first required here}} -void bar(A a) { } // expected-error {{variable of type 'Test2::A' has private destructor}} +void foo(B b) { } // no error; MSVC rejects this, but the standard allows it. +void bar(A a) { } // no error; MSVC rejects this, but the standard allows it. void baz(D d) { } // no error } @@ -64,13 +60,13 @@ class A { A(); - ~A(); // expected-note 2{{implicitly declared private here}} + ~A(); // expected-note {{implicitly declared private here}} friend void bar(A); int a; }; void bar(A a) { } -void baz(A a) { } // expected-error {{variable of type 'Test3::A' has private destructor}} +void baz(A a) { } // no error; MSVC rejects this, but the standard allows it. // MSVC accepts foo() but we reject it for consistency with Itanium. MSVC also // rejects this if A has a copy ctor or if we call A's ctor. Index: test/SemaObjCXX/microsoft-abi-byval.mm =================================================================== --- test/SemaObjCXX/microsoft-abi-byval.mm +++ test/SemaObjCXX/microsoft-abi-byval.mm @@ -1,7 +1,8 @@ // RUN: %clang_cc1 -fsyntax-only -verify -cxx-abi microsoft -Wno-objc-root-class %s +// expected-no-diagnostics class Foo { - ~Foo(); // expected-note {{implicitly declared private here}} + ~Foo(); }; @interface bar @@ -9,6 +10,6 @@ @end @implementation bar -- (void) my_method: (Foo)arg { // expected-error {{variable of type 'Foo' has private destructor}} +- (void) my_method: (Foo)arg { // no error; MS ABI will call Foo's dtor, but we skip the access check. } @end