[cfe-commits] r147824 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplate.cpp test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp test/FixIt/fixit-cxx0x.cpp test/SemaCXX/enum-scoped.cpp

Richard Smith richard-llvm at metafoo.co.uk
Mon Jan 9 17:33:14 PST 2012


Author: rsmith
Date: Mon Jan  9 19:33:14 2012
New Revision: 147824

URL: http://llvm.org/viewvc/llvm-project?rev=147824&view=rev
Log:
Update C++11 scoped enumeration support to match the final proposal:
 - reject definitions of enums within friend declarations
 - require 'enum', not 'enum class', for non-declaring references to scoped
   enumerations

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
    cfe/trunk/test/FixIt/fixit-cxx0x.cpp
    cfe/trunk/test/SemaCXX/enum-scoped.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Jan  9 19:33:14 2012
@@ -535,7 +535,7 @@
   "missing ',' between base or member initializers">;
 
 // C++ declarations
-def err_friend_decl_defines_class : Error<
+def err_friend_decl_defines_type : Error<
   "cannot define a type in a friend declaration">;
 def err_missing_whitespace_digraph : Error<
   "found '<::' after a "

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan  9 19:33:14 2012
@@ -1228,6 +1228,9 @@
   "enumeration previously declared with %select{non|}0fixed underlying type">;
 def err_enum_redeclare_scoped_mismatch : Error<
   "enumeration previously declared as %select{un|}0scoped">;
+def err_enum_class_reference : Error<
+  "reference to %select{|scoped }0enumeration must use 'enum' "
+  "not 'enum class'">;
 def err_only_enums_have_underlying_types : Error<
   "only enumeration types have underlying types">;
 def err_incomplete_type_no_underlying_type : Error<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jan  9 19:33:14 2012
@@ -1171,7 +1171,8 @@
                  AttributeList *Attr, AccessSpecifier AS,
                  SourceLocation ModulePrivateLoc,
                  MultiTemplateParamsArg TemplateParameterLists,
-                 bool &OwnedDecl, bool &IsDependent, bool ScopedEnum,
+                 bool &OwnedDecl, bool &IsDependent,
+                 SourceLocation ScopedEnumKWLoc,
                  bool ScopedEnumUsesClassTag, TypeResult UnderlyingType);
 
   Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc,

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jan  9 19:33:14 2012
@@ -2865,15 +2865,14 @@
     return cutOffParsing();
   }
 
-  bool IsScopedEnum = false;
+  SourceLocation ScopedEnumKWLoc;
   bool IsScopedUsingClassTag = false;
 
   if (getLang().CPlusPlus0x &&
       (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) {
     Diag(Tok, diag::warn_cxx98_compat_scoped_enum);
-    IsScopedEnum = true;
     IsScopedUsingClassTag = Tok.is(tok::kw_class);
-    ConsumeToken();
+    ScopedEnumKWLoc = ConsumeToken();
   }
   
   // If attributes exist after tag, parse them.
@@ -2922,11 +2921,11 @@
     NameLoc = ConsumeToken();
   }
 
-  if (!Name && IsScopedEnum) {
+  if (!Name && ScopedEnumKWLoc.isValid()) {
     // C++0x 7.2p2: The optional identifier shall not be omitted in the
     // declaration of a scoped enumeration.
     Diag(Tok, diag::err_scoped_enum_missing_identifier);
-    IsScopedEnum = false;
+    ScopedEnumKWLoc = SourceLocation();
     IsScopedUsingClassTag = false;
   }
 
@@ -2993,16 +2992,20 @@
     }
   }
 
-  // There are three options here.  If we have 'enum foo;', then this is a
-  // forward declaration.  If we have 'enum foo {...' then this is a
-  // definition. Otherwise we have something like 'enum foo xyz', a reference.
+  // There are four options here.  If we have 'friend enum foo;' then this is a
+  // friend declaration, and cannot have an accompanying definition. If we have
+  // 'enum foo;', then this is a forward declaration.  If we have
+  // 'enum foo {...' then this is a definition. Otherwise we have something
+  // like 'enum foo xyz', a reference.
   //
   // This is needed to handle stuff like this right (C99 6.7.2.3p11):
   // enum foo {..};  void bar() { enum foo; }    <- new foo in bar.
   // enum foo {..};  void bar() { enum foo x; }  <- use of old foo.
   //
   Sema::TagUseKind TUK;
-  if (Tok.is(tok::l_brace))
+  if (DS.isFriendSpecified())
+    TUK = Sema::TUK_Friend;
+  else if (Tok.is(tok::l_brace))
     TUK = Sema::TUK_Definition;
   else if (Tok.is(tok::semi))
     TUK = Sema::TUK_Declaration;
@@ -3036,7 +3039,7 @@
                                    StartLoc, SS, Name, NameLoc, attrs.getList(),
                                    AS, DS.getModulePrivateSpecLoc(),
                                    MultiTemplateParamsArg(Actions),
-                                   Owned, IsDependent, IsScopedEnum,
+                                   Owned, IsDependent, ScopedEnumKWLoc,
                                    IsScopedUsingClassTag, BaseType);
 
   if (IsDependent) {
@@ -3075,9 +3078,13 @@
     DS.SetTypeSpecError();
     return;
   }
-  
-  if (Tok.is(tok::l_brace))
+
+  if (Tok.is(tok::l_brace)) {
+    if (TUK == Sema::TUK_Friend)
+      Diag(Tok, diag::err_friend_decl_defines_type)
+        << SourceRange(DS.getFriendSpecLoc());
     ParseEnumBody(StartLoc, TagDecl);
+  }
 
   if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,
                          NameLoc.isValid() ? NameLoc : StartLoc,

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jan  9 19:33:14 2012
@@ -1115,7 +1115,7 @@
     if (DS.isFriendSpecified()) {
       // C++ [class.friend]p2:
       //   A class shall not be defined in a friend declaration.
-      Diag(Tok.getLocation(), diag::err_friend_decl_defines_class)
+      Diag(Tok.getLocation(), diag::err_friend_decl_defines_type)
         << SourceRange(DS.getFriendSpecLoc());
 
       // Skip everything up to the semicolon, so that this looks like a proper
@@ -1277,8 +1277,9 @@
     TagOrTempResult = Actions.ActOnTag(getCurScope(), TagType, TUK, StartLoc,
                                        SS, Name, NameLoc, attrs.getList(), AS,
                                        DS.getModulePrivateSpecLoc(),
-                                       TParams, Owned, IsDependent, false,
-                                       false, clang::TypeResult());
+                                       TParams, Owned, IsDependent,
+                                       SourceLocation(), false,
+                                       clang::TypeResult());
 
     // If ActOnTag said the type was dependent, try again with the
     // less common call.

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Jan  9 19:33:14 2012
@@ -7580,7 +7580,8 @@
                      SourceLocation ModulePrivateLoc,
                      MultiTemplateParamsArg TemplateParameterLists,
                      bool &OwnedDecl, bool &IsDependent,
-                     bool ScopedEnum, bool ScopedEnumUsesClassTag,
+                     SourceLocation ScopedEnumKWLoc,
+                     bool ScopedEnumUsesClassTag,
                      TypeResult UnderlyingType) {
   // If this is not a definition, it must have a name.
   assert((Name != 0 || TUK == TUK_Definition) &&
@@ -7589,6 +7590,7 @@
 
   OwnedDecl = false;
   TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec);
+  bool ScopedEnum = ScopedEnumKWLoc.isValid();
 
   // FIXME: Check explicit specializations more carefully.
   bool isExplicitSpecialization = false;
@@ -7919,6 +7921,16 @@
         if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
           const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);
 
+          // If this is an elaborated-type-specifier for a scoped enumeration,
+          // the 'class' keyword is not necessary and not permitted.
+          if (TUK == TUK_Reference || TUK == TUK_Friend) {
+            if (ScopedEnum)
+              Diag(ScopedEnumKWLoc, diag::err_enum_class_reference)
+                << PrevEnum->isScoped()
+                << FixItHint::CreateRemoval(ScopedEnumKWLoc);
+            return PrevTagDecl;
+          }
+
           // All conflicts with previous declarations are recovered by
           // returning the previous declaration.
           if (ScopedEnum != PrevEnum->isScoped()) {

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan  9 19:33:14 2012
@@ -9851,7 +9851,7 @@
                       Attr, AS_public, 
                       /*ModulePrivateLoc=*/SourceLocation(),
                       MultiTemplateParamsArg(), Owned, IsDependent, 
-                      /*ScopedEnum=*/false,
+                      /*ScopedEnumKWLoc=*/SourceLocation(),
                       /*ScopedEnumUsesClassTag=*/false,
                       /*UnderlyingType=*/TypeResult());          
     }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Jan  9 19:33:14 2012
@@ -6070,7 +6070,7 @@
                         KWLoc, SS, Name, NameLoc, Attr, AS_none,
                         /*ModulePrivateLoc=*/SourceLocation(),
                         MultiTemplateParamsArg(*this, 0, 0),
-                        Owned, IsDependent, false, false,
+                        Owned, IsDependent, SourceLocation(), false,
                         TypeResult());
   assert(!IsDependent && "explicit instantiation of dependent name not yet handled");
 

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p3.cpp Mon Jan  9 19:33:14 2012
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
-class A {}; // expected-note 3 {{previous use is here}}
+class A {}; // expected-note 4 {{previous use is here}}
+enum E {};
 
 void a1(struct A);
 void a2(class A);
@@ -12,8 +13,8 @@
   friend class A;
   friend union A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
 
-  friend enum A; // expected-error {{ISO C++ forbids forward references to 'enum' types}} \
-                 // expected-warning {{cannot be a friend}}
+  friend enum A; // expected-error {{use of 'A' with tag type that does not match previous declaration}}
+  friend enum E; // expected-warning {{cannot be a friend}}
 };
 
 template <class T> struct B { // expected-note {{previous use is here}}

Modified: cfe/trunk/test/FixIt/fixit-cxx0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/FixIt/fixit-cxx0x.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/test/FixIt/fixit-cxx0x.cpp (original)
+++ cfe/trunk/test/FixIt/fixit-cxx0x.cpp Mon Jan  9 19:33:14 2012
@@ -37,3 +37,12 @@
       f3 override, // expected-error {{expected ';' at end of declaration}}
   };
 }
+
+namespace ScopedEnum {
+  enum class E { a };
+
+  enum class E b = E::a; // expected-error {{must use 'enum' not 'enum class'}}
+  struct S {
+    friend enum class E; // expected-error {{must use 'enum' not 'enum class'}}
+  };
+}

Modified: cfe/trunk/test/SemaCXX/enum-scoped.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-scoped.cpp?rev=147824&r1=147823&r2=147824&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/enum-scoped.cpp (original)
+++ cfe/trunk/test/SemaCXX/enum-scoped.cpp Mon Jan  9 19:33:14 2012
@@ -147,3 +147,30 @@
   const int val = 104;
   enum class test1 { owner_dead = val, };
 }
+
+namespace N2764 {
+  enum class E { a, b };
+  enum E x1 = E::a; // ok
+  enum class E x2 = E::a; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
+
+  enum F { a, b };
+  enum F y1 = a; // ok
+  enum class F y2 = a; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
+
+  struct S {
+    friend enum class E; // expected-error {{reference to scoped enumeration must use 'enum' not 'enum class'}}
+    friend enum class F; // expected-error {{reference to enumeration must use 'enum' not 'enum class'}}
+
+    friend enum G {}; // expected-error {{forward reference}} expected-error {{cannot define a type in a friend declaration}}
+    friend enum class H {}; // expected-error {{cannot define a type in a friend declaration}}
+
+    enum A : int;
+    A a;
+  } s;
+
+  enum S::A : int {};
+
+  enum class B;
+}
+
+enum class N2764::B {};





More information about the cfe-commits mailing list