Implement access-check delays for out-of-line member definitions
using the same framework we use for deprecation warnings.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@94659 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 86d8678..4fbc42c 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -281,9 +281,55 @@
llvm::DenseMap<DeclarationName, VarDecl *> TentativeDefinitions;
std::vector<DeclarationName> TentativeDefinitionList;
- /// \brief The collection of delayed deprecation warnings.
- llvm::SmallVector<std::pair<SourceLocation,NamedDecl*>, 8>
- DelayedDeprecationWarnings;
+ struct DelayedDiagnostic {
+ enum DDKind { Deprecation, Access };
+
+ unsigned char Kind; // actually a DDKind
+ bool Triggered;
+
+ SourceLocation Loc;
+
+ union {
+ /// Deprecation.
+ struct { NamedDecl *Decl; } DeprecationData;
+
+ /// Access control.
+ struct {
+ NamedDecl *Decl;
+ AccessSpecifier Access;
+ CXXRecordDecl *NamingClass;
+ } AccessData;
+ };
+
+ static DelayedDiagnostic makeDeprecation(SourceLocation Loc,
+ NamedDecl *D) {
+ DelayedDiagnostic DD;
+ DD.Kind = Deprecation;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.DeprecationData.Decl = D;
+ return DD;
+ }
+
+ static DelayedDiagnostic makeAccess(SourceLocation Loc,
+ NamedDecl *Decl,
+ AccessSpecifier AS,
+ CXXRecordDecl *NamingClass) {
+ DelayedDiagnostic DD;
+ DD.Kind = Access;
+ DD.Triggered = false;
+ DD.Loc = Loc;
+ DD.AccessData.Decl = Decl;
+ DD.AccessData.Access = AS;
+ DD.AccessData.NamingClass = NamingClass;
+ return DD;
+ }
+
+ };
+
+ /// \brief The stack of diagnostics that were delayed due to being
+ /// produced during the parsing of a declaration.
+ llvm::SmallVector<DelayedDiagnostic, 8> DelayedDiagnostics;
/// \brief The depth of the current ParsingDeclaration stack.
/// If nonzero, we are currently parsing a declaration (and
@@ -1482,6 +1528,8 @@
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);
+ void HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, Decl *Ctx);
+
//===--------------------------------------------------------------------===//
// Expression Parsing Callbacks: SemaExpr.cpp.
@@ -2386,6 +2434,11 @@
bool CheckAccess(const LookupResult &R, NamedDecl *D, AccessSpecifier Access);
void CheckAccess(const LookupResult &R);
+ void HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx);
+ bool CheckEffectiveAccess(DeclContext *EffectiveContext,
+ const LookupResult &R, NamedDecl *D,
+ AccessSpecifier Access);
+
bool CheckBaseClassAccess(QualType Derived, QualType Base,
unsigned InaccessibleBaseID,
CXXBasePaths& Paths, SourceLocation AccessLoc,
@@ -4008,7 +4061,6 @@
const PartialDiagnostic &PD,
bool Equality = false);
void CheckImplicitConversion(Expr *E, QualType Target);
-
};
//===--------------------------------------------------------------------===//
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 26bafa5..f3c1039 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -172,8 +172,25 @@
if (Access == AS_public)
return false;
- // Otherwise, derive the current class context.
- DeclContext *DC = CurContext;
+ // If we're currently parsing a top-level declaration, delay
+ // diagnostics. This is the only case where parsing a declaration
+ // can actually change our effective context for the purposes of
+ // access control.
+ if (CurContext->isFileContext() && ParsingDeclDepth) {
+ DelayedDiagnostics.push_back(
+ DelayedDiagnostic::makeAccess(R.getNameLoc(), D, Access,
+ R.getNamingClass()));
+ return false;
+ }
+
+ return CheckEffectiveAccess(CurContext, R, D, Access);
+}
+
+/// Checks access from the given effective context.
+bool Sema::CheckEffectiveAccess(DeclContext *EffectiveContext,
+ const LookupResult &R,
+ NamedDecl *D, AccessSpecifier Access) {
+ DeclContext *DC = EffectiveContext;
while (isa<CXXRecordDecl>(DC) &&
cast<CXXRecordDecl>(DC)->isAnonymousStructOrUnion())
DC = DC->getParent();
@@ -233,6 +250,22 @@
return true;
}
+void Sema::HandleDelayedAccessCheck(DelayedDiagnostic &DD, Decl *Ctx) {
+ NamedDecl *D = DD.AccessData.Decl;
+
+ // Fake up a lookup result.
+ LookupResult R(*this, D->getDeclName(), DD.Loc, LookupOrdinaryName);
+ R.suppressDiagnostics();
+ R.setNamingClass(DD.AccessData.NamingClass);
+
+ // Pretend we did this from the context of the newly-parsed
+ // declaration.
+ DeclContext *EffectiveContext = Ctx->getDeclContext();
+
+ if (CheckEffectiveAccess(EffectiveContext, R, D, DD.AccessData.Access))
+ DD.Triggered = true;
+}
+
bool Sema::CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E,
NamedDecl *D, AccessSpecifier Access) {
if (!getLangOptions().AccessControl || !E->getNamingClass())
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 40169b6..a391a0e 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -2067,7 +2067,47 @@
/// on the warning stack.
Action::ParsingDeclStackState Sema::PushParsingDeclaration() {
ParsingDeclDepth++;
- return (ParsingDeclStackState) DelayedDeprecationWarnings.size();
+ return (ParsingDeclStackState) DelayedDiagnostics.size();
+}
+
+void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
+ assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
+ ParsingDeclDepth--;
+
+ if (DelayedDiagnostics.empty())
+ return;
+
+ unsigned SavedIndex = (unsigned) S;
+ assert(SavedIndex <= DelayedDiagnostics.size() &&
+ "saved index is out of bounds");
+
+ // We only want to actually emit delayed diagnostics when we
+ // successfully parsed a decl.
+ Decl *D = Ctx ? Ctx.getAs<Decl>() : 0;
+ if (D) {
+ // We really do want to start with 0 here. We get one push for a
+ // decl spec and another for each declarator; in a decl group like:
+ // deprecated_typedef foo, *bar, baz();
+ // 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) {
+ if (DelayedDiagnostics[I].Triggered)
+ continue;
+
+ switch (DelayedDiagnostics[I].Kind) {
+ case DelayedDiagnostic::Deprecation:
+ HandleDelayedDeprecationCheck(DelayedDiagnostics[I], D);
+ break;
+
+ case DelayedDiagnostic::Access:
+ HandleDelayedAccessCheck(DelayedDiagnostics[I], D);
+ break;
+ }
+ }
+ }
+
+ DelayedDiagnostics.set_size(SavedIndex);
}
static bool isDeclDeprecated(Decl *D) {
@@ -2078,37 +2118,20 @@
return false;
}
-void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
- assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
- ParsingDeclDepth--;
-
- if (DelayedDeprecationWarnings.empty())
+void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD,
+ Decl *Ctx) {
+ if (isDeclDeprecated(Ctx))
return;
- unsigned SavedIndex = (unsigned) S;
- assert(SavedIndex <= DelayedDeprecationWarnings.size() &&
- "saved index is out of bounds");
-
- if (Ctx && !isDeclDeprecated(Ctx.getAs<Decl>())) {
- for (unsigned I = 0, E = DelayedDeprecationWarnings.size(); I != E; ++I) {
- SourceLocation Loc = DelayedDeprecationWarnings[I].first;
- NamedDecl *&ND = DelayedDeprecationWarnings[I].second;
- if (ND) {
- Diag(Loc, diag::warn_deprecated) << ND->getDeclName();
-
- // Prevent this from triggering multiple times.
- ND = 0;
- }
- }
- }
-
- DelayedDeprecationWarnings.set_size(SavedIndex);
+ DD.Triggered = true;
+ Diag(DD.Loc, diag::warn_deprecated)
+ << DD.DeprecationData.Decl->getDeclName();
}
void Sema::EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc) {
// Delay if we're currently parsing a declaration.
if (ParsingDeclDepth) {
- DelayedDeprecationWarnings.push_back(std::make_pair(Loc, D));
+ DelayedDiagnostics.push_back(DelayedDiagnostic::makeDeprecation(Loc, D));
return;
}