aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td3
-rw-r--r--include/clang/Parse/Action.h5
-rw-r--r--lib/Parse/MinimalAction.cpp1
-rw-r--r--lib/Parse/ParseDeclCXX.cpp42
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDeclCXX.cpp13
-rw-r--r--test/CXX/class.access/class.access.dcl/p1.cpp199
7 files changed, 263 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index ef7b0ded16..1e694f2b99 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/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/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index b5d5764a63..011d611782 100644
--- a/include/clang/Parse/Action.h
+++ b/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/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index aa0b89b1a3..8b207fab43 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/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/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 34ea9c7d9b..78336bbfb1 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/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/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 88de8da2b3..aed7a9bc84 100644
--- a/lib/Sema/Sema.h
+++ b/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/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 70ee24c68e..75021c2850 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/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/test/CXX/class.access/class.access.dcl/p1.cpp b/test/CXX/class.access/class.access.dcl/p1.cpp
new file mode 100644
index 0000000000..043a9bfb4e
--- /dev/null
+++ b/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}}
+ };
+}
+