diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 5 | ||||
| -rw-r--r-- | clang/lib/Parse/MinimalAction.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 42 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 13 | ||||
| -rw-r--r-- | clang/test/CXX/class.access/class.access.dcl/p1.cpp | 199 | 
7 files changed, 263 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index ef7b0ded166..1e694f2b998 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -130,6 +130,9 @@ def err_using_decl_conflict_reverse : Error<    "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< diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index b5d5764a63c..011d6117825 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -1264,6 +1264,10 @@ public:    ///    /// \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 @@ public:    /// \returns a representation of the using declaration.    virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,                                            AccessSpecifier AS, +                                          bool HasUsingKeyword,                                            SourceLocation UsingLoc,                                            const CXXScopeSpec &SS,                                            UnqualifiedId &Name, diff --git a/clang/lib/Parse/MinimalAction.cpp b/clang/lib/Parse/MinimalAction.cpp index aa0b89b1a3a..8b207fab436 100644 --- a/clang/lib/Parse/MinimalAction.cpp +++ b/clang/lib/Parse/MinimalAction.cpp @@ -45,6 +45,7 @@ Action::DeclPtrTy Action::ActOnUsingDirective(Scope *CurScope,  // 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, diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 34ea9c7d9b0..78336bbfb15 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -357,7 +357,7 @@ Parser::DeclPtrTy Parser::ParseUsingDeclaration(unsigned Context,                     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::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo,  ///  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 diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 88de8da2b38..aed7a9bc848 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1768,6 +1768,7 @@ public:    virtual DeclPtrTy ActOnUsingDeclaration(Scope *CurScope,                                            AccessSpecifier AS, +                                          bool HasUsingKeyword,                                            SourceLocation UsingLoc,                                            const CXXScopeSpec &SS,                                            UnqualifiedId &Name, diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 70ee24c68e8..75021c28509 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2876,6 +2876,7 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) {  Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,                                              AccessSpecifier AS, +                                            bool HasUsingKeyword,                                              SourceLocation UsingLoc,                                              const CXXScopeSpec &SS,                                              UnqualifiedId &Name, @@ -2914,6 +2915,18 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S,    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, diff --git a/clang/test/CXX/class.access/class.access.dcl/p1.cpp b/clang/test/CXX/class.access/class.access.dcl/p1.cpp new file mode 100644 index 00000000000..043a9bfb4e0 --- /dev/null +++ b/clang/test/CXX/class.access/class.access.dcl/p1.cpp @@ -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}} +  }; +} +  | 

