[cfe-commits] r153304 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Parse/ lib/Sema/ test/CXX/temp/temp.decls/temp.class/temp.mem.enum/ test/CXX/temp/temp.spec/temp.explicit/

Richard Smith richard-llvm at metafoo.co.uk
Thu Mar 22 20:33:33 PDT 2012


Author: rsmith
Date: Thu Mar 22 22:33:32 2012
New Revision: 153304

URL: http://llvm.org/viewvc/llvm-project?rev=153304&view=rev
Log:
Support for definitions of member enumerations of class templates outside the
class template's definition, and for explicit specializations of such enum
members.

Added:
    cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/
    cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Thu Mar 22 22:33:32 2012
@@ -2862,6 +2862,16 @@
   /// this enumeration was not instantiated from any template.
   EnumDecl *getInstantiatedFromMemberEnum() const;
 
+  /// \brief If this enumeration is a member of a specialization of a
+  /// templated class, determine what kind of template specialization
+  /// or instantiation this is.
+  TemplateSpecializationKind getTemplateSpecializationKind() const;
+
+  /// \brief For an enumeration member that was instantiated from a member
+  /// enumeration of a templated class, set the template specialiation kind.
+  void setTemplateSpecializationKind(TemplateSpecializationKind TSK,
+                        SourceLocation PointOfInstantiation = SourceLocation());
+
   /// \brief If this enumeration is an instantiation of a member enumeration of
   /// a class template specialization, retrieves the member specialization
   /// information.

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Thu Mar 22 22:33:32 2012
@@ -500,6 +500,8 @@
     "definition is meant to be an explicit specialization, add '<>' after the "
     "'template' keyword">;
 def err_enum_template : Error<"enumeration cannot be a template">;
+def err_explicit_instantiation_enum : Error<
+    "enumerations cannot be explicitly instantiated">;
 
 def err_missing_dependent_template_keyword : Error<
   "use 'template' keyword to treat '%0' as a dependent template name">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Mar 22 22:33:32 2012
@@ -2376,7 +2376,8 @@
 // C++ template specialization
 def err_template_spec_unknown_kind : Error<
   "can only provide an explicit specialization for a class template, function "
-  "template, or a member function, static data member, or member class of a "
+  "template, or a member function, static data member, "
+  "%select{or member class|member class, or member enumeration}0 of a "
   "class template">;
 def note_specialized_entity : Note<
   "explicitly specialized declaration is here">;
@@ -2388,30 +2389,30 @@
   "cannot declare an explicit specialization in a friend">;
 def err_template_spec_decl_out_of_scope_global : Error<
   "%select{class template|class template partial|function template|member "
-  "function|static data member|member class}0 specialization of %1 must "
-  "originally be declared in the global scope">;
+  "function|static data member|member class|member enumeration}0 "
+  "specialization of %1 must originally be declared in the global scope">;
 def err_template_spec_decl_out_of_scope : Error<
   "%select{class template|class template partial|function template|member "
-  "function|static data member|member class}0 specialization of %1 must "
-  "originally be declared in namespace %2">;
+  "function|static data member|member class|member enumeration}0 "
+  "specialization of %1 must originally be declared in namespace %2">;
 def ext_template_spec_decl_out_of_scope : ExtWarn<
   "first declaration of %select{class template|class template partial|"
-  "function template|member function|static data member|member class}0 "
-  "specialization of %1 outside namespace %2 is a C++11 extension">,
-  InGroup<CXX11>;
+  "function template|member function|static data member|member class|"
+  "member enumeration}0 specialization of %1 outside namespace %2 is a "
+  "C++11 extension">, InGroup<CXX11>;
 def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning<
   "%select{class template|class template partial|function template|member "
-  "function|static data member|member class}0 specialization of %1 outside "
-  "namespace %2 is incompatible with C++98">,
+  "function|static data member|member class|member enumeration}0 "
+  "specialization of %1 outside namespace %2 is incompatible with C++98">,
   InGroup<CXX98Compat>, DefaultIgnore;
 def err_template_spec_redecl_out_of_scope : Error<
   "%select{class template|class template partial|function template|member "
-  "function|static data member|member class}0 specialization of %1 not in a "
-  "namespace enclosing %2">;
+  "function|static data member|member class|member enumeration}0 "
+  "specialization of %1 not in a namespace enclosing %2">;
 def err_template_spec_redecl_global_scope : Error<
   "%select{class template|class template partial|function template|member "
-  "function|static data member|member class}0 specialization of %1 must occur "
-  "at global scope">;
+  "function|static data member|member class|member enumeration}0 "
+  "specialization of %1 must occur at global scope">;
 def err_spec_member_not_instantiated : Error<
   "specialization of member %q0 does not specialize an instantiated member">;
 def note_specialized_decl : Note<"attempt to specialize declaration here">;
@@ -2579,8 +2580,6 @@
     InGroup<CXX98CompatPedantic>, DefaultIgnore;
 def note_previous_template_specialization : Note<
     "previous template specialization is here">;
-def err_explicit_instantiation_enum : Error<
-    "explicit instantiation of enumeration type %0">;
 def err_explicit_instantiation_nontemplate_type : Error<
     "explicit instantiation of non-templated type %0">;
 def note_nontemplate_decl_here : Note<

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Mar 22 22:33:32 2012
@@ -4132,6 +4132,26 @@
   /// failures rather than hard errors.
   bool AccessCheckingSFINAE;
 
+  /// \brief RAII object used to temporarily suppress access checking.
+  class SuppressAccessChecksRAII {
+    Sema &S;
+    bool SuppressingAccess;
+
+  public:
+    SuppressAccessChecksRAII(Sema &S, bool Suppress)
+      : S(S), SuppressingAccess(Suppress) {
+      if (Suppress) S.ActOnStartSuppressingAccessChecks();
+    }
+    ~SuppressAccessChecksRAII() {
+      done();
+    }
+    void done() {
+      if (!SuppressingAccess) return;
+      S.ActOnStopSuppressingAccessChecks();
+      SuppressingAccess = false;
+    }
+  };
+
   void ActOnStartSuppressingAccessChecks();
   void ActOnStopSuppressingAccessChecks();
 

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Mar 22 22:33:32 2012
@@ -2674,6 +2674,24 @@
   TagDecl::completeDefinition();
 }
 
+TemplateSpecializationKind EnumDecl::getTemplateSpecializationKind() const {
+  if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo())
+    return MSI->getTemplateSpecializationKind();
+
+  return TSK_Undeclared;
+}
+
+void EnumDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK,
+                                         SourceLocation PointOfInstantiation) {
+  MemberSpecializationInfo *MSI = getMemberSpecializationInfo();
+  assert(MSI && "Not an instantiated member enumeration?");
+  MSI->setTemplateSpecializationKind(TSK);
+  if (TSK != TSK_ExplicitSpecialization &&
+      PointOfInstantiation.isValid() &&
+      MSI->getPointOfInstantiation().isInvalid())
+    MSI->setPointOfInstantiation(PointOfInstantiation);
+}
+
 EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const {
   if (SpecializationInfo)
     return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom());

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Mar 22 22:33:32 2012
@@ -2611,19 +2611,20 @@
 ///         'enum' identifier
 /// [GNU]   'enum' attributes[opt] identifier
 ///
-/// [C++0x] enum-head '{' enumerator-list[opt] '}'
-/// [C++0x] enum-head '{' enumerator-list ','  '}'
+/// [C++11] enum-head '{' enumerator-list[opt] '}'
+/// [C++11] enum-head '{' enumerator-list ','  '}'
 ///
-///       enum-head: [C++0x]
-///         enum-key attributes[opt] identifier[opt] enum-base[opt]
-///         enum-key attributes[opt] nested-name-specifier identifier enum-base[opt]
+///       enum-head: [C++11]
+///         enum-key attribute-specifier-seq[opt] identifier[opt] enum-base[opt]
+///         enum-key attribute-specifier-seq[opt] nested-name-specifier
+///             identifier enum-base[opt]
 ///
-///       enum-key: [C++0x]
+///       enum-key: [C++11]
 ///         'enum'
 ///         'enum' 'class'
 ///         'enum' 'struct'
 ///
-///       enum-base: [C++0x]
+///       enum-base: [C++11]
 ///         ':' type-specifier-seq
 ///
 /// [C++] elaborated-type-specifier:
@@ -2648,7 +2649,14 @@
     IsScopedUsingClassTag = Tok.is(tok::kw_class);
     ScopedEnumKWLoc = ConsumeToken();
   }
-  
+
+  // C++11 [temp.explicit]p12: The usual access controls do not apply to names
+  // used to specify explicit instantiations. We extend this to also cover
+  // explicit specializations.
+  Sema::SuppressAccessChecksRAII SuppressAccess(Actions,
+    TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
+    TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
+
   // If attributes exist after tag, parse them.
   ParsedAttributes attrs(AttrFactory);
   MaybeParseGNUAttributes(attrs);
@@ -2711,6 +2719,9 @@
     IsScopedUsingClassTag = false;
   }
 
+  // Stop suppressing access control now we've parsed the enum name.
+  SuppressAccess.done();
+
   TypeResult BaseType;
 
   // Parse the fixed underlying type.
@@ -2801,34 +2812,44 @@
     TUK = Sema::TUK_Declaration;
   else
     TUK = Sema::TUK_Reference;
-  
-  // enums cannot be templates, although they can be referenced from a 
-  // template.
+
+  MultiTemplateParamsArg TParams;
   if (TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
       TUK != Sema::TUK_Reference) {
-    Diag(Tok, diag::err_enum_template);
-    
-    // Skip the rest of this declarator, up until the comma or semicolon.
-    SkipUntil(tok::comma, true);
-    return;      
+    if (!getLangOpts().CPlusPlus0x || !SS.isSet()) {
+      // Skip the rest of this declarator, up until the comma or semicolon.
+      Diag(Tok, diag::err_enum_template);
+      SkipUntil(tok::comma, true);
+      return;
+    }
+
+    if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) {
+      // Enumerations can't be explicitly instantiated.
+      DS.SetTypeSpecError();
+      Diag(StartLoc, diag::err_explicit_instantiation_enum);
+      return;
+    }
+
+    assert(TemplateInfo.TemplateParams && "no template parameters");
+    TParams = MultiTemplateParamsArg(TemplateInfo.TemplateParams->data(),
+                                     TemplateInfo.TemplateParams->size());
   }
-  
+
   if (!Name && TUK != Sema::TUK_Definition) {
     Diag(Tok, diag::err_enumerator_unnamed_no_def);
-    
+
     // Skip the rest of this declarator, up until the comma or semicolon.
     SkipUntil(tok::comma, true);
     return;
   }
-      
+
   bool Owned = false;
   bool IsDependent = false;
   const char *PrevSpec = 0;
   unsigned DiagID;
   Decl *TagDecl = Actions.ActOnTag(getCurScope(), DeclSpec::TST_enum, TUK,
                                    StartLoc, SS, Name, NameLoc, attrs.getList(),
-                                   AS, DS.getModulePrivateSpecLoc(),
-                                   MultiTemplateParamsArg(Actions),
+                                   AS, DS.getModulePrivateSpecLoc(), TParams,
                                    Owned, IsDependent, ScopedEnumKWLoc,
                                    IsScopedUsingClassTag, BaseType);
 
@@ -2870,10 +2891,14 @@
   }
 
   if (Tok.is(tok::l_brace) && TUK != Sema::TUK_Reference) {
-    if (TUK == Sema::TUK_Friend)
+    if (TUK == Sema::TUK_Friend) {
       Diag(Tok, diag::err_friend_decl_defines_type)
         << SourceRange(DS.getFriendSpecLoc());
-    ParseEnumBody(StartLoc, TagDecl);
+      ConsumeBrace();
+      SkipUntil(tok::r_brace);
+    } else {
+      ParseEnumBody(StartLoc, TagDecl);
+    }
   }
 
   if (DS.SetTypeSpecType(DeclSpec::TST_enum, StartLoc,

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Thu Mar 22 22:33:32 2012
@@ -968,12 +968,9 @@
   // As an extension we do not perform access checking on the names used to
   // specify explicit specializations either. This is important to allow
   // specializing traits classes for private types.
-  bool SuppressingAccessChecks = false;
-  if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
-      TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) {
-    Actions.ActOnStartSuppressingAccessChecks();
-    SuppressingAccessChecks = true;
-  }
+  Sema::SuppressAccessChecksRAII SuppressAccess(Actions,
+    TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation ||
+    TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization);
 
   ParsedAttributes attrs(AttrFactory);
   // If attributes exist after tag, parse them.
@@ -1102,17 +1099,13 @@
 
       DS.SetTypeSpecError();
       SkipUntil(tok::semi, false, true);
-      if (SuppressingAccessChecks)
-        Actions.ActOnStopSuppressingAccessChecks();
-
       return;
     }
   }
 
   // As soon as we're finished parsing the class's template-id, turn access
   // checking back on.
-  if (SuppressingAccessChecks)
-    Actions.ActOnStopSuppressingAccessChecks();
+  SuppressAccess.done();
 
   // There are four options here.
   //  - If we are in a trailing return type, this is always just a reference,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Thu Mar 22 22:33:32 2012
@@ -246,10 +246,14 @@
   EnumDecl *ED = enumType->getDecl();
   if (EnumDecl *Pattern = ED->getInstantiatedFromMemberEnum()) {
     MemberSpecializationInfo *MSI = ED->getMemberSpecializationInfo();
-    if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization)
-      return InstantiateEnum(loc, ED, Pattern,
-                             getTemplateInstantiationArgs(ED),
-                             TSK_ImplicitInstantiation);
+    if (MSI->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) {
+      if (InstantiateEnum(loc, ED, Pattern, getTemplateInstantiationArgs(ED),
+                          TSK_ImplicitInstantiation)) {
+        SS.SetInvalid(SS.getRange());
+        return true;
+      }
+      return false;
+    }
   }
 
   Diag(loc, diag::err_incomplete_nested_name_spec)

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Mar 22 22:33:32 2012
@@ -8283,10 +8283,19 @@
               // If we're defining a specialization and the previous definition
               // is from an implicit instantiation, don't emit an error
               // here; we'll catch this in the general case below.
-              if (!isExplicitSpecialization ||
-                  !isa<CXXRecordDecl>(Def) ||
-                  cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind() 
-                                               == TSK_ExplicitSpecialization) {
+              bool IsExplicitSpecializationAfterInstantiation = false;
+              if (isExplicitSpecialization) {
+                if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Def))
+                  IsExplicitSpecializationAfterInstantiation =
+                    RD->getTemplateSpecializationKind() !=
+                    TSK_ExplicitSpecialization;
+                else if (EnumDecl *ED = dyn_cast<EnumDecl>(Def))
+                  IsExplicitSpecializationAfterInstantiation =
+                    ED->getTemplateSpecializationKind() !=
+                    TSK_ExplicitSpecialization;
+              }
+
+              if (!IsExplicitSpecializationAfterInstantiation) {
                 // A redeclaration in function prototype scope in C isn't
                 // visible elsewhere, so merely issue a warning.
                 if (!getLangOpts().CPlusPlus && S->containedInPrototypeScope())

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Mar 22 22:33:32 2012
@@ -1413,8 +1413,7 @@
   assert((!isa<TagDecl>(LookupCtx) ||
           LookupCtx->isDependentContext() ||
           cast<TagDecl>(LookupCtx)->isCompleteDefinition() ||
-          Context.getTypeDeclType(cast<TagDecl>(LookupCtx))->getAs<TagType>()
-            ->isBeingDefined()) &&
+          cast<TagDecl>(LookupCtx)->isBeingDefined()) &&
          "Declaration context must already be complete!");
 
   // Perform qualified name lookup into the LookupCtx.

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Mar 22 22:33:32 2012
@@ -4699,8 +4699,11 @@
     EntityKind = 4;
   else if (isa<RecordDecl>(Specialized))
     EntityKind = 5;
+  else if (isa<EnumDecl>(Specialized) && S.getLangOpts().CPlusPlus0x)
+    EntityKind = 6;
   else {
-    S.Diag(Loc, diag::err_template_spec_unknown_kind);
+    S.Diag(Loc, diag::err_template_spec_unknown_kind)
+      << S.getLangOpts().CPlusPlus0x;
     S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
     return true;
   }
@@ -5816,6 +5819,14 @@
       InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
       MSInfo = PrevRecord->getMemberSpecializationInfo();
     }
+  } else if (isa<EnumDecl>(Member)) {
+    EnumDecl *PrevEnum;
+    if (Previous.isSingleResult() &&
+        (PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) {
+      Instantiation = PrevEnum;
+      InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum();
+      MSInfo = PrevEnum->getMemberSpecializationInfo();
+    }
   }
 
   if (!Instantiation) {
@@ -5906,8 +5917,7 @@
                                                 cast<VarDecl>(InstantiatedFrom),
                                                 TSK_ExplicitSpecialization);
     MarkUnusedFileScopedDecl(InstantiationVar);
-  } else {
-    assert(isa<CXXRecordDecl>(Member) && "Only member classes remain");
+  } else if (isa<CXXRecordDecl>(Member)) {
     CXXRecordDecl *InstantiationClass = cast<CXXRecordDecl>(Instantiation);
     if (InstantiationClass->getTemplateSpecializationKind() ==
           TSK_ImplicitInstantiation) {
@@ -5919,6 +5929,18 @@
     cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
                                         cast<CXXRecordDecl>(InstantiatedFrom),
                                                    TSK_ExplicitSpecialization);
+  } else {
+    assert(isa<EnumDecl>(Member) && "Only member enums remain");
+    EnumDecl *InstantiationEnum = cast<EnumDecl>(Instantiation);
+    if (InstantiationEnum->getTemplateSpecializationKind() ==
+          TSK_ImplicitInstantiation) {
+      InstantiationEnum->setTemplateSpecializationKind(
+                                                   TSK_ExplicitSpecialization);
+      InstantiationEnum->setLocation(Member->getLocation());
+    }
+
+    cast<EnumDecl>(Member)->setInstantiationOfMemberEnum(
+        cast<EnumDecl>(InstantiatedFrom), TSK_ExplicitSpecialization);
   }
 
   // Save the caller the trouble of having to figure out which declaration
@@ -6219,11 +6241,7 @@
     return true;
 
   TagDecl *Tag = cast<TagDecl>(TagD);
-  if (Tag->isEnum()) {
-    Diag(TemplateLoc, diag::err_explicit_instantiation_enum)
-      << Context.getTypeDeclType(Tag);
-    return true;
-  }
+  assert(!Tag->isEnum() && "shouldn't see enumerations here");
 
   if (Tag->isInvalidDecl())
     return true;

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Thu Mar 22 22:33:32 2012
@@ -1843,7 +1843,20 @@
         if (OldField->getInClassInitializer())
           FieldsWithMemberInitializers.push_back(std::make_pair(OldField,
                                                                 Field));
-      } else if (NewMember->isInvalidDecl())
+      } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(NewMember)) {
+        // C++11 [temp.inst]p1: The implicit instantiation of a class template
+        // specialization causes the implicit instantiation of the definitions
+        // of unscoped member enumerations.
+        // Record a point of instantiation for this implicit instantiation.
+        if (TSK == TSK_ImplicitInstantiation && !Enum->isScoped()) {
+          MemberSpecializationInfo *MSInfo =Enum->getMemberSpecializationInfo();
+          assert(MSInfo && "no spec info for member enum specialization");
+          MSInfo->setTemplateSpecializationKind(TSK_ImplicitInstantiation);
+          MSInfo->setPointOfInstantiation(PointOfInstantiation);
+        }
+      }
+
+      if (NewMember->isInvalidDecl())
         Invalid = true;
     } else {
       // FIXME: Eventually, a NULL return will mean that one of the

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Mar 22 22:33:32 2012
@@ -600,7 +600,7 @@
   // not the definitions of scoped member enumerations.
   // FIXME: There appears to be no wording for what happens for an enum defined
   // within a block scope, but we treat that like a member of a class template.
-  if (!Enum->isScoped())
+  if (!Enum->isScoped() && D->getDefinition())
     InstantiateEnumDefinition(Enum, D);
 
   return Enum;
@@ -610,6 +610,9 @@
     EnumDecl *Enum, EnumDecl *Pattern) {
   Enum->startDefinition();
 
+  // Update the location to refer to the definition.
+  Enum->setLocation(Pattern->getLocation());
+
   SmallVector<Decl*, 4> Enumerators;
 
   EnumConstantDecl *LastEnumConst = 0;

Added: cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp?rev=153304&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp Thu Mar 22 22:33:32 2012
@@ -0,0 +1,152 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+template<typename T> struct A {
+  enum E : T; // expected-note {{here}}
+  E v;
+  E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A<T>'}}
+  E g() { return E::e1; }
+  E h();
+};
+
+A<int> a;
+A<int>::E a0 = A<int>().v;
+int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}
+
+template<typename T> enum A<T>::E : T { e1, e2 };
+
+// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
+// into the already-instantiated class A<T>. This seems like a really bad idea,
+// though, so we don't implement that, but what we do implement is inconsistent.
+//
+// Either do as the standard says, or only include enumerators lexically defined
+// within the class in its scope.
+A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}
+
+A<char>::E a2 = A<char>::e2;
+
+template<typename T> typename A<T>::E A<T>::h() { return e2; }
+A<short>::E a3 = A<short>().h();
+
+
+template<typename T> struct B {
+  enum class E;
+  E v;
+  E f() { return E::e1; }
+  E g();
+};
+
+B<int> b;
+B<int>::E b0 = B<int>().v;
+
+template<typename T> enum class B<T>::E { e1, e2 };
+B<int>::E b1 = B<int>::E::e1;
+
+B<char>::E b2 = B<char>::E::e2;
+
+template<typename T> typename B<T>::E B<T>::g() { return e2; }
+B<short>::E b3 = B<short>().g();
+
+
+// Enumeration members of class templates can be explicitly specialized. For
+// unscoped enumerations, specializations must be defined before the primary
+// template is, since otherwise the primary template will be implicitly
+// instantiated when we parse the nested name specifier.
+template<> enum A<long long>::E : long long { e3, e4 }; // expected-error {{explicit specialization of 'E' after instantiation}} expected-note {{first required here}}
+
+template<> enum class B<long long>::E { e3, e4 };
+B<long long>::E b4 = B<long long>::E::e4;
+
+B<long>::E b5;
+template<> enum class B<long>::E { e5 };
+void fb5() { b5 = decltype(b5)::e5; }
+B<long>::E b6 = B<long>::E::e5;
+
+
+template<typename T> struct C {
+  enum class E : T;
+};
+
+template<> enum class C<long long>::E : long long { e3, e4 };
+C<long long>::E c0 = C<long long>::E::e3;
+
+C<long>::E c1;
+template<> enum class C<long>::E : long { e5 };
+void fc1() { c1 = decltype(c1)::e5; }
+C<long>::E c2 = C<long>::E::e5;
+
+template<> enum class C<int>::E : int { e6 };
+template<typename T> enum class C<T>::E : T { e0 };
+C<int>::E c3 = C<int>::E::e6;
+C<int>::E c4 = C<int>::E::e0; // expected-error {{no member named 'e0' in 'C<int>::E'}}
+
+
+// Enumeration members can't be partially-specialized.
+template<typename T> enum class B<T*>::E { e5, e6 }; // expected-error {{nested name specifier for a declaration cannot depend on a template parameter}}
+
+
+// Explicit specializations can be forward-declared.
+template<typename T>
+struct D {
+  enum class E { e1 };
+};
+template<> enum class D<int>::E;
+D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
+template<> enum class D<int>::E { e2 };
+D<int>::E d2 = D<int>::E::e2;
+D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
+D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
+template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}
+
+template<> enum class D<short>::E;
+struct F {
+  // Per C++11 [class.friend]p3, these friend declarations have no effect.
+  // Only classes and functions can be friends.
+  template<typename T> friend enum D<T>::E;
+  template<> friend enum D<short>::E;
+
+  template<> friend enum D<double>::E { e3 }; // expected-error {{cannot define a type in a friend declaration}}
+
+private:
+  static const int n = 1; // expected-note {{private here}}
+};
+template<> enum class D<short>::E {
+  e = F::n // expected-error {{private member}}
+};
+
+class Access {
+  friend class X;
+
+  template<typename T>
+  class Priv {
+    friend class X;
+
+    enum class E : T;
+  };
+
+  class S {
+    typedef int N; // expected-note {{here}}
+    static const int k = 3; // expected-note {{here}}
+
+    friend class Priv<char>;
+  };
+
+  static const int k = 5;
+};
+
+template<> enum class Access::Priv<Access::S::N>::E
+  : Access::S::N { // expected-error {{private member}}
+  a = Access::k, // ok
+  b = Access::S::k // expected-error {{private member}}
+};
+
+template<typename T> enum class Access::Priv<T>::E : T {
+  c = Access::k,
+  d = Access::S::k
+};
+
+class X {
+  Access::Priv<int>::E a = Access::Priv<int>::E::a;
+  Access::Priv<char>::E c = Access::Priv<char>::E::d;
+  // FIXME: We should see an access error for this enumerator.
+  Access::Priv<short>::E b = Access::Priv<short>::E::d;
+};

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp?rev=153304&r1=153303&r2=153304&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p1-0x.cpp Thu Mar 22 22:33:32 2012
@@ -13,3 +13,12 @@
 };
 
 template constexpr int Y<int>::f(); // expected-error{{explicit instantiation cannot be 'constexpr'}}
+
+template<typename T>
+struct Z {
+  enum E : T { e1, e2 };
+  T t; // expected-note {{refers here}}
+};
+
+template enum Z<int>::E; // expected-error {{enumerations cannot be explicitly instantiated}}
+template int Z<int>::t; // expected-error {{explicit instantiation of 't' does not refer to}}





More information about the cfe-commits mailing list