[cfe-commits] r153002 - in /cfe/trunk: include/clang/Sema/Sema.h lib/Sema/SemaDecl.cpp lib/Sema/SemaTemplate.cpp test/CXX/class.access/p4.cpp test/CXX/dcl.decl/dcl.meaning/p1.cpp test/SemaCXX/nested-name-spec.cpp

Douglas Gregor dgregor at apple.com
Sat Mar 17 16:06:31 PDT 2012


Author: dgregor
Date: Sat Mar 17 18:06:31 2012
New Revision: 153002

URL: http://llvm.org/viewvc/llvm-project?rev=153002&view=rev
Log:
Diagnose tag and class template declarations with qualified
declarator-ids that occur at class scope. Fixes PR8019.

Added:
    cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/class.access/p4.cpp
    cfe/trunk/test/SemaCXX/nested-name-spec.cpp

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Sat Mar 17 18:06:31 2012
@@ -1091,6 +1091,9 @@
                                         const LookupResult &Previous,
                                         Scope *S);
   bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info);
+  bool diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
+                                    DeclarationName Name,
+                                    SourceLocation Loc);
   void DiagnoseFunctionSpecifiers(Declarator& D);
   void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R);
   void CheckShadow(Scope *S, VarDecl *D);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Mar 17 18:06:31 2012
@@ -3235,7 +3235,44 @@
 
   return false;
 }
+
+/// \brief Diagnose a declaration that has a qualified name within a class,
+/// which is ill-formed but often recoverable.
+///
+/// \returns true if we cannot safely recover from this error, false otherwise.
+bool Sema::diagnoseQualifiedDeclInClass(CXXScopeSpec &SS, DeclContext *DC,
+                                        DeclarationName Name,
+                                        SourceLocation Loc) {
+  // The user provided a superfluous scope specifier inside a class
+  // definition:
+  //
+  // class X {
+  //   void X::f();
+  // };
+  if (CurContext->Equals(DC)) {
+    Diag(Loc, diag::warn_member_extra_qualification)
+      << Name << FixItHint::CreateRemoval(SS.getRange());
+    SS.clear();
+    return false;
+  } 
   
+  Diag(Loc, diag::err_member_qualification)
+    << Name << SS.getRange();
+  SS.clear();
+  
+  // C++ constructors and destructors with incorrect scopes can break
+  // our AST invariants by having the wrong underlying types. If
+  // that's the case, then drop this declaration entirely.
+  if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
+       Name.getNameKind() == DeclarationName::CXXDestructorName) &&
+      !Context.hasSameType(Name.getCXXNameType(),
+                          Context.getTypeDeclType(
+                            cast<CXXRecordDecl>(CurContext))))
+    return true;
+  
+  return false;
+}
+
 Decl *Sema::HandleDeclarator(Scope *S, Declarator &D,
                              MultiTemplateParamsArg TemplateParamLists) {
   // TODO: consider using NameInfo for diagnostic.
@@ -3294,31 +3331,9 @@
         D.setInvalidType();
       } else if (isa<CXXRecordDecl>(CurContext) && 
                  !D.getDeclSpec().isFriendSpecified()) {
-        // The user provided a superfluous scope specifier inside a class
-        // definition:
-        //
-        // class X {
-        //   void X::f();
-        // };
-        if (CurContext->Equals(DC)) {
-          Diag(D.getIdentifierLoc(), diag::warn_member_extra_qualification)
-            << Name << FixItHint::CreateRemoval(D.getCXXScopeSpec().getRange());
-        } else {
-          Diag(D.getIdentifierLoc(), diag::err_member_qualification)
-            << Name << D.getCXXScopeSpec().getRange();
-          
-          // C++ constructors and destructors with incorrect scopes can break
-          // our AST invariants by having the wrong underlying types. If
-          // that's the case, then drop this declaration entirely.
-          if ((Name.getNameKind() == DeclarationName::CXXConstructorName ||
-               Name.getNameKind() == DeclarationName::CXXDestructorName) &&
-              !Context.hasSameType(Name.getCXXNameType(),
-                 Context.getTypeDeclType(cast<CXXRecordDecl>(CurContext))))
-            return 0;
-        }
-
-        // Pretend that this qualifier was not here.
-        D.getCXXScopeSpec().clear();
+        if (diagnoseQualifiedDeclInClass(D.getCXXScopeSpec(), DC,
+                                         Name, D.getIdentifierLoc()))
+          return 0;
       }
     }
 
@@ -8004,6 +8019,9 @@
           << SS.getRange();
         return 0;
       }
+
+      if (isa<CXXRecordDecl>(CurContext))
+        diagnoseQualifiedDeclInClass(SS, DC, Name, NameLoc);
     }
 
     if (RequireCompleteDeclContext(SS, DC))

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Mar 17 18:06:31 2012
@@ -886,7 +886,9 @@
       ContextRAII SavedContext(*this, SemanticContext);
       if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
         Invalid = true;
-    }
+    } else if (CurContext->isRecord() && TUK != TUK_Friend &&
+               TUK != TUK_Reference)
+      diagnoseQualifiedDeclInClass(SS, SemanticContext, Name, NameLoc);
         
     LookupQualifiedName(Previous, SemanticContext);
   } else {
@@ -1065,7 +1067,7 @@
     PrevClassTemplate->setMemberSpecialization();
 
   // Set the access specifier.
-  if (!Invalid && TUK != TUK_Friend)
+  if (!Invalid && TUK != TUK_Friend && NewTemplate->getDeclContext()->isRecord())
     SetMemberAccessSpecifier(NewTemplate, PrevClassTemplate, AS);
 
   // Set the lexical context of these templates

Modified: cfe/trunk/test/CXX/class.access/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/p4.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/p4.cpp (original)
+++ cfe/trunk/test/CXX/class.access/p4.cpp Sat Mar 17 18:06:31 2012
@@ -481,7 +481,7 @@
   };
   template <class T> class A<T>::Inner {};
   class B {
-    template <class T> class A<T>::Inner;
+    template <class T> class A<T>::Inner; // expected-error{{non-friend class member 'Inner' cannot have a qualified name}}
   };
 
   void test() {

Added: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp?rev=153002&view=auto
==============================================================================
--- cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp (added)
+++ cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp Sat Mar 17 18:06:31 2012
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+namespace PR8019 {
+  struct x;
+  template<typename T> struct x2;
+  struct y { 
+    struct PR8019::x { int x; };  // expected-error{{non-friend class member 'x' cannot have a qualified name}}
+  
+    struct inner;
+    struct y::inner { }; // expected-warning{{extra qualification on member 'inner'}}
+
+    template<typename T>
+    struct PR8019::x2 { }; // expected-error{{non-friend class member 'x2' cannot have a qualified name}}
+
+    template<typename T>
+    struct inner_template;
+  
+    template<typename T>
+    struct y::inner_template { }; // expected-warning{{extra qualification on member 'inner_template'}}
+  };
+
+}

Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CXX/dcl.decl/dcl.meaning/p1.cpp
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=153002&r1=153001&r2=153002&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Sat Mar 17 18:06:31 2012
@@ -274,7 +274,8 @@
 protected:
   struct B;
   struct B::C; // expected-error {{requires a template parameter list}} \
-               // expected-error {{no struct named 'C'}}
+               // expected-error {{no struct named 'C'}} \
+    // expected-error{{non-friend class member 'C' cannot have a qualified name}}
 };
 
 template<typename T>





More information about the cfe-commits mailing list