diff options
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 125 |
1 files changed, 81 insertions, 44 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 54f1d87cc8..ed50722d2f 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -85,7 +85,7 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { return true; } -/// AdjustDeclForTemplates - If the given decl happens to be a template, reset +/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset /// the parameter D to reference the templated declaration and return a pointer /// to the template declaration. Otherwise, do nothing to D and return null. TemplateDecl *Sema::AdjustDeclIfTemplate(DeclTy *&D) @@ -164,27 +164,13 @@ void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam, Parm->setDefaultArgument(Default, DefaultLoc, false); } -/// ActOnNonTypeTemplateParameter - Called when a C++ non-type -/// template parameter (e.g., "int Size" in "template<int Size> -/// class Array") has been parsed. S is the current scope and D is -/// the parsed declarator. -Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, - unsigned Depth, - unsigned Position) { - QualType T = GetTypeForDeclarator(D, S); - - assert(S->isTemplateParamScope() && - "Non-type template parameter not in template parameter scope!"); - bool Invalid = false; - - IdentifierInfo *ParamName = D.getIdentifier(); - if (ParamName) { - NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); - if (PrevDecl && PrevDecl->isTemplateParameter()) - Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), - PrevDecl); - } - +/// \brief Check that the type of a non-type template parameter is +/// well-formed. +/// +/// \returns the (possibly-promoted) parameter type if valid; +/// otherwise, produces a diagnostic and returns a NULL type. +QualType +Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { // C++ [temp.param]p4: // // A non-type template-parameter shall have one of the following @@ -202,9 +188,8 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, T->isMemberPointerType() || // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. - T->isDependentType()) { - // Okay: The template parameter is well-formed. - } + T->isDependentType()) + return T; // C++ [temp.param]p8: // // A non-type template-parameter of type "array of T" or @@ -212,16 +197,42 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // T" or "pointer to function returning T", respectively. else if (T->isArrayType()) // FIXME: Keep the type prior to promotion? - T = Context.getArrayDecayedType(T); + return Context.getArrayDecayedType(T); else if (T->isFunctionType()) // FIXME: Keep the type prior to promotion? - T = Context.getPointerType(T); - else { - Diag(D.getIdentifierLoc(), diag::err_template_nontype_parm_bad_type) - << T; - return 0; + return Context.getPointerType(T); + + Diag(Loc, diag::err_template_nontype_parm_bad_type) + << T; + + return QualType(); +} + +/// ActOnNonTypeTemplateParameter - Called when a C++ non-type +/// template parameter (e.g., "int Size" in "template<int Size> +/// class Array") has been parsed. S is the current scope and D is +/// the parsed declarator. +Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position) { + QualType T = GetTypeForDeclarator(D, S); + + assert(S->isTemplateParamScope() && + "Non-type template parameter not in template parameter scope!"); + bool Invalid = false; + + IdentifierInfo *ParamName = D.getIdentifier(); + if (ParamName) { + NamedDecl *PrevDecl = LookupName(S, ParamName, LookupTagName); + if (PrevDecl && PrevDecl->isTemplateParameter()) + Invalid = Invalid || DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + PrevDecl); } + T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc()); + if (T.isNull()) + T = Context.IntTy; // Recover with an 'int' type. + NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create(Context, CurContext, D.getIdentifierLoc(), Depth, Position, ParamName, T); @@ -250,7 +261,7 @@ void Sema::ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParamD, // FIXME: Implement this check! Needs a recursive walk over the types. // Check the well-formedness of the default template argument. - if (CheckTemplateArgument(TemplateParm, Default)) { + if (CheckTemplateArgument(TemplateParm, TemplateParm->getType(), Default)) { TemplateParm->setInvalidDecl(); return; } @@ -774,6 +785,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!NTTP->hasDefaultArgument()) break; + // FIXME: Instantiate default argument ArgExpr = NTTP->getDefaultArgument(); ArgLoc = NTTP->getDefaultArgumentLoc(); } else { @@ -783,6 +795,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TempParm->hasDefaultArgument()) break; + // FIXME: Instantiate default argument ArgExpr = TempParm->getDefaultArgument(); ArgLoc = TempParm->getDefaultArgumentLoc(); } @@ -822,8 +835,30 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { // Check non-type template parameters. + + // Instantiate the type of the non-type template parameter with + // the template arguments we've seen thus far. + QualType NTTPType = NTTP->getType(); + if (NTTPType->isDependentType()) { + // Instantiate the type of the non-type template parameter. + NTTPType = InstantiateType(NTTPType, + &Converted[0], Converted.size(), + NTTP->getLocation(), + NTTP->getDeclName()); + // If that worked, check the non-type template parameter type + // for validity. + if (!NTTPType.isNull()) + NTTPType = CheckNonTypeTemplateParameterType(NTTPType, + NTTP->getLocation()); + + if (NTTPType.isNull()) { + Invalid = true; + break; + } + } + if (ArgExpr) { - if (CheckTemplateArgument(NTTP, ArgExpr, &Converted)) + if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted)) Invalid = true; continue; } @@ -1062,18 +1097,20 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { /// \brief Check a template argument against its corresponding /// non-type template parameter. /// -/// This routine implements the semantics of C++ [temp.arg.nontype]. -/// It returns true if an error occurred, and false otherwise. +/// This routine implements the semantics of C++ [temp.arg.nontype]. +/// It returns true if an error occurred, and false otherwise. \p +/// InstantiatedParamType is the type of the non-type template +/// parameter after it has been instantiated. /// /// If Converted is non-NULL and no errors occur, the value /// of this argument will be added to the end of the Converted vector. bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - Expr *&Arg, + QualType InstantiatedParamType, Expr *&Arg, llvm::SmallVectorImpl<TemplateArgument> *Converted) { // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. // FIXME: Add template argument to Converted! - if (Param->getType()->isDependentType() || Arg->isTypeDependent()) + if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) return false; // C++ [temp.arg.nontype]p5: @@ -1086,7 +1123,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- for a non-type template-parameter of integral or // enumeration type, integral promotions (4.5) and integral // conversions (4.7) are applied. - QualType ParamType = Param->getType(); + QualType ParamType = InstantiatedParamType; QualType ArgType = Arg->getType(); if (ParamType->isIntegralType() || ParamType->isEnumeralType()) { // C++ [temp.arg.nontype]p1: @@ -1130,7 +1167,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) - << Arg->getType() << Param->getType() << Arg->getSourceRange(); + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -1202,7 +1239,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) - << Arg->getType() << Param->getType() << Arg->getSourceRange(); + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -1248,7 +1285,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) - << Arg->getType() << Param->getType() << Arg->getSourceRange(); + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } @@ -1276,7 +1313,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (!Context.hasSameUnqualifiedType(ParamRefType->getPointeeType(), ArgType)) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_no_ref_bind) - << Param->getType() << Arg->getType() + << InstantiatedParamType << Arg->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; @@ -1289,7 +1326,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if ((ParamQuals | ArgQuals) != ParamQuals) { Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_ref_bind_ignores_quals) - << Param->getType() << Arg->getType() + << InstantiatedParamType << Arg->getType() << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; @@ -1317,7 +1354,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // We can't perform this conversion. Diag(Arg->getSourceRange().getBegin(), diag::err_template_arg_not_convertible) - << Arg->getType() << Param->getType() << Arg->getSourceRange(); + << Arg->getType() << InstantiatedParamType << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); return true; } |