]> granicus.if.org Git - clang/commitdiff
Many improvements to using declarations.
authorAnders Carlsson <andersca@mac.com>
Fri, 28 Aug 2009 03:16:11 +0000 (03:16 +0000)
committerAnders Carlsson <andersca@mac.com>
Fri, 28 Aug 2009 03:16:11 +0000 (03:16 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80332 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaDeclCXX.cpp
test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3-cxx0x.cpp [new file with mode: 0644]
test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p8-cxx0x.cpp [new file with mode: 0644]

index 143f84a9c2f8425fbd837d5586f96cf80564b593..4465c8baa30b9198bcdfe09b025e3bb945c28e39 100644 (file)
@@ -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<
index ed01a7f2d0704cd32fa9b95e45f9008fc5968de2..b8384ee780e94ecbcaa4fd86c6bece305502eb95 100644 (file)
@@ -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 (file)
index 0000000..d701f88
--- /dev/null
@@ -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 (file)
index 0000000..07ef7b0
--- /dev/null
@@ -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}}
+}