[cfe-commits] r98609 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Basic/PartialDiagnostic.h lib/Sema/Sema.h lib/Sema/SemaAccess.cpp lib/Sema/SemaCXXCast.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaExceptionSpec.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaOverload.cpp test/CXX/class.access/p4.cpp
John McCall
rjmccall at apple.com
Mon Mar 15 22:22:47 PDT 2010
Author: rjmccall
Date: Tue Mar 16 00:22:47 2010
New Revision: 98609
URL: http://llvm.org/viewvc/llvm-project?rev=98609&view=rev
Log:
Perform access control for the implicit base and member destructor calls
required when emitting a destructor definition.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Basic/PartialDiagnostic.h
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaCXXCast.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
cfe/trunk/lib/Sema/SemaInit.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/test/CXX/class.access/p4.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Mar 16 00:22:47 2010
@@ -428,11 +428,25 @@
// C++ access checking
def err_class_redeclared_with_different_access : Error<
"%0 redeclared with '%1' access">;
-def err_access_private : Error<"%0 is a private member of %1">;
-def err_access_ctor_private : Error<"calling a private constructor of %0">;
-// Say something about the context for these?
-def err_access_protected : Error<"%0 is a protected member of %1">;
-def err_access_ctor_protected : Error<"calling a protected constructor of %0">;
+def err_access :
+ Error<"%1 is a %select{private|protected}0 member of %3">,
+ NoSFINAE;
+def err_access_ctor :
+ Error<"calling a %select{private|protected}0 constructor of class %2">,
+ NoSFINAE;
+def err_access_dtor_base :
+ Error<"base class %0 has %select{private|protected}1 destructor">,
+ NoSFINAE;
+def err_access_dtor_vbase :
+ Error<"inherited virtual base class %0 has "
+ "%select{private|protected}1 destructor">,
+ NoSFINAE;
+def err_access_dtor_field :
+ Error<"field of type %1 has %select{private|protected}2 destructor">,
+ NoSFINAE;
+def err_access_dtor_var :
+ Error<"variable of type %1 has %select{private|protected}2 destructor">,
+ NoSFINAE;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
Modified: cfe/trunk/include/clang/Basic/PartialDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/PartialDiagnostic.h?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/PartialDiagnostic.h (original)
+++ cfe/trunk/include/clang/Basic/PartialDiagnostic.h Tue Mar 16 00:22:47 2010
@@ -69,6 +69,10 @@
CodeModificationHint CodeModificationHints[MaxCodeModificationHints];
};
+ // NOTE: Sema assumes that PartialDiagnostic is location-invariant
+ // in the sense that its bits can be safely memcpy'ed and destructed
+ // in the new location.
+
/// DiagID - The diagnostic ID.
mutable unsigned DiagID;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Mar 16 00:22:47 2010
@@ -300,60 +300,38 @@
/// \brief The set of static functions seen so far that have not been used.
std::vector<FunctionDecl*> UnusedStaticFuncs;
- /// An enum describing the kind of diagnostics to use when checking
- /// access.
- enum AccessDiagnosticsKind {
- /// Suppress diagnostics.
- ADK_quiet,
-
- /// Use the normal diagnostics.
- ADK_normal,
-
- /// Use the diagnostics appropriate for checking a covariant
- /// return type.
- ADK_covariance
- };
-
class AccessedEntity {
public:
- enum Kind {
- /// A member declaration found through lookup. The target is the
- /// member.
- Member,
-
- /// A base-to-derived conversion. The target is the base class.
- BaseToDerivedConversion,
-
- /// A derived-to-base conversion. The target is the base class.
- DerivedToBaseConversion
- };
-
- bool isMemberAccess() const { return K == Member; }
-
- static AccessedEntity makeMember(CXXRecordDecl *NamingClass,
- AccessSpecifier Access,
- NamedDecl *Target) {
- AccessedEntity E;
- E.K = Member;
- E.Access = Access;
- E.Target = Target;
- E.NamingClass = NamingClass;
- return E;
- }
-
- static AccessedEntity makeBaseClass(bool BaseToDerived,
- CXXRecordDecl *BaseClass,
- CXXRecordDecl *DerivedClass,
- AccessSpecifier Access) {
- AccessedEntity E;
- E.K = BaseToDerived ? BaseToDerivedConversion : DerivedToBaseConversion;
- E.Access = Access;
- E.Target = BaseClass;
- E.NamingClass = DerivedClass;
- return E;
+ /// A member declaration found through lookup. The target is the
+ /// member.
+ enum MemberNonce { Member };
+
+ /// A hierarchy (base-to-derived or derived-to-base) conversion.
+ /// The target is the base class.
+ enum BaseNonce { Base };
+
+ bool isMemberAccess() const { return IsMember; }
+
+ AccessedEntity(MemberNonce _,
+ CXXRecordDecl *NamingClass,
+ AccessSpecifier Access,
+ NamedDecl *Target)
+ : Access(Access), IsMember(true),
+ Target(Target), NamingClass(NamingClass),
+ Diag(0) {
+ }
+
+ AccessedEntity(BaseNonce _,
+ CXXRecordDecl *BaseClass,
+ CXXRecordDecl *DerivedClass,
+ AccessSpecifier Access)
+ : Access(Access), IsMember(false),
+ Target(BaseClass), NamingClass(DerivedClass),
+ Diag(0) {
}
- Kind getKind() const { return Kind(K); }
+ bool isQuiet() const { return Diag.getDiagID() == 0; }
+
AccessSpecifier getAccess() const { return AccessSpecifier(Access); }
// These apply to member decls...
@@ -364,11 +342,32 @@
CXXRecordDecl *getBaseClass() const { return cast<CXXRecordDecl>(Target); }
CXXRecordDecl *getDerivedClass() const { return NamingClass; }
+ /// Sets a diagnostic to be performed. The diagnostic is given
+ /// four (additional) arguments:
+ /// %0 - 0 if the entity was private, 1 if protected
+ /// %1 - the DeclarationName of the entity
+ /// %2 - the TypeDecl type of the naming class
+ /// %3 - the TypeDecl type of the declaring class
+ void setDiag(const PartialDiagnostic &PDiag) {
+ assert(isQuiet() && "partial diagnostic already defined");
+ Diag = PDiag;
+ }
+ PartialDiagnostic &setDiag(unsigned DiagID) {
+ assert(isQuiet() && "partial diagnostic already defined");
+ assert(DiagID && "creating null diagnostic");
+ Diag = PartialDiagnostic(DiagID);
+ return Diag;
+ }
+ const PartialDiagnostic &getDiag() const {
+ return Diag;
+ }
+
private:
- unsigned K : 2;
unsigned Access : 2;
+ bool IsMember;
NamedDecl *Target;
CXXRecordDecl *NamingClass;
+ PartialDiagnostic Diag;
};
struct DelayedDiagnostic {
@@ -384,9 +383,16 @@
struct { NamedDecl *Decl; } DeprecationData;
/// Access control.
- AccessedEntity AccessData;
+ char AccessData[sizeof(AccessedEntity)];
};
+ void destroy() {
+ switch (Kind) {
+ case Access: getAccessData().~AccessedEntity(); break;
+ case Deprecation: break;
+ }
+ }
+
static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
NamedDecl *D) {
DelayedDiagnostic DD;
@@ -403,10 +409,16 @@
DD.Kind = Access;
DD.Triggered = false;
DD.Loc = Loc;
- DD.AccessData = Entity;
+ new (&DD.getAccessData()) AccessedEntity(Entity);
return DD;
}
+ AccessedEntity &getAccessData() {
+ return *reinterpret_cast<AccessedEntity*>(AccessData);
+ }
+ const AccessedEntity &getAccessData() const {
+ return *reinterpret_cast<const AccessedEntity*>(AccessData);
+ }
};
/// \brief The stack of diagnostics that were delayed due to being
@@ -2566,7 +2578,7 @@
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess = false);
bool CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- AccessDiagnosticsKind ADK,
+ unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name);
@@ -2614,18 +2626,19 @@
CXXConstructorDecl *D,
AccessSpecifier Access);
AccessResult CheckDestructorAccess(SourceLocation Loc,
- const RecordType *Record);
+ CXXDestructorDecl *Dtor,
+ const PartialDiagnostic &PDiag);
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
+ Expr *ArgExpr,
NamedDecl *D,
AccessSpecifier Access);
AccessResult CheckBaseClassAccess(SourceLocation AccessLoc,
- bool IsBaseToDerived,
QualType Base, QualType Derived,
const CXXBasePath &Path,
+ unsigned DiagID,
bool ForceCheck = false,
- bool ForceUnprivileged = false,
- AccessDiagnosticsKind ADK = ADK_normal);
+ bool ForceUnprivileged = false);
void CheckLookupAccess(const LookupResult &R);
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Tue Mar 16 00:22:47 2010
@@ -255,18 +255,11 @@
NamedDecl *D = Entity.getTargetDecl();
CXXRecordDecl *DeclaringClass = FindDeclaringClass(D);
- if (isa<CXXConstructorDecl>(D)) {
- unsigned DiagID = (Access == AS_protected ? diag::err_access_ctor_protected
- : diag::err_access_ctor_private);
- S.Diag(Loc, DiagID)
- << S.Context.getTypeDeclType(DeclaringClass);
- } else {
- unsigned DiagID = (Access == AS_protected ? diag::err_access_protected
- : diag::err_access_private);
- S.Diag(Loc, DiagID)
- << D->getDeclName()
- << S.Context.getTypeDeclType(DeclaringClass);
- }
+ S.Diag(Loc, Entity.getDiag())
+ << (Access == AS_protected)
+ << D->getDeclName()
+ << S.Context.getTypeDeclType(NamingClass)
+ << S.Context.getTypeDeclType(DeclaringClass);
DiagnoseAccessPath(S, EC, NamingClass, DeclaringClass, D, Access);
}
@@ -274,39 +267,25 @@
static void DiagnoseInaccessibleBase(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
AccessSpecifier Access,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK) {
- if (ADK == Sema::ADK_covariance) {
- S.Diag(Loc, diag::err_covariant_return_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- } else if (Entity.getKind() == Sema::AccessedEntity::BaseToDerivedConversion) {
- S.Diag(Loc, diag::err_downcast_from_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- } else {
- S.Diag(Loc, diag::err_upcast_to_inaccessible_base)
- << S.Context.getTypeDeclType(Entity.getDerivedClass())
- << S.Context.getTypeDeclType(Entity.getBaseClass())
- << (Access == AS_protected);
- }
+ const Sema::AccessedEntity &Entity) {
+ S.Diag(Loc, Entity.getDiag())
+ << (Access == AS_protected)
+ << DeclarationName()
+ << S.Context.getTypeDeclType(Entity.getDerivedClass())
+ << S.Context.getTypeDeclType(Entity.getBaseClass());
DiagnoseAccessPath(S, EC, Entity.getDerivedClass(),
Entity.getBaseClass(), 0, Access);
}
-static void DiagnoseBadAccess(Sema &S,
- SourceLocation Loc,
+static void DiagnoseBadAccess(Sema &S, SourceLocation Loc,
const EffectiveContext &EC,
CXXRecordDecl *NamingClass,
AccessSpecifier Access,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK) {
+ const Sema::AccessedEntity &Entity) {
if (Entity.isMemberAccess())
DiagnoseInaccessibleMember(S, Loc, EC, NamingClass, Access, Entity);
else
- DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity, ADK);
+ DiagnoseInaccessibleBase(S, Loc, EC, Access, Entity);
}
@@ -369,8 +348,7 @@
static Sema::AccessResult CheckEffectiveAccess(Sema &S,
const EffectiveContext &EC,
SourceLocation Loc,
- Sema::AccessedEntity const &Entity,
- Sema::AccessDiagnosticsKind ADK) {
+ Sema::AccessedEntity const &Entity) {
AccessSpecifier Access = Entity.getAccess();
assert(Access != AS_public);
@@ -378,14 +356,14 @@
while (NamingClass->isAnonymousStructOrUnion())
// This should be guaranteed by the fact that the decl has
// non-public access. If not, we should make it guaranteed!
- NamingClass = cast<CXXRecordDecl>(NamingClass);
+ NamingClass = cast<CXXRecordDecl>(NamingClass->getParent());
if (!EC.Record) {
TryElevateAccess(S, EC, Entity, Access);
if (Access == AS_public) return Sema::AR_accessible;
- if (ADK != Sema::ADK_quiet)
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
return Sema::AR_inaccessible;
}
@@ -418,15 +396,13 @@
}
// Okay, that's it, reject it.
- if (ADK != Sema::ADK_quiet)
- DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity, ADK);
+ if (!Entity.isQuiet())
+ DiagnoseBadAccess(S, Loc, EC, NamingClass, Access, Entity);
return Sema::AR_inaccessible;
}
static Sema::AccessResult CheckAccess(Sema &S, SourceLocation Loc,
- const Sema::AccessedEntity &Entity,
- Sema::AccessDiagnosticsKind ADK
- = Sema::ADK_normal) {
+ const Sema::AccessedEntity &Entity) {
// If the access path is public, it's accessible everywhere.
if (Entity.getAccess() == AS_public)
return Sema::AR_accessible;
@@ -436,14 +412,13 @@
// can actually change our effective context for the purposes of
// access control.
if (S.CurContext->isFileContext() && S.ParsingDeclDepth) {
- assert(ADK == Sema::ADK_normal && "delaying abnormal access check");
S.DelayedDiagnostics.push_back(
Sema::DelayedDiagnostic::makeAccess(Loc, Entity));
return Sema::AR_delayed;
}
return CheckEffectiveAccess(S, EffectiveContext(S.CurContext),
- Loc, Entity, ADK);
+ Loc, Entity);
}
void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
@@ -451,18 +426,23 @@
// declaration.
EffectiveContext EC(Ctx->getDeclContext());
- if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.AccessData, ADK_normal))
+ if (CheckEffectiveAccess(*this, EC, DD.Loc, DD.getAccessData()))
DD.Triggered = true;
}
Sema::AccessResult Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
NamedDecl *D,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl || !E->getNamingClass())
+ if (!getLangOptions().AccessControl ||
+ !E->getNamingClass() ||
+ Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, E->getNameLoc(),
- AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+ AccessedEntity Entity(AccessedEntity::Member,
+ E->getNamingClass(), Access, D);
+ Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+ return CheckAccess(*this, E->getNameLoc(), Entity);
}
/// Perform access-control checking on a previously-unresolved member
@@ -470,56 +450,73 @@
Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
NamedDecl *D,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, E->getMemberLoc(),
- AccessedEntity::makeMember(E->getNamingClass(), Access, D));
+ AccessedEntity Entity(AccessedEntity::Member,
+ E->getNamingClass(), Access, D);
+ Entity.setDiag(diag::err_access) << E->getSourceRange();
+
+ return CheckAccess(*this, E->getMemberLoc(), Entity);
}
Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
- const RecordType *RT) {
+ CXXDestructorDecl *Dtor,
+ const PartialDiagnostic &PDiag) {
if (!getLangOptions().AccessControl)
return AR_accessible;
- CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- CXXDestructorDecl *Dtor = NamingClass->getDestructor(Context);
-
+ // There's never a path involved when checking implicit destructor access.
AccessSpecifier Access = Dtor->getAccess();
if (Access == AS_public)
return AR_accessible;
- return CheckAccess(*this, Loc,
- AccessedEntity::makeMember(NamingClass, Access, Dtor));
+ CXXRecordDecl *NamingClass = Dtor->getParent();
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Dtor);
+ Entity.setDiag(PDiag); // TODO: avoid copy
+
+ return CheckAccess(*this, Loc, Entity);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
- return CheckAccess(*this, UseLoc,
- AccessedEntity::makeMember(NamingClass, Access, Constructor));
+ AccessedEntity Entity(AccessedEntity::Member,
+ NamingClass, Access, Constructor);
+ Entity.setDiag(diag::err_access_ctor);
+
+ return CheckAccess(*this, UseLoc, Entity);
}
/// Checks access to an overloaded member operator, including
/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
Expr *ObjectExpr,
+ Expr *ArgExpr,
NamedDecl *MemberOperator,
AccessSpecifier Access) {
- if (!getLangOptions().AccessControl)
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
return AR_accessible;
const RecordType *RT = ObjectExpr->getType()->getAs<RecordType>();
assert(RT && "found member operator but object expr not of record type");
CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(RT->getDecl());
- return CheckAccess(*this, OpLoc,
- AccessedEntity::makeMember(NamingClass, Access, MemberOperator));
+ AccessedEntity Entity(AccessedEntity::Member,
+ NamingClass, Access, MemberOperator);
+ Entity.setDiag(diag::err_access)
+ << ObjectExpr->getSourceRange()
+ << (ArgExpr ? ArgExpr->getSourceRange() : SourceRange());
+
+ return CheckAccess(*this, OpLoc, Entity);
}
/// Checks access for a hierarchy conversion.
@@ -532,31 +529,29 @@
/// context had no special privileges
/// \param ADK controls the kind of diagnostics that are used
Sema::AccessResult Sema::CheckBaseClassAccess(SourceLocation AccessLoc,
- bool IsBaseToDerived,
QualType Base,
QualType Derived,
const CXXBasePath &Path,
+ unsigned DiagID,
bool ForceCheck,
- bool ForceUnprivileged,
- AccessDiagnosticsKind ADK) {
+ bool ForceUnprivileged) {
if (!ForceCheck && !getLangOptions().AccessControl)
return AR_accessible;
if (Path.Access == AS_public)
return AR_accessible;
- // TODO: preserve the information about which types exactly were used.
CXXRecordDecl *BaseD, *DerivedD;
BaseD = cast<CXXRecordDecl>(Base->getAs<RecordType>()->getDecl());
DerivedD = cast<CXXRecordDecl>(Derived->getAs<RecordType>()->getDecl());
- AccessedEntity Entity = AccessedEntity::makeBaseClass(IsBaseToDerived,
- BaseD, DerivedD,
- Path.Access);
+
+ AccessedEntity Entity(AccessedEntity::Base, BaseD, DerivedD, Path.Access);
+ if (DiagID)
+ Entity.setDiag(DiagID) << Derived << Base;
if (ForceUnprivileged)
- return CheckEffectiveAccess(*this, EffectiveContext(),
- AccessLoc, Entity, ADK);
- return CheckAccess(*this, AccessLoc, Entity, ADK);
+ return CheckEffectiveAccess(*this, EffectiveContext(), AccessLoc, Entity);
+ return CheckAccess(*this, AccessLoc, Entity);
}
/// Checks access to all the declarations in the given result set.
@@ -565,9 +560,13 @@
&& "performing access check without access control");
assert(R.getNamingClass() && "performing access check without naming class");
- for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- if (I.getAccess() != AS_public)
- CheckAccess(*this, R.getNameLoc(),
- AccessedEntity::makeMember(R.getNamingClass(),
- I.getAccess(), *I));
+ for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
+ if (I.getAccess() != AS_public) {
+ AccessedEntity Entity(AccessedEntity::Member,
+ R.getNamingClass(), I.getAccess(), *I);
+ Entity.setDiag(diag::err_access);
+
+ CheckAccess(*this, R.getNameLoc(), Entity);
+ }
+ }
}
Modified: cfe/trunk/lib/Sema/SemaCXXCast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXCast.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXCast.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXCast.cpp Tue Mar 16 00:22:47 2010
@@ -780,9 +780,9 @@
}
if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
- /*IsBaseToDerived*/ true,
SrcType, DestType,
- Paths.front())) {
+ Paths.front(),
+ diag::err_downcast_from_inaccessible_base)) {
msg = 0;
return TC_Failed;
}
@@ -858,9 +858,9 @@
}
if (!CStyle && Self.CheckBaseClassAccess(OpRange.getBegin(),
- /*IsBaseToDerived*/ false,
DestType, SrcType,
- Paths.front())) {
+ Paths.front(),
+ diag::err_upcast_to_inaccessible_base)) {
msg = 0;
return TC_Failed;
}
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Mar 16 00:22:47 2010
@@ -2038,6 +2038,8 @@
assert(SavedIndex <= DelayedDiagnostics.size() &&
"saved index is out of bounds");
+ unsigned E = DelayedDiagnostics.size();
+
// We only want to actually emit delayed diagnostics when we
// successfully parsed a decl.
Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
@@ -2048,7 +2050,7 @@
// only the declarator pops will be passed decls. This is correct;
// we really do need to consider delayed diagnostics from the decl spec
// for each of the different declarations.
- for (unsigned I = 0, E = DelayedDiagnostics.size(); I != E; ++I) {
+ for (unsigned I = 0; I != E; ++I) {
if (DelayedDiagnostics[I].Triggered)
continue;
@@ -2064,6 +2066,10 @@
}
}
+ // Destroy all the delayed diagnostics we're about to pop off.
+ for (unsigned I = SavedIndex; I != E; ++I)
+ DelayedDiagnostics[I].destroy();
+
DelayedDiagnostics.set_size(SavedIndex);
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Mar 16 00:22:47 2010
@@ -720,7 +720,7 @@
/// if there is an error.
bool
Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base,
- AccessDiagnosticsKind ADK,
+ unsigned InaccessibleBaseID,
unsigned AmbigiousBaseConvID,
SourceLocation Loc, SourceRange Range,
DeclarationName Name) {
@@ -736,15 +736,12 @@
(void)DerivationOkay;
if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) {
- if (ADK == ADK_quiet)
+ if (!InaccessibleBaseID)
return false;
// Check that the base class can be accessed.
- switch (CheckBaseClassAccess(Loc, /*IsBaseToDerived*/ false,
- Base, Derived, Paths.front(),
- /*force*/ false,
- /*unprivileged*/ false,
- ADK)) {
+ switch (CheckBaseClassAccess(Loc, Base, Derived, Paths.front(),
+ InaccessibleBaseID)) {
case AR_accessible: return false;
case AR_inaccessible: return true;
case AR_dependent: return false;
@@ -780,7 +777,8 @@
SourceLocation Loc, SourceRange Range,
bool IgnoreAccess) {
return CheckDerivedToBaseConversion(Derived, Base,
- IgnoreAccess ? ADK_quiet : ADK_normal,
+ IgnoreAccess ? 0
+ : diag::err_upcast_to_inaccessible_base,
diag::err_ambiguous_derived_to_base_conv,
Loc, Range, DeclarationName());
}
@@ -1854,6 +1852,11 @@
// Ignore dependent destructors.
if (Destructor->isDependentContext())
return;
+
+ // FIXME: all the access-control diagnostics are positioned on the
+ // field/base declaration. That's probably good; that said, the
+ // user might reasonably want to know why the destructor is being
+ // emitted, and we currently don't say.
CXXRecordDecl *ClassDecl = Destructor->getParent();
@@ -1872,25 +1875,41 @@
if (FieldClassDecl->hasTrivialDestructor())
continue;
- const CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ CXXDestructorDecl *Dtor = FieldClassDecl->getDestructor(Context);
+ CheckDestructorAccess(Field->getLocation(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_field)
+ << Field->getDeclName()
+ << FieldType);
+
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
+ llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
+
// Bases.
for (CXXRecordDecl::base_class_iterator Base = ClassDecl->bases_begin(),
E = ClassDecl->bases_end(); Base != E; ++Base) {
- // Ignore virtual bases.
+ // Bases are always records in a well-formed non-dependent class.
+ const RecordType *RT = Base->getType()->getAs<RecordType>();
+
+ // Remember direct virtual bases.
if (Base->isVirtual())
- continue;
+ DirectVirtualBases.insert(RT);
// Ignore trivial destructors.
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
+
+ CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+ // FIXME: caret should be on the start of the class name
+ CheckDestructorAccess(Base->getSourceRange().getBegin(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_base)
+ << Base->getType()
+ << Base->getSourceRange());
- const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
@@ -1898,13 +1917,24 @@
// Virtual bases.
for (CXXRecordDecl::base_class_iterator VBase = ClassDecl->vbases_begin(),
E = ClassDecl->vbases_end(); VBase != E; ++VBase) {
+
+ // Bases are always records in a well-formed non-dependent class.
+ const RecordType *RT = VBase->getType()->getAs<RecordType>();
+
+ // Ignore direct virtual bases.
+ if (DirectVirtualBases.count(RT))
+ continue;
+
// Ignore trivial destructors.
- CXXRecordDecl *BaseClassDecl
- = cast<CXXRecordDecl>(VBase->getType()->getAs<RecordType>()->getDecl());
+ CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (BaseClassDecl->hasTrivialDestructor())
continue;
-
- const CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+
+ CXXDestructorDecl *Dtor = BaseClassDecl->getDestructor(Context);
+ CheckDestructorAccess(ClassDecl->getLocation(), Dtor,
+ PartialDiagnostic(diag::err_access_dtor_vbase)
+ << VBase->getType());
+
MarkDeclarationReferenced(Destructor->getLocation(),
const_cast<CXXDestructorDecl*>(Dtor));
}
@@ -4062,7 +4092,10 @@
!ClassDecl->hasTrivialDestructor()) {
CXXDestructorDecl *Destructor = ClassDecl->getDestructor(Context);
MarkDeclarationReferenced(VD->getLocation(), Destructor);
- CheckDestructorAccess(VD->getLocation(), Record);
+ CheckDestructorAccess(VD->getLocation(), Destructor,
+ PartialDiagnostic(diag::err_access_dtor_var)
+ << VD->getDeclName()
+ << VD->getType());
}
}
@@ -5725,7 +5758,8 @@
}
// Check if we the conversion from derived to base is valid.
- if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy, ADK_covariance,
+ if (CheckDerivedToBaseConversion(NewClassTy, OldClassTy,
+ diag::err_covariant_return_inaccessible_base,
diag::err_covariant_return_ambiguous_derived_to_base_conv,
// FIXME: Should this point to the return type?
New->getLocation(), SourceRange(), New->getDeclName())) {
Modified: cfe/trunk/lib/Sema/SemaExceptionSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExceptionSpec.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExceptionSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExceptionSpec.cpp Tue Mar 16 00:22:47 2010
@@ -294,12 +294,12 @@
continue;
// Do this check from a context without privileges.
- switch (CheckBaseClassAccess(SourceLocation(), false,
+ switch (CheckBaseClassAccess(SourceLocation(),
CanonicalSuperT, CanonicalSubT,
Paths.front(),
+ /*Diagnostic*/ 0,
/*ForceCheck*/ true,
- /*ForceUnprivileged*/ true,
- ADK_quiet)) {
+ /*ForceUnprivileged*/ true)) {
case AR_accessible: break;
case AR_inaccessible: continue;
case AR_dependent:
Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Tue Mar 16 00:22:47 2010
@@ -3401,7 +3401,7 @@
// Build a call to the conversion function.
CXXConversionDecl *Conversion = cast<CXXConversionDecl>(Fn);
- S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr,
+ S.CheckMemberOperatorAccess(Kind.getLocation(), CurInitExpr, 0,
Conversion, FnAccess);
// FIXME: Should we move this initialization into a separate
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Tue Mar 16 00:22:47 2010
@@ -1411,8 +1411,9 @@
}
if (!IgnoreBaseAccess)
- CheckBaseClassAccess(From->getExprLoc(), /*BaseToDerived*/ true,
- FromClass, ToClass, Paths.front());
+ CheckBaseClassAccess(From->getExprLoc(), FromClass, ToClass,
+ Paths.front(),
+ diag::err_downcast_from_inaccessible_base);
// Must be a base to derived member conversion.
Kind = CastExpr::CK_BaseToDerivedMemberPointer;
@@ -5548,7 +5549,7 @@
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
- CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], 0, Method, Best->getAccess());
if (PerformObjectArgumentInitialization(Input, /*Qualifier=*/0, Method))
return ExprError();
@@ -5732,7 +5733,8 @@
// Convert the arguments.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FnDecl)) {
// Best->Access is only meaningful for class members.
- CheckMemberOperatorAccess(OpLoc, Args[0], Method, Best->getAccess());
+ CheckMemberOperatorAccess(OpLoc, Args[0], Args[1], Method,
+ Best->getAccess());
OwningExprResult Arg1
= PerformCopyInitialization(
@@ -5906,7 +5908,8 @@
// We matched an overloaded operator. Build a call to that
// operator.
- CheckMemberOperatorAccess(LLoc, Args[0], FnDecl, Best->getAccess());
+ CheckMemberOperatorAccess(LLoc, Args[0], Args[1], FnDecl,
+ Best->getAccess());
// Convert the arguments.
CXXMethodDecl *Method = cast<CXXMethodDecl>(FnDecl);
@@ -6275,7 +6278,7 @@
= cast<CXXConversionDecl>(
Best->Conversions[0].UserDefined.ConversionFunction);
- CheckMemberOperatorAccess(LParenLoc, Object, Conv, Best->getAccess());
+ CheckMemberOperatorAccess(LParenLoc, Object, 0, Conv, Best->getAccess());
// We selected one of the surrogate functions that converts the
// object parameter to a function pointer. Perform the conversion
@@ -6290,7 +6293,7 @@
CommaLocs, RParenLoc).release();
}
- CheckMemberOperatorAccess(LParenLoc, Object,
+ CheckMemberOperatorAccess(LParenLoc, Object, 0,
Best->Function, Best->getAccess());
// We found an overloaded operator(). Build a CXXOperatorCallExpr
Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=98609&r1=98608&r2=98609&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Tue Mar 16 00:22:47 2010
@@ -99,18 +99,36 @@
// Implicit destructor calls.
namespace test3 {
- class A{
+ class A {
private:
~A(); // expected-note 3 {{declared private here}}
static A foo;
};
- A a; // expected-error {{'~A' is a private member}}
+ A a; // expected-error {{variable of type 'test3::A' has private destructor}}
A A::foo;
- void foo(A param) { // expected-error {{'~A' is a private member}}
- A local; // expected-error {{'~A' is a private member}}
+ void foo(A param) { // expected-error {{variable of type 'test3::A' has private destructor}}
+ A local; // expected-error {{variable of type 'test3::A' has private destructor}}
}
+
+ template <unsigned N> class Base { ~Base(); }; // expected-note 4 {{declared private here}}
+ class Base2 : virtual Base<2> { ~Base2(); }; // expected-note {{declared private here}}
+ class Base3 : virtual Base<3> { public: ~Base3(); };
+
+ // These don't cause diagnostics because we don't need the destructor.
+ class Derived0 : Base<0> { ~Derived0(); };
+ class Derived1 : Base<1> { };
+
+ class Derived2 : // expected-error {{inherited virtual base class 'Base<2>' has private destructor}} \
+ // expected-error {{inherited virtual base class 'Base<3>' has private destructor}}
+ Base<0>, // expected-error {{base class 'Base<0>' has private destructor}}
+ virtual Base<1>, // expected-error {{base class 'Base<1>' has private destructor}}
+ Base2, // expected-error {{base class 'test3::Base2' has private destructor}}
+ virtual Base3
+ {
+ ~Derived2() {}
+ };
}
// Conversion functions.
More information about the cfe-commits
mailing list