Support for definitions of member enumerations of class templates outside the
class template's definition, and for explicit specializations of such enum members. llvm-svn: 153304
This commit is contained in:
		
							parent
							
								
									a754a03550
								
							
						
					
					
						commit
						7d137e3b98
					
				| 
						 | 
				
			
			@ -2862,6 +2862,16 @@ public:
 | 
			
		|||
  /// 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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -500,6 +500,8 @@ def err_explicit_instantiation_with_definition : Error<
 | 
			
		|||
    "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">;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2376,7 +2376,8 @@ def err_pointer_to_member_oper_value_classify: Error<
 | 
			
		|||
// 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 @@ def err_template_spec_decl_friend : Error<
 | 
			
		|||
  "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 @@ def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning<
 | 
			
		|||
    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<
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4132,6 +4132,26 @@ public:
 | 
			
		|||
  /// 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();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2674,6 +2674,24 @@ void EnumDecl::completeDefinition(QualType NewType,
 | 
			
		|||
  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());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2611,19 +2611,20 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc,
 | 
			
		|||
///         '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:
 | 
			
		||||
| 
						 | 
				
			
			@ -2649,6 +2650,13 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 | 
			
		|||
    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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 | 
			
		|||
    IsScopedUsingClassTag = false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Stop suppressing access control now we've parsed the enum name.
 | 
			
		||||
  SuppressAccess.done();
 | 
			
		||||
 | 
			
		||||
  TypeResult BaseType;
 | 
			
		||||
 | 
			
		||||
  // Parse the fixed underlying type.
 | 
			
		||||
| 
						 | 
				
			
			@ -2802,15 +2813,26 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 | 
			
		|||
  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);
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Skip the rest of this declarator, up until the comma or semicolon.
 | 
			
		||||
    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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -2827,8 +2849,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 | 
			
		|||
  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 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -968,12 +968,9 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
 | 
			
		|||
  // 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 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
 | 
			
		|||
 | 
			
		||||
      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,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -246,10 +246,14 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
 | 
			
		|||
  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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8283,10 +8283,19 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
 | 
			
		|||
              // 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())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1413,8 +1413,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
 | 
			
		|||
  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.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4699,8 +4699,11 @@ static bool CheckTemplateSpecializationScope(Sema &S,
 | 
			
		|||
    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 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 | 
			
		|||
      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 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 | 
			
		|||
                                                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 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
 | 
			
		|||
    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 @@ Sema::ActOnExplicitInstantiation(Scope *S,
 | 
			
		|||
    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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1843,7 +1843,20 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
 | 
			
		|||
        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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -600,7 +600,7 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) {
 | 
			
		|||
  // 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 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
 | 
			
		|||
    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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -13,3 +13,12 @@ struct Y {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
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}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue