[cfe-commits] r91095 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Action.h lib/Parse/MinimalAction.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDeclCXX.cpp test/CXX/class.access/class.access.dcl/p1.cpp

John McCall rjmccall at apple.com
Thu Dec 10 18:10:03 PST 2009


Author: rjmccall
Date: Thu Dec 10 20:10:03 2009
New Revision: 91095

URL: http://llvm.org/viewvc/llvm-project?rev=91095&view=rev
Log:
Implement access declarations.  Most of the work here is parsing them, which
is difficult because they're so terribly, terribly ambiguous.


We implement access declarations in terms of using declarations, which is
quite reasonable.  However, we should really persist the access/using
distinction in the AST and use the appropriate name in diagnostics.  This
isn't a priority, so I'll just file a PR and hope someone else does it. :)

Added:
    cfe/trunk/test/CXX/class.access/class.access.dcl/p1.cpp
Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/MinimalAction.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 10 20:10:03 2009
@@ -130,6 +130,9 @@
   "declaration conflicts with target of using declaration already in scope">;
 def note_using_decl : Note<"%select{|previous }0using declaration">;
 
+def warn_access_decl_deprecated : Warning<
+  "access declarations are deprecated; use using declarations instead">;
+
 def err_invalid_thread : Error<
   "'__thread' is only allowed on variable declarations">;
 def err_thread_non_global : Error<

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Thu Dec 10 20:10:03 2009
@@ -1264,6 +1264,10 @@
   ///
   /// \param AS the currently-active access specifier.
   ///
+  /// \param HasUsingKeyword true if this was declared with an
+  ///   explicit 'using' keyword (i.e. if this is technically a using
+  ///   declaration, not an access declaration)
+  ///
   /// \param UsingLoc the location of the 'using' keyword.
   ///
   /// \param SS the nested-name-specifier that precedes the name.
@@ -1281,6 +1285,7 @@
   /// \returns a representation of the using declaration.
   virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
                                           AccessSpecifier AS,
+                                          bool HasUsingKeyword,
                                           SourceLocation UsingLoc,
                                           const CXXScopeSpec &SS,
                                           UnqualifiedId &Name,

Modified: cfe/trunk/lib/Parse/MinimalAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/MinimalAction.cpp?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/MinimalAction.cpp (original)
+++ cfe/trunk/lib/Parse/MinimalAction.cpp Thu Dec 10 20:10:03 2009
@@ -45,6 +45,7 @@
 // Defined out-of-line here because of dependency on AttributeList
 Action::DeclPtrTy Action::ActOnUsingDeclaration(Scope *CurScope,
                                                 AccessSpecifier AS,
+                                                bool HasUsingKeyword,
                                                 SourceLocation UsingLoc,
                                                 const CXXScopeSpec &SS,
                                                 UnqualifiedId &Name,

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Dec 10 20:10:03 2009
@@ -357,7 +357,7 @@
                    AttrList ? "attributes list" : "using declaration", 
                    tok::semi);
 
-  return Actions.ActOnUsingDeclaration(CurScope, AS, UsingLoc, SS, Name,
+  return Actions.ActOnUsingDeclaration(CurScope, AS, true, UsingLoc, SS, Name,
                                        AttrList, IsTypeName, TypenameLoc);
 }
 
@@ -1065,6 +1065,46 @@
 ///
 void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
                                        const ParsedTemplateInfo &TemplateInfo) {
+  // Access declarations.
+  if (!TemplateInfo.Kind &&
+      (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) &&
+      TryAnnotateCXXScopeToken() &&
+      Tok.is(tok::annot_cxxscope)) {
+    bool isAccessDecl = false;
+    if (NextToken().is(tok::identifier))
+      isAccessDecl = GetLookAheadToken(2).is(tok::semi);
+    else
+      isAccessDecl = NextToken().is(tok::kw_operator);
+
+    if (isAccessDecl) {
+      // Collect the scope specifier token we annotated earlier.
+      CXXScopeSpec SS;
+      ParseOptionalCXXScopeSpecifier(SS, /*ObjectType*/ 0, false);
+
+      // Try to parse an unqualified-id.
+      UnqualifiedId Name;
+      if (ParseUnqualifiedId(SS, false, true, true, /*ObjectType*/ 0, Name)) {
+        SkipUntil(tok::semi);
+        return;
+      }
+
+      // TODO: recover from mistakenly-qualified operator declarations.
+      if (ExpectAndConsume(tok::semi,
+                           diag::err_expected_semi_after,
+                           "access declaration",
+                           tok::semi))
+        return;
+
+      Actions.ActOnUsingDeclaration(CurScope, AS,
+                                    false, SourceLocation(),
+                                    SS, Name,
+                                    /* AttrList */ 0,
+                                    /* IsTypeName */ false,
+                                    SourceLocation());
+      return;
+    }
+  }
+
   // static_assert-declaration
   if (Tok.is(tok::kw_static_assert)) {
     // FIXME: Check for templates

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Dec 10 20:10:03 2009
@@ -1768,6 +1768,7 @@
 
   virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,
                                           AccessSpecifier AS,
+                                          bool HasUsingKeyword,
                                           SourceLocation UsingLoc,
                                           const CXXScopeSpec &SS,
                                           UnqualifiedId &Name,

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=91095&r1=91094&r2=91095&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Dec 10 20:10:03 2009
@@ -2876,6 +2876,7 @@
 
 Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,
                                             AccessSpecifier AS,
+                                            bool HasUsingKeyword,
                                             SourceLocation UsingLoc,
                                             const CXXScopeSpec &SS,
                                             UnqualifiedId &Name,
@@ -2914,6 +2915,18 @@
   if (!TargetName)
     return DeclPtrTy();
 
+  // Warn about using declarations.
+  // TODO: store that the declaration was written without 'using' and
+  // talk about access decls instead of using decls in the
+  // diagnostics.
+  if (!HasUsingKeyword) {
+    UsingLoc = Name.getSourceRange().getBegin();
+    
+    Diag(UsingLoc, diag::warn_access_decl_deprecated)
+      << CodeModificationHint::CreateInsertion(SS.getRange().getBegin(),
+                                               "using ");
+  }
+
   NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS,
                                         Name.getSourceRange().getBegin(),
                                         TargetName, AttrList,

Added: cfe/trunk/test/CXX/class.access/class.access.dcl/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.access.dcl/p1.cpp?rev=91095&view=auto

==============================================================================
--- cfe/trunk/test/CXX/class.access/class.access.dcl/p1.cpp (added)
+++ cfe/trunk/test/CXX/class.access/class.access.dcl/p1.cpp Thu Dec 10 20:10:03 2009
@@ -0,0 +1,199 @@
+// RUN: clang-cc -fsyntax-only -verify
+
+// This is just the test for [namespace.udecl]p4 with 'using'
+// uniformly stripped out.
+
+// C++03 [namespace.udecl]p4:
+//   A using-declaration used as a member-declaration shall refer to a
+//   member of a base class of the class being defined, shall refer to
+//   a member of an anonymous union that is a member of a base class
+//   of the class being defined, or shall refer to an enumerator for
+//   an enumeration type that is a member of a base class of the class
+//   being defined.
+
+// There is no directly analogous paragraph in C++0x, and the feature
+// works sufficiently differently there that it needs a separate test.
+
+namespace test0 {
+  namespace NonClass {
+    typedef int type;
+    struct hiding {};
+    int hiding;
+    static union { double union_member; };
+    enum tagname { enumerator };
+  }
+
+  class Test0 {
+    NonClass::type; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}}
+    NonClass::hiding; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}}
+    NonClass::union_member; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}}
+    NonClass::enumerator; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}}
+  };
+}
+
+struct Opaque0 {};
+
+namespace test1 {
+  struct A {
+    typedef int type;
+    struct hiding {}; // expected-note {{previous use is here}}
+    Opaque0 hiding;
+    union { double union_member; };
+    enum tagname { enumerator };
+  };
+
+  struct B : A {
+    A::type; // expected-warning {{access declarations are deprecated}}
+    A::hiding; // expected-warning {{access declarations are deprecated}}
+    A::union_member; // expected-warning {{access declarations are deprecated}}
+    A::enumerator; // expected-warning {{access declarations are deprecated}}
+    A::tagname; // expected-warning {{access declarations are deprecated}}
+
+    void test0() {
+      type t = 0;
+    }
+
+    void test1() {
+      typedef struct A::hiding local;
+      struct hiding _ = local();
+    }
+
+    void test2() {
+      union hiding _; // expected-error {{tag type that does not match previous}}
+    }
+
+    void test3() {
+      char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
+    }
+
+    void test4() {
+      enum tagname _ = enumerator;
+    }
+
+    void test5() {
+      Opaque0 _ = hiding;
+    }
+  };
+}
+
+namespace test2 {
+  struct A {
+    typedef int type;
+    struct hiding {}; // expected-note {{previous use is here}}
+    int hiding;
+    union { double union_member; };
+    enum tagname { enumerator };
+  };
+
+  template <class T> struct B : A {
+    A::type; // expected-warning {{access declarations are deprecated}}
+    A::hiding; // expected-warning {{access declarations are deprecated}}
+    A::union_member; // expected-warning {{access declarations are deprecated}}
+    A::enumerator; // expected-warning {{access declarations are deprecated}}
+    A::tagname; // expected-warning {{access declarations are deprecated}}
+
+    void test0() {
+      type t = 0;
+    }
+
+    void test1() {
+      typedef struct A::hiding local;
+      struct hiding _ = local();
+    }
+
+    void test2() {
+      union hiding _; // expected-error {{tag type that does not match previous}}
+    }
+
+    void test3() {
+      char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
+    }
+
+    void test4() {
+      enum tagname _ = enumerator;
+    }
+
+    void test5() {
+      Opaque0 _ = hiding;
+    }
+  };
+}
+
+namespace test3 {
+  struct hiding {};
+
+  template <class T> struct A {
+    typedef int type; // expected-note {{target of using declaration}}
+    struct hiding {};
+    Opaque0 hiding;
+    union { double union_member; };
+    enum tagname { enumerator }; // expected-note {{target of using declaration}}
+  };
+
+  template <class T> struct B : A<T> {
+    A<T>::type; // expected-error {{dependent using declaration resolved to type without 'typename'}} // expected-warning {{access declarations are deprecated}}
+    A<T>::hiding; // expected-warning {{access declarations are deprecated}}
+    A<T>::union_member; // expected-warning {{access declarations are deprecated}}
+    A<T>::enumerator; // expected-warning {{access declarations are deprecated}}
+    A<T>::tagname; // expected-error {{dependent using declaration resolved to type without 'typename'}} // expected-warning {{access declarations are deprecated}}
+
+    // FIXME: re-enable these when the various bugs involving tags are fixed
+#if 0
+    void test1() {
+      typedef struct A<T>::hiding local;
+      struct hiding _ = local();
+    }
+
+    void test2() {
+      typedef struct A<T>::hiding local;
+      union hiding _ = local();
+    }
+#endif
+
+    void test3() {
+      char array[sizeof(union_member) == sizeof(double) ? 1 : -1];
+    }
+
+#if 0
+    void test4() {
+      enum tagname _ = enumerator;
+    }
+#endif
+
+    void test5() {
+      Opaque0 _ = hiding;
+    }
+  };
+
+  template struct B<int>; // expected-note {{in instantiation}}
+}
+
+namespace test4 {
+  struct Base {
+    int foo();
+  };
+
+  struct Unrelated {
+    int foo();
+  };
+
+  struct Subclass : Base {
+  };
+
+  namespace InnerNS {
+    int foo();
+  }
+
+  // We should be able to diagnose these without instantiation.
+  template <class T> struct C : Base {
+    InnerNS::foo; // expected-error {{not a class}} expected-warning {{access declarations are deprecated}}
+    Base::bar; // expected-error {{no member named 'bar'}} expected-warning {{access declarations are deprecated}}
+    Unrelated::foo; // expected-error {{not a base class}} expected-warning {{access declarations are deprecated}}
+    C::foo; // legal in C++03 // expected-warning {{access declarations are deprecated}}
+    Subclass::foo; // legal in C++03 // expected-warning {{access declarations are deprecated}}
+
+    int bar(); //expected-note {{target of using declaration}}
+    C::bar; // expected-error {{refers to its own class}} expected-warning {{access declarations are deprecated}}
+  };
+}
+





More information about the cfe-commits mailing list