diff options
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 72 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 89 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 171 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 54 |
4 files changed, 269 insertions, 117 deletions
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 1c414dda5d..5e6c27b15d 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, 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, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c1ef732a92..3363af324c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7738,6 +7738,50 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, } +/// \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 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, 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 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, 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) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 697ac0ecd4..c2ebbf4b55 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -469,6 +469,11 @@ void Sema::PrintInstantiationStack() { 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 @@ namespace clang { } } +/// 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 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, 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 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, 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 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, 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); + } } } } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index d7da736fe6..d0ba4db0b5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -563,20 +563,18 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { /*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 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { 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 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { 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 @@ Decl *TemplateDeclInstantiator::VisitEnumDecl(EnumDecl *D) { } } - // 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) { |