Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ C++ Specific Potentially Breaking Changes
static_assert((b.*mp)() == 1); // newly rejected
static_assert((c.*mp)() == 1); // accepted

- ``VarTemplateSpecializationDecl::getTemplateArgsAsWritten()`` method now
returns ``nullptr`` for implicitly instantiated declarations.

ABI Changes in This Version
---------------------------

Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -11662,7 +11662,8 @@ class Sema final : public SemaBase {
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
const TemplateArgumentListInfo &TemplateArgs);
const TemplateArgumentListInfo &TemplateArgs,
bool SetWrittenArgs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than adding a new bool parameter, I think we better move the responsibility of setting the written args entirely out of CheckVarTemplateId, which would make this more similar to CheckTypeTemplateId.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the args to the CheckVarTemplateId result may change some previous declaration stored in the ASTContext when CheckVarTemplateId returns it and not a new one.

I cannot find CheckTypeTemplateId in the project (typo?)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Err I meant CheckTemplateIdType, pretty unfortunate inconsistency in naming formulation.

Copy link
Contributor

@mizvekov mizvekov Sep 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, that's another inconsistency with how CheckTemplateIdType operates and is used.

This may need some though, I don't want to propose a large refactoring to support such a simple change, but the bool parameter does not feel right.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the difference is because CheckTemplateIdType returns template specialization type and not the specialization declaration.


/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
Expand Down Expand Up @@ -14022,7 +14023,6 @@ class Sema final : public SemaBase {
VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList *PartialSpecArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation,
LateInstantiatedAttrVec *LateAttrs = nullptr,
Expand Down
3 changes: 1 addition & 2 deletions clang/include/clang/Sema/Template.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,9 +723,8 @@ enum class TemplateSubstitutionKind : char {
bool SubstQualifier(const TagDecl *OldDecl,
TagDecl *NewDecl);

Decl *VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl = nullptr);

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1126,8 +1126,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
return ExprError();
}

DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
MemberNameInfo.getLoc(), *TemplateArgs);
DeclResult VDecl =
CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
*TemplateArgs, /*SetWrittenArgs=*/false);
if (VDecl.isInvalid())
return ExprError();

Expand Down
16 changes: 10 additions & 6 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4542,7 +4542,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
SourceLocation TemplateNameLoc,
const TemplateArgumentListInfo &TemplateArgs) {
const TemplateArgumentListInfo &TemplateArgs,
bool SetWrittenArgs) {
assert(Template && "A variable template id without template?");

// Check that the template argument list is well-formed for this template.
Expand Down Expand Up @@ -4725,10 +4726,12 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// in DoMarkVarDeclReferenced().
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, PartialSpecArgs, TemplateArgs,
CTAI.CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
Template, InstantiationPattern, PartialSpecArgs, CTAI.CanonicalConverted,
TemplateNameLoc /*, LateAttrs, StartingScope*/);
if (!Decl)
return true;
if (SetWrittenArgs)
Decl->setTemplateArgsAsWritten(TemplateArgs);

if (AmbiguousPartialSpec) {
// Partial ordering did not produce a clear winner. Complain.
Expand Down Expand Up @@ -4760,7 +4763,7 @@ ExprResult Sema::CheckVarTemplateId(
const TemplateArgumentListInfo *TemplateArgs) {

DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
*TemplateArgs);
*TemplateArgs, /*SetWrittenArgs=*/false);
if (Decl.isInvalid())
return ExprError();

Expand Down Expand Up @@ -10707,8 +10710,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);

DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
D.getIdentifierLoc(), TemplateArgs);
DeclResult Res =
CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
TemplateArgs, /*SetWrittenArgs=*/true);
if (Res.isInvalid())
return true;

Expand Down
31 changes: 18 additions & 13 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4542,14 +4542,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
PrevDecl->getPointOfInstantiation(), Ignored))
return nullptr;

return VisitVarTemplateSpecializationDecl(InstVarTemplate, D,
VarTemplateArgsInfo,
CTAI.CanonicalConverted, PrevDecl);
if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
return VTSD;
}
return nullptr;
}

Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *
TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateDecl *VarTemplate, VarDecl *D,
const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted,
VarTemplateSpecializationDecl *PrevDecl) {

Expand All @@ -4570,7 +4573,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
Var->setTemplateArgsAsWritten(TemplateArgsInfo);
if (!PrevDecl) {
void *InsertPos = nullptr;
VarTemplate->findSpecialization(Converted, InsertPos);
Expand Down Expand Up @@ -5880,7 +5882,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
const TemplateArgumentList *PartialSpecArgs,
const TemplateArgumentListInfo &TemplateArgsInfo,
SmallVectorImpl<TemplateArgument> &Converted,
SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
LocalInstantiationScope *StartingScope) {
Expand Down Expand Up @@ -5922,9 +5923,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(

// TODO: Set LateAttrs and StartingScope ...

return cast_or_null<VarTemplateSpecializationDecl>(
Instantiator.VisitVarTemplateSpecializationDecl(
VarTemplate, FromVar, TemplateArgsInfo, Converted));
return Instantiator.VisitVarTemplateSpecializationDecl(VarTemplate, FromVar,
Converted);
}

VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
Expand Down Expand Up @@ -6340,10 +6340,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
TemplateArgInfo.addArgument(Arg);
}

Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo,
VarSpec->getTemplateArgs().asArray(), VarSpec));
VarTemplateSpecializationDecl *VTSD =
Instantiator.VisitVarTemplateSpecializationDecl(
VarSpec->getSpecializedTemplate(), Def,
VarSpec->getTemplateArgs().asArray(), VarSpec);
Var = VTSD;

if (Var) {
VTSD->setTemplateArgsAsWritten(TemplateArgInfo);

llvm::PointerUnion<VarTemplateDecl *,
VarTemplatePartialSpecializationDecl *> PatternPtr =
VarSpec->getSpecializedTemplateOrPartial();
Expand Down
19 changes: 19 additions & 0 deletions clang/unittests/AST/DeclTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,22 @@ namespace x::y {
ASSERT_NE(FD, nullptr);
ASSERT_EQ(FD->getQualifiedNameAsString(), "x::y::Foo::Foo<T>");
}

TEST(Decl, NoWrittenArgsInImplicitlyInstantiatedVarSpec) {
const char *Code = R"cpp(
template <typename>
int VarTpl;

void fn() {
(void)VarTpl<char>;
}
)cpp";

auto AST = tooling::buildASTFromCode(Code);
ASTContext &Ctx = AST->getASTContext();

const auto *VTSD = selectFirst<VarTemplateSpecializationDecl>(
"id", match(varDecl(isTemplateInstantiation()).bind("id"), Ctx));
ASSERT_NE(VTSD, nullptr);
EXPECT_EQ(VTSD->getTemplateArgsAsWritten(), nullptr);
}