[cfe-commits] r152750 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ lib/AST/ lib/Sema/ lib/Serialization/ test/CXX/temp/temp.spec/temp.explicit/ test/CXX/temp/temp.spec/temp.inst/ test/PCH/ www/

Richard Smith richard-llvm at metafoo.co.uk
Wed Mar 14 16:13:11 PDT 2012


Author: rsmith
Date: Wed Mar 14 18:13:10 2012
New Revision: 152750

URL: http://llvm.org/viewvc/llvm-project?rev=152750&view=rev
Log:
Instantiating a class template should not instantiate the definition of any
scoped enumeration members. Later uses of an enumeration temploid as a nested
name specifier should cause its instantiation. Plus some groundwork for
explicit specialization of member enumerations of class templates.

Added:
    cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp
    cfe/trunk/test/PCH/cxx11-enum-template.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/Template.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Mar 14 18:13:10 2012
@@ -2458,7 +2458,7 @@
   /// in the syntax of a declarator.
   bool IsEmbeddedInDeclarator : 1;
 
-  /// /brief True if this tag is free standing, e.g. "struct foo;".
+  /// \brief True if this tag is free standing, e.g. "struct foo;".
   bool IsFreeStanding : 1;
 
 protected:
@@ -2467,7 +2467,7 @@
   unsigned NumNegativeBits : 8;
 
   /// IsScoped - True if this tag declaration is a scoped enumeration. Only
-  /// possible in C++0x mode.
+  /// possible in C++11 mode.
   bool IsScoped : 1;
   /// IsScopedUsingClassTag - If this tag declaration is a scoped enum,
   /// then this is true if the scoped enum was declared using the class
@@ -2476,7 +2476,7 @@
   bool IsScopedUsingClassTag : 1;
 
   /// IsFixed - True if this is an enumeration with fixed underlying type. Only
-  /// possible in C++0x mode.
+  /// possible in C++11 or Microsoft extensions mode.
   bool IsFixed : 1;
 
 private:
@@ -2671,8 +2671,9 @@
   friend class ASTDeclWriter;
 };
 
-/// EnumDecl - Represents an enum.  As an extension, we allow forward-declared
-/// enums.
+/// EnumDecl - Represents an enum.  In C++11, enums can be forward-declared
+/// with a fixed underlying type, and in C we allow them to be forward-declared
+/// with no underlying type as an extension.
 class EnumDecl : public TagDecl {
   virtual void anchor();
   /// IntegerType - This represent the integer type that the enum corresponds
@@ -2698,10 +2699,10 @@
   /// in C++) are of the enum type instead.
   QualType PromotionType;
 
-  /// \brief If the enumeration was instantiated from an enumeration
-  /// within a class or function template, this pointer refers to the
-  /// enumeration declared within the template.
-  EnumDecl *InstantiatedFrom;
+  /// \brief If this enumeration is an instantiation of a member enumeration
+  /// of a class template specialization, this is the member specialization
+  /// information.
+  MemberSpecializationInfo *SpecializationInfo;
 
   // The number of positive and negative bits required by the
   // enumerators are stored in the SubclassBits field.
@@ -2714,7 +2715,7 @@
            IdentifierInfo *Id, EnumDecl *PrevDecl,
            bool Scoped, bool ScopedUsingClassTag, bool Fixed)
     : TagDecl(Enum, TTK_Enum, DC, IdLoc, Id, PrevDecl, StartLoc),
-      InstantiatedFrom(0) {
+      SpecializationInfo(0) {
     assert(Scoped || !ScopedUsingClassTag);
     IntegerType = (const Type*)0;
     NumNegativeBits = 0;
@@ -2723,6 +2724,9 @@
     IsScopedUsingClassTag = ScopedUsingClassTag;
     IsFixed = Fixed;
   }
+
+  void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
+                                    TemplateSpecializationKind TSK);
 public:
   EnumDecl *getCanonicalDecl() {
     return cast<EnumDecl>(TagDecl::getCanonicalDecl());
@@ -2745,6 +2749,10 @@
     return cast<EnumDecl>(TagDecl::getMostRecentDecl());
   }
 
+  EnumDecl *getDefinition() const {
+    return cast_or_null<EnumDecl>(TagDecl::getDefinition());
+  }
+
   static EnumDecl *Create(ASTContext &C, DeclContext *DC,
                           SourceLocation StartLoc, SourceLocation IdLoc,
                           IdentifierInfo *Id, EnumDecl *PrevDecl,
@@ -2767,14 +2775,14 @@
   typedef specific_decl_iterator<EnumConstantDecl> enumerator_iterator;
 
   enumerator_iterator enumerator_begin() const {
-    const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
+    const EnumDecl *E = getDefinition();
     if (!E)
       E = this;
     return enumerator_iterator(E->decls_begin());
   }
 
   enumerator_iterator enumerator_end() const {
-    const EnumDecl *E = cast_or_null<EnumDecl>(getDefinition());
+    const EnumDecl *E = getDefinition();
     if (!E)
       E = this;
     return enumerator_iterator(E->decls_end());
@@ -2859,11 +2867,21 @@
   /// \brief Returns the enumeration (declared within the template)
   /// from which this enumeration type was instantiated, or NULL if
   /// this enumeration was not instantiated from any template.
-  EnumDecl *getInstantiatedFromMemberEnum() const {
-    return InstantiatedFrom;
+  EnumDecl *getInstantiatedFromMemberEnum() const;
+
+  /// \brief If this enumeration is an instantiation of a member enumeration of
+  /// a class template specialization, retrieves the member specialization
+  /// information.
+  MemberSpecializationInfo *getMemberSpecializationInfo() const {
+    return SpecializationInfo;
   }
 
-  void setInstantiationOfMemberEnum(EnumDecl *IF) { InstantiatedFrom = IF; }
+  /// \brief Specify that this enumeration is an instantiation of the
+  /// member enumeration ED.
+  void setInstantiationOfMemberEnum(EnumDecl *ED,
+                                    TemplateSpecializationKind TSK) {
+    setInstantiationOfMemberEnum(getASTContext(), ED, TSK);
+  }
 
   static bool classof(const Decl *D) { return classofKind(D->getKind()); }
   static bool classof(const EnumDecl *D) { return true; }

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Mar 14 18:13:10 2012
@@ -355,8 +355,8 @@
 };
 
 /// \brief Provides information a specialization of a member of a class
-/// template, which may be a member function, static data member, or
-/// member class.
+/// template, which may be a member function, static data member,
+/// member class or member enumeration.
 class MemberSpecializationInfo {
   // The member declaration from which this member was instantiated, and the
   // manner in which the instantiation occurred (in the lower two bits).

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Mar 14 18:13:10 2012
@@ -2529,6 +2529,8 @@
   "in instantiation of function template specialization %q0 requested here">;
 def note_template_static_data_member_def_here : Note<
   "in instantiation of static data member %q0 requested here">;
+def note_template_enum_def_here : Note<
+  "in instantiation of enumeration %q0 requested here">;
 def note_template_type_alias_instantiation_here : Note<
   "in instantiation of template type alias %0 requested here">;
   

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed Mar 14 18:13:10 2012
@@ -1343,6 +1343,9 @@
                                       SourceLocation IdLoc,
                                       IdentifierInfo *Id,
                                       Expr *val);
+  bool CheckEnumUnderlyingType(TypeSourceInfo *TI);
+  bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
+                              QualType EnumUnderlyingTy, const EnumDecl *Prev);
 
   Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant,
                           SourceLocation IdLoc, IdentifierInfo *Id,
@@ -5489,6 +5492,11 @@
                    TemplateSpecializationKind TSK,
                    bool Complain = true);
 
+  bool InstantiateEnum(SourceLocation PointOfInstantiation,
+                       EnumDecl *Instantiation, EnumDecl *Pattern,
+                       const MultiLevelTemplateArgumentList &TemplateArgs,
+                       TemplateSpecializationKind TSK);
+
   struct LateInstantiatedAttribute {
     const Attr *TmplAttr;
     LocalInstantiationScope *Scope;

Modified: cfe/trunk/include/clang/Sema/Template.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Template.h (original)
+++ cfe/trunk/include/clang/Sema/Template.h Wed Mar 14 18:13:10 2012
@@ -484,6 +484,7 @@
     InstantiateClassTemplatePartialSpecialization(
                                               ClassTemplateDecl *ClassTemplate,
                            ClassTemplatePartialSpecializationDecl *PartialSpec);
+    void InstantiateEnumDefinition(EnumDecl *Enum, EnumDecl *Pattern);
   };  
 }
 

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Mar 14 18:13:10 2012
@@ -2674,6 +2674,19 @@
   TagDecl::completeDefinition();
 }
 
+EnumDecl *EnumDecl::getInstantiatedFromMemberEnum() const {
+  if (SpecializationInfo)
+    return cast<EnumDecl>(SpecializationInfo->getInstantiatedFrom());
+
+  return 0;
+}
+
+void EnumDecl::setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
+                                            TemplateSpecializationKind TSK) {
+  assert(!SpecializationInfo && "Member enum is already a specialization");
+  SpecializationInfo = new (C) MemberSpecializationInfo(ED, TSK);
+}
+
 //===----------------------------------------------------------------------===//
 // RecordDecl Implementation
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Mar 14 18:13:10 2012
@@ -13,6 +13,7 @@
 
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Lookup.h"
+#include "clang/Sema/Template.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ExprCXX.h"
@@ -209,43 +210,52 @@
                                       DeclContext *DC) {
   assert(DC != 0 && "given null context");
 
-  if (TagDecl *tag = dyn_cast<TagDecl>(DC)) {
-    // If this is a dependent type, then we consider it complete.
-    if (tag->isDependentContext())
-      return false;
+  TagDecl *tag = dyn_cast<TagDecl>(DC);
 
-    // If we're currently defining this type, then lookup into the
-    // type is okay: don't complain that it isn't complete yet.
-    QualType type = Context.getTypeDeclType(tag);
-    const TagType *tagType = type->getAs<TagType>();
-    if (tagType && tagType->isBeingDefined())
-      return false;
+  // If this is a dependent type, then we consider it complete.
+  if (!tag || tag->isDependentContext())
+    return false;
 
-    SourceLocation loc = SS.getLastQualifierNameLoc();
-    if (loc.isInvalid()) loc = SS.getRange().getBegin();
+  // If we're currently defining this type, then lookup into the
+  // type is okay: don't complain that it isn't complete yet.
+  QualType type = Context.getTypeDeclType(tag);
+  const TagType *tagType = type->getAs<TagType>();
+  if (tagType && tagType->isBeingDefined())
+    return false;
 
-    // The type must be complete.
-    if (RequireCompleteType(loc, type,
-                            PDiag(diag::err_incomplete_nested_name_spec)
-                              << SS.getRange())) {
-      SS.SetInvalid(SS.getRange());
-      return true;
-    }
+  SourceLocation loc = SS.getLastQualifierNameLoc();
+  if (loc.isInvalid()) loc = SS.getRange().getBegin();
 
-    // Fixed enum types are complete, but they aren't valid as scopes
-    // until we see a definition, so awkwardly pull out this special
-    // case.
-    if (const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType)) {
-      if (!enumType->getDecl()->isCompleteDefinition()) {
-        Diag(loc, diag::err_incomplete_nested_name_spec)
-          << type << SS.getRange();
-        SS.SetInvalid(SS.getRange());
-        return true;
-      }
-    }
+  // The type must be complete.
+  if (RequireCompleteType(loc, type,
+                          PDiag(diag::err_incomplete_nested_name_spec)
+                            << SS.getRange())) {
+    SS.SetInvalid(SS.getRange());
+    return true;
   }
 
-  return false;
+  // Fixed enum types are complete, but they aren't valid as scopes
+  // until we see a definition, so awkwardly pull out this special
+  // case.
+  const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
+  if (!enumType || enumType->getDecl()->isCompleteDefinition())
+    return false;
+
+  // Try to instantiate the definition, if this is a specialization of an
+  // enumeration temploid.
+  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);
+  }
+
+  Diag(loc, diag::err_incomplete_nested_name_spec)
+    << type << SS.getRange();
+  SS.SetInvalid(SS.getRange());
+  return true;
 }
 
 bool Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 14 18:13:10 2012
@@ -7738,6 +7738,50 @@
 }
 
 
+/// \brief Check that this is a valid underlying type for an enum declaration.
+bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
+  SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
+  QualType T = TI->getType();
+
+  if (T->isDependentType() || T->isIntegralType(Context))
+    return false;
+
+  Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T;
+  return true;
+}
+
+/// Check whether this is a valid redeclaration of a previous enumeration.
+/// \return true if the redeclaration was invalid.
+bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped,
+                                  QualType EnumUnderlyingTy,
+                                  const EnumDecl *Prev) {
+  bool IsFixed = !EnumUnderlyingTy.isNull();
+
+  if (IsScoped != Prev->isScoped()) {
+    Diag(EnumLoc, diag::err_enum_redeclare_scoped_mismatch)
+      << Prev->isScoped();
+    Diag(Prev->getLocation(), diag::note_previous_use);
+    return true;
+  }
+
+  if (IsFixed && Prev->isFixed()) {
+    if (!Context.hasSameUnqualifiedType(EnumUnderlyingTy,
+                                        Prev->getIntegerType())) {
+      Diag(EnumLoc, diag::err_enum_redeclare_type_mismatch)
+        << EnumUnderlyingTy << Prev->getIntegerType();
+      Diag(Prev->getLocation(), diag::note_previous_use);
+      return true;
+    }
+  } else if (IsFixed != Prev->isFixed()) {
+    Diag(EnumLoc, diag::err_enum_redeclare_fixed_mismatch)
+      << Prev->isFixed();
+    Diag(Prev->getLocation(), diag::note_previous_use);
+    return true;
+  }
+
+  return false;
+}
+
 /// \brief Determine whether a tag with a given kind is acceptable
 /// as a redeclaration of the given tag declaration.
 ///
@@ -7913,16 +7957,11 @@
       QualType T = GetTypeFromParser(UnderlyingType.get(), &TI);
       EnumUnderlying = TI;
 
-      SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
-
-      if (!T->isDependentType() && !T->isIntegralType(Context)) {
-        Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
-          << T;
+      if (CheckEnumUnderlyingType(TI))
         // Recover by falling back to int.
         EnumUnderlying = Context.IntTy.getTypePtr();
-      }
 
-      if (DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI, 
+      if (DiagnoseUnexpandedParameterPack(TI->getTypeLoc().getBeginLoc(), TI,
                                           UPPC_FixedUnderlyingType))
         EnumUnderlying = Context.IntTy.getTypePtr();
 
@@ -8196,37 +8235,17 @@
             return PrevTagDecl;
           }
 
+          QualType EnumUnderlyingTy;
+          if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
+            EnumUnderlyingTy = TI->getType();
+          else if (const Type *T = EnumUnderlying.dyn_cast<const Type*>())
+            EnumUnderlyingTy = QualType(T, 0);
+
           // All conflicts with previous declarations are recovered by
           // returning the previous declaration.
-          if (ScopedEnum != PrevEnum->isScoped()) {
-            Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
-              << PrevEnum->isScoped();
-            Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
-            return PrevTagDecl;
-          }
-          else if (EnumUnderlying && PrevEnum->isFixed()) {
-            QualType T;
-            if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>())
-                T = TI->getType();
-            else
-                T = QualType(EnumUnderlying.get<const Type*>(), 0);
-
-            if (!Context.hasSameUnqualifiedType(T, 
-                                                PrevEnum->getIntegerType())) {
-              Diag(NameLoc.isValid() ? NameLoc : KWLoc, 
-                   diag::err_enum_redeclare_type_mismatch)
-                << T
-                << PrevEnum->getIntegerType();
-              Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
-              return PrevTagDecl;
-            }
-          }
-          else if (!EnumUnderlying.isNull() != PrevEnum->isFixed()) {
-            Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
-              << PrevEnum->isFixed();
-            Diag(PrevTagDecl->getLocation(), diag::note_previous_use);
+          if (CheckEnumRedeclaration(NameLoc.isValid() ? NameLoc : KWLoc,
+                                     ScopedEnum, EnumUnderlyingTy, PrevEnum))
             return PrevTagDecl;
-          }
         }
 
         if (!Invalid) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Mar 14 18:13:10 2012
@@ -469,6 +469,11 @@
                      diag::note_template_static_data_member_def_here)
           << VD
           << Active->InstantiationRange;
+      } else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+        Diags.Report(Active->PointOfInstantiation,
+                     diag::note_template_enum_def_here)
+          << ED
+          << Active->InstantiationRange;
       } else {
         Diags.Report(Active->PointOfInstantiation,
                      diag::note_template_type_alias_instantiation_here)
@@ -1680,6 +1685,51 @@
   }
 }
 
+/// Determine whether we would be unable to instantiate this template (because
+/// it either has no definition, or is in the process of being instantiated).
+static bool DiagnoseUninstantiableTemplate(Sema &S,
+                                           SourceLocation PointOfInstantiation,
+                                           TagDecl *Instantiation,
+                                           bool InstantiatedFromMember,
+                                           TagDecl *Pattern,
+                                           TagDecl *PatternDef,
+                                           TemplateSpecializationKind TSK,
+                                           bool Complain = true) {
+  if (PatternDef && !PatternDef->isBeingDefined())
+    return false;
+
+  if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
+    // Say nothing
+  } else if (PatternDef) {
+    assert(PatternDef->isBeingDefined());
+    S.Diag(PointOfInstantiation,
+           diag::err_template_instantiate_within_definition)
+      << (TSK != TSK_ImplicitInstantiation)
+      << S.Context.getTypeDeclType(Instantiation);
+    // Not much point in noting the template declaration here, since
+    // we're lexically inside it.
+    Instantiation->setInvalidDecl();
+  } else if (InstantiatedFromMember) {
+    S.Diag(PointOfInstantiation,
+           diag::err_implicit_instantiate_member_undefined)
+      << S.Context.getTypeDeclType(Instantiation);
+    S.Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+  } else {
+    S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
+      << (TSK != TSK_ImplicitInstantiation)
+      << S.Context.getTypeDeclType(Instantiation);
+    S.Diag(Pattern->getLocation(), diag::note_template_decl_here);
+  }
+
+  // In general, Instantiation isn't marked invalid to get more than one
+  // error for multiple undefined instantiations. But the code that does
+  // explicit declaration -> explicit definition conversion can't handle
+  // invalid declarations, so mark as invalid in that case.
+  if (TSK == TSK_ExplicitInstantiationDeclaration)
+    Instantiation->setInvalidDecl();
+  return true;
+}
+
 /// \brief Instantiate the definition of a class from a given pattern.
 ///
 /// \param PointOfInstantiation The point of instantiation within the
@@ -1712,38 +1762,10 @@
 
   CXXRecordDecl *PatternDef
     = cast_or_null<CXXRecordDecl>(Pattern->getDefinition());
-  if (!PatternDef || PatternDef->isBeingDefined()) {
-    if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
-      // Say nothing
-    } else if (PatternDef) {
-      assert(PatternDef->isBeingDefined());
-      Diag(PointOfInstantiation,
-           diag::err_template_instantiate_within_definition)
-        << (TSK != TSK_ImplicitInstantiation)
-        << Context.getTypeDeclType(Instantiation);
-      // Not much point in noting the template declaration here, since
-      // we're lexically inside it.
-      Instantiation->setInvalidDecl();
-    } else if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
-      Diag(PointOfInstantiation,
-           diag::err_implicit_instantiate_member_undefined)
-        << Context.getTypeDeclType(Instantiation);
-      Diag(Pattern->getLocation(), diag::note_member_of_template_here);
-    } else {
-      Diag(PointOfInstantiation, diag::err_template_instantiate_undefined)
-        << (TSK != TSK_ImplicitInstantiation)
-        << Context.getTypeDeclType(Instantiation);
-      Diag(Pattern->getLocation(), diag::note_template_decl_here);
-    }
-
-    // In general, Instantiation isn't marked invalid to get more than one
-    // error for multiple undefined instantiations. But the code that does
-    // explicit declaration -> explicit definition conversion can't handle
-    // invalid declarations, so mark as invalid in that case.
-    if (TSK == TSK_ExplicitInstantiationDeclaration)
-       Instantiation->setInvalidDecl();
+  if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
+                                Instantiation->getInstantiatedFromMemberClass(),
+                                     Pattern, PatternDef, TSK, Complain))
     return true;
-  }
   Pattern = PatternDef;
 
   // \brief Record the point of instantiation.
@@ -1911,6 +1933,63 @@
   return Invalid;
 }
 
+/// \brief Instantiate the definition of an enum from a given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+///        source code.
+/// \param Instantiation is the declaration whose definition is being
+///        instantiated. This will be a member enumeration of a class
+///        temploid specialization, or a local enumeration within a
+///        function temploid specialization.
+/// \param Pattern The templated declaration from which the instantiation
+///        occurs.
+/// \param TemplateArgs The template arguments to be substituted into
+///        the pattern.
+/// \param TSK The kind of implicit or explicit instantiation to perform.
+///
+/// \return \c true if an error occurred, \c false otherwise.
+bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
+                           EnumDecl *Instantiation, EnumDecl *Pattern,
+                           const MultiLevelTemplateArgumentList &TemplateArgs,
+                           TemplateSpecializationKind TSK) {
+  EnumDecl *PatternDef = Pattern->getDefinition();
+  if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation,
+                                 Instantiation->getInstantiatedFromMemberEnum(),
+                                     Pattern, PatternDef, TSK,/*Complain*/true))
+    return true;
+  Pattern = PatternDef;
+
+  // Record the point of instantiation.
+  if (MemberSpecializationInfo *MSInfo
+        = Instantiation->getMemberSpecializationInfo()) {
+    MSInfo->setTemplateSpecializationKind(TSK);
+    MSInfo->setPointOfInstantiation(PointOfInstantiation);
+  }
+
+  InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
+  if (Inst)
+    return true;
+
+  // Enter the scope of this instantiation. We don't use
+  // PushDeclContext because we don't have a scope.
+  ContextRAII SavedContext(*this, Instantiation);
+  EnterExpressionEvaluationContext EvalContext(*this,
+                                               Sema::PotentiallyEvaluated);
+
+  LocalInstantiationScope Scope(*this, /*MergeWithParentScope*/true);
+
+  // Pull attributes from the pattern onto the instantiation.
+  InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
+
+  TemplateDeclInstantiator Instantiator(*this, Instantiation, TemplateArgs);
+  Instantiator.InstantiateEnumDefinition(Instantiation, Pattern);
+
+  // Exit the scope of this instantiation.
+  SavedContext.pop();
+
+  return Instantiation->isInvalidDecl();
+}
+
 namespace {
   /// \brief A partial specialization whose template arguments have matched
   /// a given template-id.
@@ -2231,6 +2310,36 @@
       if (Pattern)
         InstantiateClassMembers(PointOfInstantiation, Pattern, TemplateArgs, 
                                 TSK);
+    } else if (EnumDecl *Enum = dyn_cast<EnumDecl>(*D)) {
+      MemberSpecializationInfo *MSInfo = Enum->getMemberSpecializationInfo();
+      assert(MSInfo && "No member specialization information?");
+
+      if (MSInfo->getTemplateSpecializationKind()
+            == TSK_ExplicitSpecialization)
+        continue;
+
+      if (CheckSpecializationInstantiationRedecl(
+            PointOfInstantiation, TSK, Enum,
+            MSInfo->getTemplateSpecializationKind(),
+            MSInfo->getPointOfInstantiation(), SuppressNew) ||
+          SuppressNew)
+        continue;
+
+      if (Enum->getDefinition())
+        continue;
+
+      EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum();
+      assert(Pattern && "Missing instantiated-from-template information");
+
+      if (TSK == TSK_ExplicitInstantiationDefinition) {
+        if (!Pattern->getDefinition())
+          continue;
+
+        InstantiateEnum(PointOfInstantiation, Enum, Pattern, TemplateArgs, TSK);
+      } else {
+        MSInfo->setTemplateSpecializationKind(TSK);
+        MSInfo->setPointOfInstantiation(PointOfInstantiation);
+      }
     }
   }
 }

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Mar 14 18:13:10 2012
@@ -563,20 +563,18 @@
                                     /*PrevDecl=*/0, D->isScoped(),
                                     D->isScopedUsingClassTag(), D->isFixed());
   if (D->isFixed()) {
-    if (TypeSourceInfo* TI = D->getIntegerTypeSourceInfo()) {
+    if (TypeSourceInfo *TI = D->getIntegerTypeSourceInfo()) {
       // If we have type source information for the underlying type, it means it
       // has been explicitly set by the user. Perform substitution on it before
       // moving on.
       SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
-      Enum->setIntegerTypeSourceInfo(SemaRef.SubstType(TI,
-                                                       TemplateArgs,
-                                                       UnderlyingLoc,
-                                                       DeclarationName()));
-
-      if (!Enum->getIntegerTypeSourceInfo())
+      TypeSourceInfo *NewTI = SemaRef.SubstType(TI, TemplateArgs, UnderlyingLoc,
+                                                DeclarationName());
+      if (!NewTI || SemaRef.CheckEnumUnderlyingType(NewTI))
         Enum->setIntegerType(SemaRef.Context.IntTy);
-    }
-    else {
+      else
+        Enum->setIntegerTypeSourceInfo(NewTI);
+    } else {
       assert(!D->getIntegerType()->isDependentType()
              && "Dependent type without type source info");
       Enum->setIntegerType(D->getIntegerType());
@@ -585,20 +583,38 @@
 
   SemaRef.InstantiateAttrs(TemplateArgs, D, Enum);
 
-  Enum->setInstantiationOfMemberEnum(D);
+  Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation);
   Enum->setAccess(D->getAccess());
   if (SubstQualifier(D, Enum)) return 0;
   Owner->addDecl(Enum);
-  Enum->startDefinition();
+
+  // FIXME: If this is a redeclaration:
+  // CheckEnumRedeclaration(Enum->getLocation(), Enum->isScoped(),
+  //                        Enum->getIntegerType(), Prev);
 
   if (D->getDeclContext()->isFunctionOrMethod())
     SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Enum);
 
+  // C++11 [temp.inst]p1: The implicit instantiation of a class template
+  // specialization causes the implicit instantiation of the declarations, but
+  // 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())
+    InstantiateEnumDefinition(Enum, D);
+
+  return Enum;
+}
+
+void TemplateDeclInstantiator::InstantiateEnumDefinition(
+    EnumDecl *Enum, EnumDecl *Pattern) {
+  Enum->startDefinition();
+
   SmallVector<Decl*, 4> Enumerators;
 
   EnumConstantDecl *LastEnumConst = 0;
-  for (EnumDecl::enumerator_iterator EC = D->enumerator_begin(),
-         ECEnd = D->enumerator_end();
+  for (EnumDecl::enumerator_iterator EC = Pattern->enumerator_begin(),
+         ECEnd = Pattern->enumerator_end();
        EC != ECEnd; ++EC) {
     // The specified value for the enumerator.
     ExprResult Value = SemaRef.Owned((Expr *)0);
@@ -636,7 +652,8 @@
       Enumerators.push_back(EnumConst);
       LastEnumConst = EnumConst;
 
-      if (D->getDeclContext()->isFunctionOrMethod()) {
+      if (Pattern->getDeclContext()->isFunctionOrMethod() &&
+          !Enum->isScoped()) {
         // If the enumeration is within a function or method, record the enum
         // constant as a local.
         SemaRef.CurrentInstantiationScope->InstantiatedLocal(*EC, EnumConst);
@@ -644,14 +661,11 @@
     }
   }
 
-  // FIXME: Fixup LBraceLoc and RBraceLoc
-  // FIXME: Empty Scope and AttributeList (required to handle attribute packed).
-  SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), SourceLocation(),
-                        Enum,
+  // FIXME: Fixup LBraceLoc
+  SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
+                        Enum->getRBraceLoc(), Enum,
                         Enumerators.data(), Enumerators.size(),
                         0, 0);
-
-  return Enum;
 }
 
 Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Mar 14 18:13:10 2012
@@ -453,7 +453,13 @@
   ED->IsScoped = Record[Idx++];
   ED->IsScopedUsingClassTag = Record[Idx++];
   ED->IsFixed = Record[Idx++];
-  ED->setInstantiationOfMemberEnum(ReadDeclAs<EnumDecl>(Record, Idx));
+
+  if (EnumDecl *InstED = ReadDeclAs<EnumDecl>(Record, Idx)) {
+    TemplateSpecializationKind TSK = (TemplateSpecializationKind)Record[Idx++];
+    SourceLocation POI = ReadSourceLocation(Record, Idx);
+    ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK);
+    ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI);
+  }
 }
 
 void ASTDeclReader::VisitRecordDecl(RecordDecl *RD) {

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Mar 14 18:13:10 2012
@@ -230,7 +230,13 @@
   Record.push_back(D->isScoped());
   Record.push_back(D->isScopedUsingClassTag());
   Record.push_back(D->isFixed());
-  Writer.AddDeclRef(D->getInstantiatedFromMemberEnum(), Record);
+  if (MemberSpecializationInfo *MemberInfo = D->getMemberSpecializationInfo()) {
+    Writer.AddDeclRef(MemberInfo->getInstantiatedFrom(), Record);
+    Record.push_back(MemberInfo->getTemplateSpecializationKind());
+    Writer.AddSourceLocation(MemberInfo->getPointOfInstantiation(), Record);
+  } else {
+    Writer.AddDeclRef(0, Record);
+  }
 
   if (!D->hasAttrs() &&
       !D->isImplicit() &&

Modified: cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p8.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p8.cpp?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p8.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.explicit/p8.cpp Wed Mar 14 18:13:10 2012
@@ -1,16 +1,15 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
 
 template<typename T>
 struct X0 {
   struct MemberClass;
-  
+
   T* f0(T* ptr);
-  
+
   static T* static_member;
 };
 
-template class X0<int>; // okay
-template class X0<int(int)>; // okay; nothing gets instantiated.
+template class X0<int(int)>; // ok; nothing gets instantiated.
 
 template<typename T>
 struct X0<T>::MemberClass {
@@ -25,3 +24,17 @@
 template<typename T>
 T* X0<T>::static_member = 0;
 
+template class X0<int>; // ok
+
+
+template<typename T>
+struct X1 {
+  enum class E {
+    e = T::error // expected-error 2{{no members}}
+  };
+};
+template struct X1<int>; // expected-note {{here}}
+
+extern template struct X1<char>; // ok
+
+template struct X1<char>; // expected-note {{here}}

Added: cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp?rev=152750&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.spec/temp.inst/p1.cpp Wed Mar 14 18:13:10 2012
@@ -0,0 +1,104 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+// The implicit specialization of a class template specialuzation causes the
+// implicit instantiation of the declarations, but not the definitions or
+// default arguments, of:
+
+// FIXME: Many omitted cases
+
+// - scoped member enumerations
+namespace ScopedEnum {
+  template<typename T> struct ScopedEnum1 {
+    enum class E {
+      e = T::error // expected-error {{'double' cannot be used prior to '::'}}
+    };
+  };
+  ScopedEnum1<int> se1; // ok
+
+  template<typename T> struct ScopedEnum2 {
+    enum class E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
+      e = 0
+    };
+  };
+  ScopedEnum2<void*> se2; // expected-note {{here}}
+
+  template<typename T> struct UnscopedEnum3 {
+    enum class E : T {
+      e = 4
+    };
+    int arr[(int)E::e];
+  };
+  UnscopedEnum3<int> ue3; // ok
+
+  ScopedEnum1<double>::E e1; // ok
+  ScopedEnum1<double>::E e2 = decltype(e2)::e; // expected-note {{in instantiation of enumeration 'ScopedEnum::ScopedEnum1<double>::E' requested here}}
+
+  // The behavior for enums defined within function templates is not clearly
+  // specified by the standard. We follow the rules for enums defined within
+  // class templates.
+  template<typename T>
+  int f() {
+    enum class E {
+      e = T::error
+    };
+    return (int)E();
+  }
+  int test1 = f<int>();
+
+  template<typename T>
+  int g() {
+    enum class E {
+      e = T::error // expected-error {{has no members}}
+    };
+    return E::e; // expected-note {{here}}
+  }
+  int test2 = g<int>(); // expected-note {{here}}
+}
+
+// And it cases the implicit instantiations of the definitions of:
+
+// - unscoped member enumerations
+namespace UnscopedEnum {
+  template<typename T> struct UnscopedEnum1 {
+    enum E {
+      e = T::error // expected-error {{'int' cannot be used prior to '::'}}
+    };
+  };
+  UnscopedEnum1<int> ue1; // expected-note {{here}}
+
+  template<typename T> struct UnscopedEnum2 {
+    enum E : T { // expected-error {{non-integral type 'void *' is an invalid underlying type}}
+      e = 0
+    };
+  };
+  UnscopedEnum2<void*> ue2; // expected-note {{here}}
+
+  template<typename T> struct UnscopedEnum3 {
+    enum E : T {
+      e = 4
+    };
+    int arr[E::e];
+  };
+  UnscopedEnum3<int> ue3; // ok
+
+  template<typename T>
+  int f() {
+    enum E {
+      e = T::error // expected-error {{has no members}}
+    };
+    return (int)E();
+  }
+  int test1 = f<int>(); // expected-note {{here}}
+
+  template<typename T>
+  int g() {
+    enum E {
+      e = T::error // expected-error {{has no members}}
+    };
+    return E::e;
+  }
+  int test2 = g<int>(); // expected-note {{here}}
+}
+
+// FIXME:
+//- - member anonymous unions

Added: cfe/trunk/test/PCH/cxx11-enum-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx11-enum-template.cpp?rev=152750&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx11-enum-template.cpp (added)
+++ cfe/trunk/test/PCH/cxx11-enum-template.cpp Wed Mar 14 18:13:10 2012
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -pedantic-errors -std=c++11 -include-pch %t -verify %s
+
+#ifndef HEADER_INCLUDED
+
+#define HEADER_INCLUDED
+
+template<typename T> struct S {
+  enum class E {
+    e = T() // expected-error {{conversion from 'double' to 'int'}}
+  };
+};
+
+S<int> a;
+S<long>::E b;
+S<double>::E c;
+template struct S<char>;
+
+#else
+
+int k1 = (int)S<int>::E::e;
+int k2 = (int)decltype(b)::e;
+int k3 = (int)decltype(c)::e; // expected-note {{here}}
+int k4 = (int)S<char>::E::e;
+
+#endif

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=152750&r1=152749&r2=152750&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed Mar 14 18:13:10 2012
@@ -156,7 +156,8 @@
     </tr>
     <tr>
       <td>Forward declarations for enums</td>
-      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764</a></td>
+      <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf">N2764</a>
+      <br><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1206">DR1206</a></td>
       <td class="none" align="center">No</td>
     </tr>
     <tr>





More information about the cfe-commits mailing list