diff options
Diffstat (limited to 'clang/lib/Sema/SemaTemplate.cpp')
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 338 |
1 files changed, 224 insertions, 114 deletions
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1184446796eb..f961244da072 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -1050,7 +1050,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } -bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { ConceptDecl *CD = @@ -1080,14 +1081,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, makeTemplateArgumentListInfo(*this, *TypeConstr); } return AttachTypeConstraint( - TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : - NestedNameSpecifierLoc(), + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), DeclarationNameInfo(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc), CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } +template<typename ArgumentLocAppender> +static ExprResult formImmediatelyDeclaredConstraint( + Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, SourceLocation LAngleLoc, + SourceLocation RAngleLoc, QualType ConstrainedType, + SourceLocation ParamNameLoc, ArgumentLocAppender Appender, + SourceLocation EllipsisLoc) { + + TemplateArgumentListInfo ConstraintArgs; + ConstraintArgs.addArgument( + S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), + /*NTTPType=*/QualType(), ParamNameLoc)); + + ConstraintArgs.setRAngleLoc(RAngleLoc); + ConstraintArgs.setLAngleLoc(LAngleLoc); + Appender(ConstraintArgs); + + // C++2a [temp.param]p4: + // [...] This constraint-expression E is called the immediately-declared + // constraint of T. [...] + CXXScopeSpec SS; + SS.Adopt(NS); + ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( + SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); + if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) + return ImmediatelyDeclaredConstraint; + + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // + // We have the following case: + // + // template<typename T> concept C1 = true; + // template<C1... T> struct s1; + // + // The constraint: (C1<T> && ...) + return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None); +} + /// Attach a type-constraint to a template parameter. /// \returns true if an error occured. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number @@ -1106,51 +1150,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, *TemplateArgs) : nullptr; QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); - TemplateArgumentListInfo ConstraintArgs; - ConstraintArgs.addArgument( - TemplateArgumentLoc( - TemplateArgument(ParamAsArgument), - TemplateArgumentLocInfo( - Context.getTrivialTypeSourceInfo(ParamAsArgument, - ConstrainedParameter->getLocation())))); - if (TemplateArgs) { - ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); - ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); - for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) - ConstraintArgs.addArgument(ArgLoc); - } - // C++2a [temp.param]p4: - // [...] This constraint-expression E is called the immediately-declared - // constraint of T. [...] - CXXScopeSpec SS; - SS.Adopt(NS); - ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, - /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, - NamedConcept, &ConstraintArgs); + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, NS, NameInfo, NamedConcept, + TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), + TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), + ParamAsArgument, ConstrainedParameter->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + if (TemplateArgs) + for (const auto &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; - if (ConstrainedParameter->isParameterPack()) { - // C++2a [temp.param]p4: - // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). - // - // We have the following case: - // - // template<typename T> concept C1 = true; - // template<C1... T> struct s1; - // - // The constraint: (C1<T> && ...) - ImmediatelyDeclaredConstraint = - BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), - ImmediatelyDeclaredConstraint.get(), BO_LAnd, - EllipsisLoc, /*RHS=*/nullptr, - /*RParenLoc=*/SourceLocation(), - /*NumExpansions=*/None).get(); - if (ImmediatelyDeclaredConstraint.isInvalid()) - return true; - } - ConstrainedParameter->setTypeConstraint(NS, NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, ArgsAsWritten, @@ -1158,6 +1172,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, return false; } +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, + SourceLocation EllipsisLoc) { + if (NTTP->getType() != TL.getType() || + TL.getAutoKeyword() != AutoTypeKeyword::Auto) { + Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + diag::err_unsupported_placeholder_constraint) + << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + return true; + } + // FIXME: Concepts: This should be the type of the placeholder, but this is + // unclear in the wording right now. + DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue, + NTTP->getLocation()); + if (!Ref) + return true; + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, EllipsisLoc); + if (ImmediatelyDeclaredConstraint.isInvalid() || + !ImmediatelyDeclaredConstraint.isUsable()) + return true; + + NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1319,6 +1365,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, TInfo); Param->setAccess(AS_public); + if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) + if (TL.isConstrained()) + if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) + Invalid = true; + if (Invalid) Param->setInvalidDecl(); @@ -2762,7 +2813,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, - bool &IsMemberSpecialization, bool &Invalid) { + bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) { IsMemberSpecialization = false; Invalid = false; @@ -2870,8 +2921,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_specialize_member_of_template) + << !Recovery << Range; Invalid = true; IsMemberSpecialization = false; return true; @@ -2892,9 +2944,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( else ExpectedTemplateLoc = DeclStartLoc; - Diag(DeclLoc, diag::err_template_spec_needs_header) - << Range - << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_header) + << Range + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); return false; }; @@ -2984,12 +3037,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << T - << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), - ParamLists[ParamIdx]->getRAngleLoc()) - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; return nullptr; } @@ -3025,7 +3079,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ExpectedTemplateParams && !TemplateParameterListsAreEqual(ParamLists[ParamIdx], ExpectedTemplateParams, - true, TPL_TemplateMatch)) + !SuppressDiagnostic, TPL_TemplateMatch)) Invalid = true; if (!Invalid && @@ -3037,9 +3091,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } - Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) - << T - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; continue; } @@ -3075,16 +3130,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( AllExplicitSpecHeaders = false; } - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamLists.size() - 2]->getRAngleLoc()); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[ParamLists.size() - 2]->getRAngleLoc()); // If there was a specialization somewhere, such that 'template<>' is // not required, and there were any 'template<>' headers, note where the // specialization occurred. - if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader && + !SuppressDiagnostic) Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); @@ -4044,7 +4101,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), Converted) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus2a || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -6530,7 +6587,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeductionArg = PE->getPattern(); if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - DeductionArg, ParamType, Depth) == DAR_Failed) { + DeductionArg, ParamType, Depth, + // We do not check constraints right now because the + // immediately-declared constraint of the auto type is also an + // associated constraint, and will be checked along with the other + // associated constraints after checking the template argument list. + /*IgnoreConstraints=*/true) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -7102,6 +7164,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // [temp.constr.order]. SmallVector<const Expr *, 3> ParamsAC, TemplateAC; Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; Template->getAssociatedConstraints(TemplateAC); bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, @@ -7872,13 +7939,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs( DeclResult Sema::ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, - const ParsedAttributesView &Attr, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(TUK != TUK_Reference && "References are not specializations"); - CXXScopeSpec &SS = TemplateId.SS; - // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 @@ -8048,7 +8113,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization()) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus2a || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -10012,24 +10077,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + TypeSourceInfo *TSI = nullptr; QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc); + TypenameLoc, QualifierLoc, II, IdLoc, &TSI, + /*DeducedTSTContext=*/true); if (T.isNull()) return true; - - TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - if (isa<DependentNameType>(T)) { - DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.setNameLoc(IdLoc); - } else { - ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); - } - return CreateParsedType(T, TSI); } @@ -10166,6 +10219,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return true; } +QualType +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext) { + QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc, + DeducedTSTContext); + if (T.isNull()) + return QualType(); + + *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = + (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.setNameLoc(IILoc); + } else { + ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc); + } + return T; +} + /// Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType @@ -10173,32 +10255,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc) { + SourceLocation IILoc, bool DeducedTSTContext) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - 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(QualifierLoc.getNestedNameSpecifier()->isDependent()); - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - &II); + DeclContext *Ctx = nullptr; + if (QualifierLoc) { + 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(QualifierLoc.getNestedNameSpecifier()->isDependent()); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); + } + + // 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 with only a warning. In any case we continue. + + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); } - // 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 with only a warning. In any case we continue. - - if (RequireCompleteDeclContext(SS, Ctx)) - return QualType(); - DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx, SS); + if (Ctx) + LookupQualifiedName(Result, Ctx, SS); + else + LookupName(Result, CurScope); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { @@ -10207,7 +10295,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // a more specific diagnostic. SourceRange CondRange; Expr *Cond = nullptr; - if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) { // If we have a condition, narrow it down to the specific failed // condition. if (Cond) { @@ -10223,12 +10311,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); } - Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) + Diag(CondRange.getBegin(), + diag::err_typename_nested_not_found_enable_if) << Ctx << CondRange; return QualType(); } - DiagID = diag::err_typename_nested_not_found; + DiagID = Ctx ? diag::err_typename_nested_not_found + : diag::err_unknown_typename; break; } @@ -10294,6 +10384,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // is a placeholder for a deduced class type [...]. if (getLangOpts().CPlusPlus17) { if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { + if (!DeducedTSTContext) { + QualType T(QualifierLoc + ? QualifierLoc.getNestedNameSpecifier()->getAsType() + : nullptr, 0); + if (!T.isNull()) + Diag(IILoc, diag::err_dependent_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T; + else + Diag(IILoc, diag::err_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)); + Diag(TD->getLocation(), diag::note_template_decl_here); + return QualType(); + } return Context.getElaboratedType( Keyword, QualifierLoc.getNestedNameSpecifier(), Context.getDeducedTemplateSpecializationType(TemplateName(TD), @@ -10301,12 +10404,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } } - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = Result.getFoundDecl(); break; case LookupResult::FoundOverloaded: - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = *Result.begin(); break; @@ -10318,9 +10423,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // type. Emit an appropriate diagnostic and return an error. SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); - Diag(IILoc, DiagID) << FullRange << Name << Ctx; + if (Ctx) + Diag(IILoc, DiagID) << FullRange << Name << Ctx; + else + Diag(IILoc, DiagID) << FullRange << Name; if (Referenced) - Diag(Referenced->getLocation(), diag::note_typename_refers_here) + Diag(Referenced->getLocation(), + Ctx ? diag::note_typename_member_refers_here + : diag::note_typename_refers_here) << Name; return QualType(); } |
