diff options
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 496 |
1 files changed, 362 insertions, 134 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 40ec4bcb..694b21c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -63,20 +63,40 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, NamedDecl *D) { } static void FilterAcceptableTemplateNames(ASTContext &C, LookupResult &R) { + // The set of class templates we've already seen. + llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); NamedDecl *Repl = isAcceptableTemplateName(C, Orig->getUnderlyingDecl()); if (!Repl) filter.erase(); - else if (Repl != Orig) + else if (Repl != Orig) { + + // C++ [temp.local]p3: + // A lookup that finds an injected-class-name (10.2) can result in an + // ambiguity in certain cases (for example, if it is found in more than + // one base class). If all of the injected-class-names that are found + // refer to specializations of the same class template, and if the name + // is followed by a template-argument-list, the reference refers to the + // class template itself and not a specialization thereof, and is not + // ambiguous. + // + // FIXME: Will we eventually have to do the same for alias templates? + if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) + if (!ClassTemplates.insert(ClassTmpl)) { + filter.erase(); + continue; + } + filter.replace(Repl); + } } filter.done(); } TemplateNameKind Sema::isTemplateName(Scope *S, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectTypePtr, bool EnteringContext, @@ -109,7 +129,7 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupOrdinaryName); R.suppressDiagnostics(); LookupTemplateName(R, S, SS, ObjectType, EnteringContext); - if (R.empty()) + if (R.empty() || R.isAmbiguous()) return TNK_Non_template; TemplateName Template; @@ -169,7 +189,7 @@ bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, } void Sema::LookupTemplateName(LookupResult &Found, - Scope *S, const CXXScopeSpec &SS, + Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext) { // Determine where to perform name lookup @@ -190,7 +210,7 @@ void Sema::LookupTemplateName(LookupResult &Found, isDependent = isDependentScopeSpecifier(SS); // The declaration context must be complete. - if (LookupCtx && RequireCompleteDeclContext(SS)) + if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) return; } @@ -227,14 +247,11 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupName(Found, S); } - // FIXME: Cope with ambiguous name-lookup results. - assert(!Found.isAmbiguous() && - "Cannot handle template name-lookup ambiguities"); - if (Found.empty() && !isDependent) { // If we did not find any names, attempt to correct any typos. DeclarationName Name = Found.getLookupName(); - if (CorrectTypo(Found, S, &SS, LookupCtx)) { + if (DeclarationName Corrected = CorrectTypo(Found, S, &SS, LookupCtx, + false, CTC_CXXCasts)) { FilterAcceptableTemplateNames(Context, Found); if (!Found.empty() && isa<TemplateDecl>(*Found.begin())) { if (LookupCtx) @@ -271,8 +288,7 @@ void Sema::LookupTemplateName(LookupResult &Found, LookupOrdinaryName); LookupName(FoundOuter, S); FilterAcceptableTemplateNames(Context, FoundOuter); - // FIXME: Handle ambiguities in this lookup better - + if (FoundOuter.empty()) { // - if the name is not found, the name found in the class of the // object expression is used, otherwise @@ -439,7 +455,9 @@ Sema::DeclPtrTy Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis, bool Invalid = false; if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, ParamNameLoc, + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(ParamNameLoc, PrevDecl); @@ -560,7 +578,9 @@ Sema::DeclPtrTy Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, IdentifierInfo *ParamName = D.getIdentifier(); if (ParamName) { - NamedDecl *PrevDecl = LookupSingleName(S, ParamName, LookupTagName); + NamedDecl *PrevDecl = LookupSingleName(S, ParamName, D.getIdentifierLoc(), + LookupOrdinaryName, + ForRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl); @@ -705,7 +725,7 @@ static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { Sema::DeclResult Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, - SourceLocation KWLoc, const CXXScopeSpec &SS, + SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, @@ -733,25 +753,27 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, LookupResult Previous(*this, Name, NameLoc, LookupOrdinaryName, ForRedeclaration); if (SS.isNotEmpty() && !SS.isInvalid()) { - if (RequireCompleteDeclContext(SS)) - return true; - SemanticContext = computeDeclContext(SS, true); if (!SemanticContext) { // FIXME: Produce a reasonable diagnostic here return true; } + if (RequireCompleteDeclContext(SS, SemanticContext)) + return true; + LookupQualifiedName(Previous, SemanticContext); } else { SemanticContext = CurContext; LookupName(Previous, S); } - assert(!Previous.isAmbiguous() && "Ambiguity in class template redecl?"); + if (Previous.isAmbiguous()) + return true; + NamedDecl *PrevDecl = 0; if (Previous.begin() != Previous.end()) - PrevDecl = *Previous.begin(); + PrevDecl = (*Previous.begin())->getUnderlyingDecl(); // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. @@ -779,22 +801,24 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // declared as a friend, and when the name of the friend class or // function is neither a qualified name nor a template-id, scopes outside // the innermost enclosing namespace scope are not considered. - DeclContext *OutermostContext = CurContext; - while (!OutermostContext->isFileContext()) - OutermostContext = OutermostContext->getLookupParent(); - - if (PrevDecl && - (OutermostContext->Equals(PrevDecl->getDeclContext()) || - OutermostContext->Encloses(PrevDecl->getDeclContext()))) { - SemanticContext = PrevDecl->getDeclContext(); - } else { - // Declarations in outer scopes don't matter. However, the outermost - // context we computed is the semantic context for our new - // declaration. - PrevDecl = PrevClassTemplate = 0; - SemanticContext = OutermostContext; + if (!SS.isSet()) { + DeclContext *OutermostContext = CurContext; + while (!OutermostContext->isFileContext()) + OutermostContext = OutermostContext->getLookupParent(); + + if (PrevDecl && + (OutermostContext->Equals(PrevDecl->getDeclContext()) || + OutermostContext->Encloses(PrevDecl->getDeclContext()))) { + SemanticContext = PrevDecl->getDeclContext(); + } else { + // Declarations in outer scopes don't matter. However, the outermost + // context we computed is the semantic context for our new + // declaration. + PrevDecl = PrevClassTemplate = 0; + SemanticContext = OutermostContext; + } } - + if (CurContext->isDependentContext()) { // If this is a dependent context, we don't want to link the friend // class template to the template in scope, because that would perform @@ -804,7 +828,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, } } else if (PrevDecl && !isDeclInScope(PrevDecl, SemanticContext, S)) PrevDecl = PrevClassTemplate = 0; - + if (PrevClassTemplate) { // Ensure that the template parameter lists are compatible. if (!TemplateParameterListsAreEqual(TemplateParams, @@ -861,9 +885,15 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, TPC_ClassTemplate)) Invalid = true; - // FIXME: If we had a scope specifier, we better have a previous template - // declaration! - + if (SS.isSet()) { + // If the name of the template was qualified, we must be defining the + // template out-of-line. + if (!SS.isInvalid() && !Invalid && !PrevClassTemplate && + !(TUK == TUK_Friend && CurContext->isDependentContext())) + Diag(NameLoc, diag::err_member_def_does_not_match) + << Name << SemanticContext << SS.getRange(); + } + CXXRecordDecl *NewClass = CXXRecordDecl::Create(Context, Kind, SemanticContext, NameLoc, Name, KWLoc, PrevClassTemplate? @@ -1206,6 +1236,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, /// /// \param NumParamLists the number of template parameter lists in ParamLists. /// +/// \param IsFriend Whether to apply the slightly different rules for +/// matching template parameters to scope specifiers in friend +/// declarations. +/// /// \param IsExplicitSpecialization will be set true if the entity being /// declared is an explicit specialization, false otherwise. /// @@ -1220,6 +1254,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization) { IsExplicitSpecialization = false; @@ -1285,6 +1320,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (Idx >= NumParamLists) { // We have a template-id without a corresponding template parameter // list. + + // ...which is fine if this is a friend declaration. + if (IsFriend) { + IsExplicitSpecialization = true; + break; + } + if (DependentTemplateId) { // FIXME: the location information here isn't great. Diag(SS.getRange().getBegin(), @@ -1302,27 +1344,25 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, // Check the template parameter list against its corresponding template-id. if (DependentTemplateId) { - TemplateDecl *Template - = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); - - if (ClassTemplateDecl *ClassTemplate - = dyn_cast<ClassTemplateDecl>(Template)) { - TemplateParameterList *ExpectedTemplateParams = 0; - // Is this template-id naming the primary template? - if (Context.hasSameType(TemplateId, - ClassTemplate->getInjectedClassNameSpecialization(Context))) - ExpectedTemplateParams = ClassTemplate->getTemplateParameters(); - // ... or a partial specialization? - else if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(TemplateId)) - ExpectedTemplateParams = PartialSpec->getTemplateParameters(); - - if (ExpectedTemplateParams) - TemplateParameterListsAreEqual(ParamLists[Idx], - ExpectedTemplateParams, - true, TPL_TemplateMatch); + TemplateParameterList *ExpectedTemplateParams = 0; + + // Are there cases in (e.g.) friends where this won't match? + if (const InjectedClassNameType *Injected + = TemplateId->getAs<InjectedClassNameType>()) { + CXXRecordDecl *Record = Injected->getDecl(); + if (ClassTemplatePartialSpecializationDecl *Partial = + dyn_cast<ClassTemplatePartialSpecializationDecl>(Record)) + ExpectedTemplateParams = Partial->getTemplateParameters(); + else + ExpectedTemplateParams = Record->getDescribedClassTemplate() + ->getTemplateParameters(); } + if (ExpectedTemplateParams) + TemplateParameterListsAreEqual(ParamLists[Idx], + ExpectedTemplateParams, + true, TPL_TemplateMatch); + CheckTemplateParameterList(ParamLists[Idx], 0, TPC_ClassTemplateMember); } else if (ParamLists[Idx]->size() > 0) Diag(ParamLists[Idx]->getTemplateLoc(), @@ -1388,6 +1428,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, "Converted template argument list is too short!"); QualType CanonType; + bool IsCurrentInstantiation = false; if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( @@ -1409,6 +1450,45 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // In the future, we need to teach getTemplateSpecializationType to only // build the canonical type and return that to us. CanonType = Context.getCanonicalType(CanonType); + + // This might work out to be a current instantiation, in which + // case the canonical type needs to be the InjectedClassNameType. + // + // TODO: in theory this could be a simple hashtable lookup; most + // changes to CurContext don't change the set of current + // instantiations. + if (isa<ClassTemplateDecl>(Template)) { + for (DeclContext *Ctx = CurContext; Ctx; Ctx = Ctx->getLookupParent()) { + // If we get out to a namespace, we're done. + if (Ctx->isFileContext()) break; + + // If this isn't a record, keep looking. + CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx); + if (!Record) continue; + + // Look for one of the two cases with InjectedClassNameTypes + // and check whether it's the same template. + if (!isa<ClassTemplatePartialSpecializationDecl>(Record) && + !Record->getDescribedClassTemplate()) + continue; + + // Fetch the injected class name type and check whether its + // injected type is equal to the type we just built. + QualType ICNT = Context.getTypeDeclType(Record); + QualType Injected = cast<InjectedClassNameType>(ICNT) + ->getInjectedSpecializationType(); + + if (CanonType != Injected->getCanonicalTypeInternal()) + continue; + + // If so, the canonical type of this TST is the injected + // class name type of the record we just found. + assert(ICNT.isCanonical()); + CanonType = ICNT; + IsCurrentInstantiation = true; + break; + } + } } else if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(Template)) { // Find the class template specialization declaration that @@ -1442,7 +1522,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType); + return Context.getTemplateSpecializationType(Name, TemplateArgs, CanonType, + IsCurrentInstantiation); } Action::TypeResult @@ -1545,14 +1626,14 @@ Sema::OwningExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, // We actually only call this from template instantiation. Sema::OwningExprResult -Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, +Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, DeclarationName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &TemplateArgs) { DeclContext *DC; if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext() || - RequireCompleteDeclContext(SS)) + RequireCompleteDeclContext(SS, DC)) return BuildDependentDeclRefExpr(SS, Name, NameLoc, &TemplateArgs); LookupResult R(*this, Name, NameLoc, LookupOrdinaryName); @@ -1586,7 +1667,7 @@ Sema::BuildQualifiedTemplateIdExpr(const CXXScopeSpec &SS, /// of the "template" keyword, and "apply" is the \p Name. Sema::TemplateTy Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, UnqualifiedId &Name, TypeTy *ObjectType, bool EnteringContext) { @@ -1663,11 +1744,25 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, const TemplateArgument &Arg = AL.getArgument(); // Check template type parameter. - if (Arg.getKind() != TemplateArgument::Type) { + switch(Arg.getKind()) { + case TemplateArgument::Type: // C++ [temp.arg.type]p1: // A template-argument for a template-parameter which is a // type shall be a type-id. + break; + case TemplateArgument::Template: { + // We have a template type parameter but the template argument + // is a template without any arguments. + SourceRange SR = AL.getSourceRange(); + TemplateName Name = Arg.getAsTemplate(); + Diag(SR.getBegin(), diag::err_template_missing_args) + << Name << SR; + if (TemplateDecl *Decl = Name.getAsTemplateDecl()) + Diag(Decl->getLocation(), diag::note_template_decl_here); + return true; + } + default: { // We have a template type parameter but the template argument // is not a type. SourceRange SR = AL.getSourceRange(); @@ -1676,6 +1771,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; } + } if (CheckTemplateArgument(Param, AL.getTypeSourceInfo())) return true; @@ -2317,14 +2413,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, DRE = dyn_cast<DeclRefExpr>(Arg); if (!DRE) { - if (S.Context.hasSameUnqualifiedType(ArgType, S.Context.OverloadTy)) { - S.Diag(Arg->getLocStart(), - diag::err_template_arg_unresolved_overloaded_function) - << ParamType << Arg->getSourceRange(); - } else { - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) - << Arg->getSourceRange(); - } + S.Diag(Arg->getLocStart(), diag::err_template_arg_not_decl_ref) + << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -2525,6 +2615,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // Create the template argument. Converted = TemplateArgument(Entity->getCanonicalDecl()); + S.MarkDeclarationReferenced(Arg->getLocStart(), Entity); return false; } @@ -2797,16 +2888,19 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, ParamType->getAs<MemberPointerType>()->getPointeeType() ->isFunctionType())) { - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, ParamType, + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + if (!ParamType->isMemberPointerType()) return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, @@ -2851,17 +2945,20 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, assert(ParamRefType->getPointeeType()->isObjectType() && "Only object references allowed here"); - if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, - ParamRefType->getPointeeType(), - true, - FoundResult)) { - if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) - return true; + if (Arg->getType() == Context.OverloadTy) { + if (FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(Arg, + ParamRefType->getPointeeType(), + true, + FoundResult)) { + if (DiagnoseUseOfDecl(Fn, Arg->getSourceRange().getBegin())) + return true; - Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); - ArgType = Arg->getType(); + Arg = FixOverloadedFunctionReference(Arg, FoundResult, Fn); + ArgType = Arg->getType(); + } else + return true; } - + return CheckTemplateArgumentAddressOfObjectOrFunction(*this, Param, ParamType, Arg, Converted); @@ -2964,9 +3061,21 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, return ExprError(); RefExpr = CreateBuiltinUnaryOp(Loc, UnaryOperator::AddrOf, move(RefExpr)); + + // We might need to perform a trailing qualification conversion, since + // the element type on the parameter could be more qualified than the + // element type in the expression we constructed. + if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), + ParamType.getUnqualifiedType())) { + Expr *RefE = RefExpr.takeAs<Expr>(); + ImpCastExprToType(RefE, ParamType.getUnqualifiedType(), + CastExpr::CK_NoOp); + RefExpr = Owned(RefE); + } + assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), - ParamType)); + ParamType.getUnqualifiedType())); return move(RefExpr); } } @@ -3467,7 +3576,7 @@ Sema::DeclResult Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, TemplateTy TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, @@ -3500,6 +3609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization); if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -3683,6 +3793,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Create a new class template partial specialization declaration node. ClassTemplatePartialSpecializationDecl *PrevPartial = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl); + unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber() + : ClassTemplate->getPartialSpecializations().size(); ClassTemplatePartialSpecializationDecl *Partial = ClassTemplatePartialSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), @@ -3692,7 +3804,8 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Converted, TemplateArgs, CanonType, - PrevPartial); + PrevPartial, + SequenceNumber); SetNestedNameSpecifier(Partial, SS); if (PrevPartial) { @@ -4032,7 +4145,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // instantiation has no effect. // // In C++98/03 mode, we only give an extension warning here, because it - // is not not harmful to try to explicitly instantiate something that + // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. if (!getLangOptions().CPlusPlus0x) { Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) @@ -4068,6 +4181,42 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, return false; } +/// \brief Perform semantic analysis for the given dependent function +/// template specialization. The only possible way to get a dependent +/// function template specialization is with a friend declaration, +/// like so: +/// +/// template <class T> void foo(T); +/// template <class T> class A { +/// friend void foo<>(T); +/// }; +/// +/// There really isn't any useful analysis we can do here, so we +/// just store the information. +bool +Sema::CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, + const TemplateArgumentListInfo &ExplicitTemplateArgs, + LookupResult &Previous) { + // Remove anything from Previous that isn't a function template in + // the correct context. + DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext(); + LookupResult::Filter F = Previous.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next()->getUnderlyingDecl(); + if (!isa<FunctionTemplateDecl>(D) || + !FDLookupContext->Equals(D->getDeclContext()->getLookupContext())) + F.erase(); + } + F.done(); + + // Should this be diagnosed here? + if (Previous.empty()) return true; + + FD->setDependentTemplateSpecialization(Context, Previous.asUnresolvedSet(), + ExplicitTemplateArgs); + return false; +} + /// \brief Perform semantic analysis for the given function template /// specialization. /// @@ -4153,6 +4302,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + Specialization->setLocation(FD->getLocation()); // FIXME: Check if the prior specialization has a point of instantiation. // If so, we have run afoul of . @@ -4227,7 +4377,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); - + // Try to find the member we are instantiating. NamedDecl *Instantiation = 0; NamedDecl *InstantiatedFrom = 0; @@ -4273,6 +4423,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // this mismatch later. return false; } + + // If this is a friend, just bail out here before we start turning + // things into explicit specializations. + if (Member->getFriendObjectKind() != Decl::FOK_None) { + // Preserve instantiation information. + if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) { + cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction( + cast<CXXMethodDecl>(InstantiatedFrom), + cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind()); + } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) { + cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass( + cast<CXXRecordDecl>(InstantiatedFrom), + cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind()); + } + + Previous.clear(); + Previous.addDecl(Instantiation); + return false; + } // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { @@ -4612,7 +4781,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, - const CXXScopeSpec &SS, + CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr) { @@ -5001,9 +5170,30 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } assert(Keyword != ETK_None && "Invalid tag kind!"); + if (TUK == TUK_Declaration || TUK == TUK_Definition) { + Diag(NameLoc, diag::err_dependent_tag_decl) + << (TUK == TUK_Definition) << TagDecl::getTagKindForTypeSpec(TagSpec) + << SS.getRange(); + return true; + } + return Context.getDependentNameType(Keyword, NNS, Name).getAsOpaquePtr(); } +static void FillTypeLoc(DependentNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + +static void FillTypeLoc(QualifiedNameTypeLoc TL, + SourceLocation TypenameLoc, + SourceRange QualifierRange) { + // FIXME: typename, qualifier range + TL.setNameLoc(TypenameLoc); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { @@ -5012,10 +5202,23 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, if (!NNS) return true; - QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc)); + QualType T = CheckTypenameType(ETK_Typename, NNS, II, + SourceRange(TypenameLoc, IdLoc)); if (T.isNull()) return true; - return T.getAsOpaquePtr(); + + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } else { + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + } + + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } Sema::TypeResult @@ -5034,48 +5237,49 @@ Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, // track of the nested-name-specifier. // FIXME: Note that the QualifiedNameType had the "typename" keyword! - return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr(); + + T = Context.getQualifiedNameType(NNS, T); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + QualifiedNameTypeLoc TL = cast<QualifiedNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } - return Context.getDependentNameType(ETK_Typename, NNS, TemplateId) - .getAsOpaquePtr(); + T = Context.getDependentNameType(ETK_Typename, NNS, TemplateId); + TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); + DependentNameTypeLoc TL = cast<DependentNameTypeLoc>(TSI->getTypeLoc()); + // FIXME: fill inner type loc + FillTypeLoc(TL, TypenameLoc, SS.getRange()); + return CreateLocInfoType(T, TSI).getAsOpaquePtr(); } /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo &II, SourceRange Range) { - CXXRecordDecl *CurrentInstantiation = 0; - if (NNS->isDependent()) { - CurrentInstantiation = getCurrentInstantiationOf(NNS); - - // If the nested-name-specifier does not refer to the current - // instantiation, then build a typename type. - if (!CurrentInstantiation) - return Context.getDependentNameType(ETK_Typename, NNS, &II); - - // The nested-name-specifier refers to the current instantiation, so the - // "typename" keyword itself is superfluous. In C++03, the program is - // actually ill-formed. However, DR 382 (in C++0x CD1) allows such - // extraneous "typename" keywords, and we retroactively apply this DR to - // C++03 code. + CXXScopeSpec SS; + SS.setScopeRep(NNS); + SS.setRange(Range); + + DeclContext *Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(NNS->isDependent()); + return Context.getDependentNameType(Keyword, NNS, &II); } - DeclContext *Ctx = 0; + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code. In any case we continue. - if (CurrentInstantiation) - Ctx = CurrentInstantiation; - else { - CXXScopeSpec SS; - SS.setScopeRep(NNS); - SS.setRange(Range); - if (RequireCompleteDeclContext(SS)) - return QualType(); - - Ctx = computeDeclContext(SS); - } - assert(Ctx && "No declaration context?"); + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); DeclarationName Name(&II); LookupResult Result(*this, Name, Range.getEnd(), LookupOrdinaryName); @@ -5089,7 +5293,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(ETK_Typename, NNS, &II); + return Context.getDependentNameType(Keyword, NNS, &II); case LookupResult::Found: if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getFoundDecl())) { @@ -5133,6 +5337,8 @@ namespace { DeclarationName Entity; public: + typedef TreeTransform<CurrentInstantiationRebuilder> inherited; + CurrentInstantiationRebuilder(Sema &SemaRef, SourceLocation Loc, DeclarationName Entity) @@ -5168,7 +5374,7 @@ namespace { /// FIXME: This is completely unsafe; we will need to actually clone the /// expressions. Sema::OwningExprResult TransformExpr(Expr *E) { - return getSema().Owned(E); + return getSema().Owned(E->Retain()); } /// \brief Transforms a typename type by determining whether the type now @@ -5256,15 +5462,30 @@ CurrentInstantiationRebuilder::TransformDependentNameType(TypeLocBuilder &TLB, /// in X<T> and returning a QualifiedNameType whose canonical type is the same /// as the canonical type of T*, allowing the return types of the out-of-line /// definition and the declaration to match. -QualType Sema::RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc, - DeclarationName Name) { - if (T.isNull() || !T->isDependentType()) +TypeSourceInfo *Sema::RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, + SourceLocation Loc, + DeclarationName Name) { + if (!T || !T->getType()->isDependentType()) return T; CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name); return Rebuilder.TransformType(T); } +bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { + if (SS.isInvalid()) return true; + + NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier*>(SS.getScopeRep()); + CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), + DeclarationName()); + NestedNameSpecifier *Rebuilt = + Rebuilder.TransformNestedNameSpecifier(NNS, SS.getRange()); + if (!Rebuilt) return true; + + SS.setScopeRep(Rebuilt); + return false; +} + /// \brief Produces a formatted string that describes the binding of /// template parameters to template arguments. std::string @@ -5344,8 +5565,15 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } case TemplateArgument::Expression: { - assert(false && "No expressions in deduced template arguments!"); - Result += "<expression>"; + // FIXME: This is non-optimal, since we're regurgitating the + // expression we were given. + std::string Str; + { + llvm::raw_string_ostream OS(Str); + Args[I].getAsExpr()->printPretty(OS, Context, 0, + Context.PrintingPolicy); + } + Result += Str; break; } |