diff options
author | Anders Carlsson <andersca@mac.com> | 2009-08-28 03:16:11 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-08-28 03:16:11 +0000 |
commit | cf9f921268e67703d9cddcf9f2d6ac057c4c3cc8 (patch) | |
tree | fc54994b08b485f66e8546fdb2815586c7646ee5 | |
parent | dd46adef4e839686bf9f22c2f861d1f29c9095d4 (diff) |
Many improvements to using declarations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80332 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 8 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 87 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp | 20 | ||||
-rw-r--r-- | test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp | 15 |
4 files changed, 110 insertions, 20 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 143f84a9c2..4465c8baa3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -92,13 +92,19 @@ def warn_use_out_of_scope_declaration : Warning< "use of out-of-scope declaration of %0">; def err_inline_non_function : Error< "'inline' can only appear on functions">; + +// C++ using declarations def err_using_requires_qualname : Error< "using declaration requires a qualified name">; def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; def err_using_dependent_unsupported : Error< "dependent using declaration not supported yet">; - +def err_using_decl_nested_name_specifier_is_not_a_base_class : Error< + "using declaration refers into %0, which is not a base class of %1">; +def err_using_decl_refers_to_class_member : Error< + "using declaration refers to class member">; + def err_invalid_thread : Error< "'__thread' is only allowed on variable declarations">; def err_thread_non_global : Error< diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ed01a7f2d0..b8384ee780 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2094,13 +2094,13 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, - SourceLocation UsingLoc, - const CXXScopeSpec &SS, - SourceLocation IdentLoc, - IdentifierInfo *TargetName, - OverloadedOperatorKind Op, - AttributeList *AttrList, - bool IsTypeName) { + SourceLocation UsingLoc, + const CXXScopeSpec &SS, + SourceLocation IdentLoc, + IdentifierInfo *TargetName, + OverloadedOperatorKind Op, + AttributeList *AttrList, + bool IsTypeName) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); assert((TargetName || Op) && "Invalid TargetName."); assert(IdentLoc.isValid() && "Invalid TargetName location."); @@ -2118,25 +2118,74 @@ Sema::DeclPtrTy Sema::ActOnUsingDeclaration(Scope *S, if (isUnknownSpecialization(SS)) { Diag(IdentLoc, diag::err_using_dependent_unsupported); delete AttrList; - return DeclPtrTy::make((UsingDecl*)0); + return DeclPtrTy(); } - // Lookup target name. - LookupResult R = LookupParsedName(S, &SS, Name, LookupOrdinaryName, false); + if (SS.isEmpty()) { + Diag(IdentLoc, diag::err_using_requires_qualname); + return DeclPtrTy(); + } + + NestedNameSpecifier *NNS = + static_cast<NestedNameSpecifier *>(SS.getScopeRep()); - if (NamedDecl *NS = R) { - if (IsTypeName && !isa<TypeDecl>(NS)) { - Diag(IdentLoc, diag::err_using_typename_non_type); + DeclContext *LookupContext = 0; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(CurContext)) { + // C++0x N2914 [namespace.udecl]p3: + // 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. + const Type *Ty = NNS->getAsType(); + if (!Ty || !IsDerivedFrom(Context.getTagDeclType(RD), QualType(Ty, 0))) { + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_a_base_class) + << NNS << RD->getDeclName(); + return DeclPtrTy(); } - UsingAlias = UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(), - NS->getLocation(), UsingLoc, NS, - static_cast<NestedNameSpecifier *>(SS.getScopeRep()), - IsTypeName); - PushOnScopeChains(UsingAlias, S); + + LookupContext = cast<RecordType>(Ty)->getDecl(); } else { - Diag(IdentLoc, diag::err_using_requires_qualname) << SS.getRange(); + // C++0x N2914 [namespace.udecl]p8: + // A using-declaration for a class member shall be a member-declaration. + if (NNS->getKind() == NestedNameSpecifier::TypeSpec) { + Diag(IdentLoc, diag::err_using_decl_refers_to_class_member) + << SS.getRange(); + return DeclPtrTy(); + } + + // C++0x N2914 [namespace.udecl]p9: + // In a using-declaration, a prefix :: refers to the global namespace. + if (NNS->getKind() == NestedNameSpecifier::Global) + LookupContext = Context.getTranslationUnitDecl(); + else + LookupContext = NNS->getAsNamespace(); + } + + + // Lookup target name. + LookupResult R = LookupQualifiedName(LookupContext, + Name, LookupOrdinaryName); + + if (!R) { + Diag(IdentLoc, diag::err_typecheck_no_member) << Name << SS.getRange(); + return DeclPtrTy(); } + NamedDecl *ND = R.getAsDecl(); + + if (IsTypeName && !isa<TypeDecl>(ND)) { + Diag(IdentLoc, diag::err_using_typename_non_type); + return DeclPtrTy(); + } + + UsingAlias = + UsingDecl::Create(Context, CurContext, IdentLoc, SS.getRange(), + ND->getLocation(), UsingLoc, ND, NNS, IsTypeName); + PushOnScopeChains(UsingAlias, S); + // FIXME: We ignore attributes for now. delete AttrList; return DeclPtrTy::make(UsingAlias); diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp new file mode 100644 index 0000000000..d701f885fb --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp @@ -0,0 +1,20 @@ +// RUN: clang-cc -fsyntax-only -verify %s +// C++0x N2914. + +struct B { + void f(char); + void g(char); + enum E { e }; + union { int x; }; +}; + +class C { + int g(); +}; + +class D2 : public B { + using B::f; + using B::e; + using B::x; + using C::g; // expected-error{{using declaration refers into 'C::', which is not a base class of 'D2'}} +}; diff --git a/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp new file mode 100644 index 0000000000..07ef7b0b04 --- /dev/null +++ b/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp @@ -0,0 +1,15 @@ +// RUN: clang-cc -fsyntax-only -verify %s +// C++0x N2914. + +struct X { + int i; + static int a; +}; + +using X::i; // expected-error{{error: using declaration refers to class member}} +using X::s; // expected-error{{error: using declaration refers to class member}} + +void f() { + using X::i; // expected-error{{error: using declaration refers to class member}} + using X::s; // expected-error{{error: using declaration refers to class member}} +} |