diff options
author | Anders Carlsson <andersca@mac.com> | 2009-03-26 00:24:17 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-03-26 00:24:17 +0000 |
commit | 50713450f61b85805e1ca97e547a4082b7798bd3 (patch) | |
tree | 20856bc121adb7398bf1fb648fbe397a2be064b8 | |
parent | bbf462314b1dc8e422b7c4dd4cac47e566aedf6d (diff) |
Check that the access specifier of a member redeclaration is the same as the original declaration.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67722 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 29 | ||||
-rw-r--r-- | test/SemaCXX/access.cpp | 15 |
3 files changed, 47 insertions, 3 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fb194fe4c3..5dbc3d0ce8 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -234,6 +234,12 @@ def err_deleted_non_function : Error< def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; +// C++ access checking +def err_class_redeclared_with_different_access : Error< + "%0 redeclared with '%1' access">; +def note_previous_access_declaration : Note< + "previously declared '%1' here">; + // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 88c08b0f75..d974301785 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -3083,6 +3083,21 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } +static const char *getAccessName(AccessSpecifier AS) { + switch (AS) { + default: + case AS_none: + assert("Invalid access specifier!"); + return 0; + case AS_public: + return "public"; + case AS_private: + return "private"; + case AS_protected: + return "protected"; + } +} + /// ActOnTag - This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TK indicates whether this is a @@ -3384,9 +3399,17 @@ CreateNewDecl: // lexical context will be different from the semantic context. New->setLexicalDeclContext(CurContext); - if (PrevDecl) - New->setAccess(PrevDecl->getAccess()); - else + if (PrevDecl) { + // C++ [class.access.spec]p3: When a member is redeclared its access + // specifier must be same as its initial declaration. + if (AS != AS_none && AS != PrevDecl->getAccess()) { + Diag(Loc, diag::err_class_redeclared_with_different_access) + << New << getAccessName(AS); + Diag(PrevDecl->getLocation(), diag::note_previous_access_declaration) + << PrevDecl << getAccessName(PrevDecl->getAccess()); + } else + New->setAccess(PrevDecl->getAccess()); + } else New->setAccess(AS); if (TK == TK_Definition) diff --git a/test/SemaCXX/access.cpp b/test/SemaCXX/access.cpp new file mode 100644 index 0000000000..d95781c1b7 --- /dev/null +++ b/test/SemaCXX/access.cpp @@ -0,0 +1,15 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +class C { + struct S; // expected-note {{previously declared 'private' here}} + +public: + struct S {}; // expected-error {{'S' redeclared with 'public' access}} +}; + +struct S { + class C; // expected-note {{previously declared 'public' here}} + +private: + class C { }; // expected-error {{'C' redeclared with 'private' access}} +};
\ No newline at end of file |