[cfe-commits] r94659 - in /cfe/trunk: lib/Sema/Sema.h lib/Sema/SemaAccess.cpp lib/Sema/SemaDeclAttr.cpp test/CXX/class.access/p6.cpp
John McCall
rjmccall at apple.com
Tue Jan 26 19:50:36 PST 2010
Author: rjmccall
Date: Tue Jan 26 21:50:35 2010
New Revision: 94659
URL: http://llvm.org/viewvc/llvm-project?rev=94659&view=rev
Log:
Implement access-check delays for out-of-line member definitions
using the same framework we use for deprecation warnings.
Added:
cfe/trunk/test/CXX/class.access/p6.cpp
Modified:
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaAccess.cpp
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=94659&r1=94658&r2=94659&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Jan 26 21:50:35 2010
@@ -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);
-
};
//===--------------------------------------------------------------------===//
Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=94659&r1=94658&r2=94659&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Tue Jan 26 21:50:35 2010
@@ -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())
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=94659&r1=94658&r2=94659&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Jan 26 21:50:35 2010
@@ -2067,48 +2067,71 @@
/// on the warning stack.
Action::ParsingDeclStackState Sema::PushParsingDeclaration() {
ParsingDeclDepth++;
- return (ParsingDeclStackState) DelayedDeprecationWarnings.size();
-}
-
-static bool isDeclDeprecated(Decl *D) {
- do {
- if (D->hasAttr<DeprecatedAttr>())
- return true;
- } while ((D = cast_or_null<Decl>(D->getDeclContext())));
- return false;
+ return (ParsingDeclStackState) DelayedDiagnostics.size();
}
void Sema::PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy Ctx) {
assert(ParsingDeclDepth > 0 && "empty ParsingDeclaration stack");
ParsingDeclDepth--;
- if (DelayedDeprecationWarnings.empty())
+ if (DelayedDiagnostics.empty())
return;
unsigned SavedIndex = (unsigned) S;
- assert(SavedIndex <= DelayedDeprecationWarnings.size() &&
+ assert(SavedIndex <= DelayedDiagnostics.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;
+ // 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;
}
}
}
- DelayedDeprecationWarnings.set_size(SavedIndex);
+ DelayedDiagnostics.set_size(SavedIndex);
+}
+
+static bool isDeclDeprecated(Decl *D) {
+ do {
+ if (D->hasAttr<DeprecatedAttr>())
+ return true;
+ } while ((D = cast_or_null<Decl>(D->getDeclContext())));
+ return false;
+}
+
+void Sema::HandleDelayedDeprecationCheck(Sema::DelayedDiagnostic &DD,
+ Decl *Ctx) {
+ if (isDeclDeprecated(Ctx))
+ return;
+
+ 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;
}
Added: cfe/trunk/test/CXX/class.access/p6.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p6.cpp?rev=94659&view=auto
==============================================================================
--- cfe/trunk/test/CXX/class.access/p6.cpp (added)
+++ cfe/trunk/test/CXX/class.access/p6.cpp Tue Jan 26 21:50:35 2010
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -fsyntax-only -faccess-control -verify %s
+
+// C++0x [class.access]p6:
+// All access controls in [class.access] affect the ability to
+// access a class member name from a particular scope. For purposes
+// of access control, the base-specifiers of a class and the
+// definitions of class members that appear outside of the class
+// definition are considered to be within the scope of that
+// class. In particular, access controls apply as usual to member
+// names accessed as part of a function return type, even though it
+// is not possible to determine the access privileges of that use
+// without first parsing the rest of the function
+// declarator. Similarly, access control for implicit calls to the
+// constructors, the conversion functions, or the destructor called
+// to create and destroy a static data member is performed as if
+// these calls appeared in the scope of the member's class.
+
+namespace test0 {
+ class A {
+ typedef int type; // expected-note {{declared private here}}
+ type foo();
+ };
+
+ A::type foo() { } // expected-error {{access to private member}}
+ A::type A::foo() { }
+}
More information about the cfe-commits
mailing list