[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