Skip to content

Commit 1cb47c1

Browse files
authored
[clang] Remove written template args from implicit var tpl spec (#156329)
`VarTemplateSpecializationDecl::getTemplateArgsAsWritten()` function should return `nullptr` in the case of implicit instantiation, as its `ClassTemplateSpecializationDecl` counterpart does, and not the arguments written in `DeclRefExpr` referencing the specialization in the first place. Otherwise, for such code: ```cpp template <typename> int VarTpl; template <typename T> void tplFn() { (void)VarTpl<T>; // (1) } void fn() { tplFn<char>(); } ``` Clang treats the `char` argument of the `VarTpl` specialization as if it were written in the line marked as (1), which is misleading and hardly makes sense. Moreover, "template args as written" are stored inside `ExplicitInfo` field of `VarTemplateSpecializationDecl`, but it is [documented](https://github.com/llvm/llvm-project/blob/13357e8a12c1a45364a0c4d3137b6d21ee6ac40c/clang/include/clang/AST/DeclTemplate.h#L2653) that it is not for implicit instantiations. Moreover, it is assumed in `TraverseVarTemplateSpecializationDecl` method of `RecursiveASTVisitor` that `getTemplateArgsAsWritten()` returns `nullptr` for implicit instantiations, as it is stated in the comment [there](https://github.com/llvm/llvm-project/blob/13357e8a12c1a45364a0c4d3137b6d21ee6ac40c/clang/include/clang/AST/RecursiveASTVisitor.h#L2196). That said, `setTemplateArgsAsWritten` should be called only for variable template explicit specializations (it is [already done inside `Sema::ActOnVarTemplateSpecialization`](https://github.com/llvm/llvm-project/blob/4c916273041ff5ed7b2af20bec787ffc42871c9f/clang/lib/Sema/SemaTemplate.cpp#L4459)) and explicit instantiations (hence `true` is passed to the new `SetWrittenArgs` parameter of `CheckVarTemplateId` function inside `Sema::ActOnExplicitInstantiation`, but not when handling expressions referencing a variable template specialization). `InstantiateVariableDefinition` function just passes the arguments from the corresponding declaration. I'm not sure about instantiating a class template containing a variable template explicit specialization and thus have tried to leave the logic of the first overload of `TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl` as it was.
1 parent f6e8b26 commit 1cb47c1

File tree

7 files changed

+56
-25
lines changed

7 files changed

+56
-25
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ C++ Specific Potentially Breaking Changes
8484
static_assert((b.*mp)() == 1); // newly rejected
8585
static_assert((c.*mp)() == 1); // accepted
8686
87+
- ``VarTemplateSpecializationDecl::getTemplateArgsAsWritten()`` method now
88+
returns ``nullptr`` for implicitly instantiated declarations.
89+
8790
ABI Changes in This Version
8891
---------------------------
8992

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11668,7 +11668,8 @@ class Sema final : public SemaBase {
1166811668
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
1166911669
SourceLocation TemplateLoc,
1167011670
SourceLocation TemplateNameLoc,
11671-
const TemplateArgumentListInfo &TemplateArgs);
11671+
const TemplateArgumentListInfo &TemplateArgs,
11672+
bool SetWrittenArgs);
1167211673

1167311674
/// Form a reference to the specialization of the given variable template
1167411675
/// corresponding to the specified argument list, or a null-but-valid result
@@ -14028,7 +14029,6 @@ class Sema final : public SemaBase {
1402814029
VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(
1402914030
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
1403014031
const TemplateArgumentList *PartialSpecArgs,
14031-
const TemplateArgumentListInfo &TemplateArgsInfo,
1403214032
SmallVectorImpl<TemplateArgument> &Converted,
1403314033
SourceLocation PointOfInstantiation,
1403414034
LateInstantiatedAttrVec *LateAttrs = nullptr,

clang/include/clang/Sema/Template.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -723,9 +723,8 @@ enum class TemplateSubstitutionKind : char {
723723
bool SubstQualifier(const TagDecl *OldDecl,
724724
TagDecl *NewDecl);
725725

726-
Decl *VisitVarTemplateSpecializationDecl(
726+
VarTemplateSpecializationDecl *VisitVarTemplateSpecializationDecl(
727727
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
728-
const TemplateArgumentListInfo &TemplateArgsInfo,
729728
ArrayRef<TemplateArgument> Converted,
730729
VarTemplateSpecializationDecl *PrevDecl = nullptr);
731730

clang/lib/Sema/SemaExprMember.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,8 +1126,9 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
11261126
return ExprError();
11271127
}
11281128

1129-
DeclResult VDecl = CheckVarTemplateId(VarTempl, TemplateKWLoc,
1130-
MemberNameInfo.getLoc(), *TemplateArgs);
1129+
DeclResult VDecl =
1130+
CheckVarTemplateId(VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(),
1131+
*TemplateArgs, /*SetWrittenArgs=*/false);
11311132
if (VDecl.isInvalid())
11321133
return ExprError();
11331134

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4542,7 +4542,8 @@ static bool IsLibstdcxxStdFormatKind(Preprocessor &PP, VarDecl *Var) {
45424542
DeclResult
45434543
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
45444544
SourceLocation TemplateNameLoc,
4545-
const TemplateArgumentListInfo &TemplateArgs) {
4545+
const TemplateArgumentListInfo &TemplateArgs,
4546+
bool SetWrittenArgs) {
45464547
assert(Template && "A variable template id without template?");
45474548

45484549
// Check that the template argument list is well-formed for this template.
@@ -4725,10 +4726,12 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
47254726
// in DoMarkVarDeclReferenced().
47264727
// FIXME: LateAttrs et al.?
47274728
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
4728-
Template, InstantiationPattern, PartialSpecArgs, TemplateArgs,
4729-
CTAI.CanonicalConverted, TemplateNameLoc /*, LateAttrs, StartingScope*/);
4729+
Template, InstantiationPattern, PartialSpecArgs, CTAI.CanonicalConverted,
4730+
TemplateNameLoc /*, LateAttrs, StartingScope*/);
47304731
if (!Decl)
47314732
return true;
4733+
if (SetWrittenArgs)
4734+
Decl->setTemplateArgsAsWritten(TemplateArgs);
47324735

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

47624765
DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(),
4763-
*TemplateArgs);
4766+
*TemplateArgs, /*SetWrittenArgs=*/false);
47644767
if (Decl.isInvalid())
47654768
return ExprError();
47664769

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

10710-
DeclResult Res = CheckVarTemplateId(PrevTemplate, TemplateLoc,
10711-
D.getIdentifierLoc(), TemplateArgs);
10713+
DeclResult Res =
10714+
CheckVarTemplateId(PrevTemplate, TemplateLoc, D.getIdentifierLoc(),
10715+
TemplateArgs, /*SetWrittenArgs=*/true);
1071210716
if (Res.isInvalid())
1071310717
return true;
1071410718

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4542,14 +4542,17 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
45424542
PrevDecl->getPointOfInstantiation(), Ignored))
45434543
return nullptr;
45444544

4545-
return VisitVarTemplateSpecializationDecl(InstVarTemplate, D,
4546-
VarTemplateArgsInfo,
4547-
CTAI.CanonicalConverted, PrevDecl);
4545+
if (VarTemplateSpecializationDecl *VTSD = VisitVarTemplateSpecializationDecl(
4546+
InstVarTemplate, D, CTAI.CanonicalConverted, PrevDecl)) {
4547+
VTSD->setTemplateArgsAsWritten(VarTemplateArgsInfo);
4548+
return VTSD;
4549+
}
4550+
return nullptr;
45484551
}
45494552

4550-
Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
4553+
VarTemplateSpecializationDecl *
4554+
TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
45514555
VarTemplateDecl *VarTemplate, VarDecl *D,
4552-
const TemplateArgumentListInfo &TemplateArgsInfo,
45534556
ArrayRef<TemplateArgument> Converted,
45544557
VarTemplateSpecializationDecl *PrevDecl) {
45554558

@@ -4570,7 +4573,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
45704573
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
45714574
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
45724575
VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
4573-
Var->setTemplateArgsAsWritten(TemplateArgsInfo);
45744576
if (!PrevDecl) {
45754577
void *InsertPos = nullptr;
45764578
VarTemplate->findSpecialization(Converted, InsertPos);
@@ -5880,7 +5882,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
58805882
VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
58815883
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
58825884
const TemplateArgumentList *PartialSpecArgs,
5883-
const TemplateArgumentListInfo &TemplateArgsInfo,
58845885
SmallVectorImpl<TemplateArgument> &Converted,
58855886
SourceLocation PointOfInstantiation, LateInstantiatedAttrVec *LateAttrs,
58865887
LocalInstantiationScope *StartingScope) {
@@ -5922,9 +5923,8 @@ VarTemplateSpecializationDecl *Sema::BuildVarTemplateInstantiation(
59225923

59235924
// TODO: Set LateAttrs and StartingScope ...
59245925

5925-
return cast_or_null<VarTemplateSpecializationDecl>(
5926-
Instantiator.VisitVarTemplateSpecializationDecl(
5927-
VarTemplate, FromVar, TemplateArgsInfo, Converted));
5926+
return Instantiator.VisitVarTemplateSpecializationDecl(VarTemplate, FromVar,
5927+
Converted);
59285928
}
59295929

59305930
VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl(
@@ -6340,10 +6340,15 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
63406340
TemplateArgInfo.addArgument(Arg);
63416341
}
63426342

6343-
Var = cast_or_null<VarDecl>(Instantiator.VisitVarTemplateSpecializationDecl(
6344-
VarSpec->getSpecializedTemplate(), Def, TemplateArgInfo,
6345-
VarSpec->getTemplateArgs().asArray(), VarSpec));
6343+
VarTemplateSpecializationDecl *VTSD =
6344+
Instantiator.VisitVarTemplateSpecializationDecl(
6345+
VarSpec->getSpecializedTemplate(), Def,
6346+
VarSpec->getTemplateArgs().asArray(), VarSpec);
6347+
Var = VTSD;
6348+
63466349
if (Var) {
6350+
VTSD->setTemplateArgsAsWritten(TemplateArgInfo);
6351+
63476352
llvm::PointerUnion<VarTemplateDecl *,
63486353
VarTemplatePartialSpecializationDecl *> PatternPtr =
63496354
VarSpec->getSpecializedTemplateOrPartial();

clang/unittests/AST/DeclTest.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,3 +586,22 @@ namespace x::y {
586586
ASSERT_NE(FD, nullptr);
587587
ASSERT_EQ(FD->getQualifiedNameAsString(), "x::y::Foo::Foo<T>");
588588
}
589+
590+
TEST(Decl, NoWrittenArgsInImplicitlyInstantiatedVarSpec) {
591+
const char *Code = R"cpp(
592+
template <typename>
593+
int VarTpl;
594+
595+
void fn() {
596+
(void)VarTpl<char>;
597+
}
598+
)cpp";
599+
600+
auto AST = tooling::buildASTFromCode(Code);
601+
ASTContext &Ctx = AST->getASTContext();
602+
603+
const auto *VTSD = selectFirst<VarTemplateSpecializationDecl>(
604+
"id", match(varDecl(isTemplateInstantiation()).bind("id"), Ctx));
605+
ASSERT_NE(VTSD, nullptr);
606+
EXPECT_EQ(VTSD->getTemplateArgsAsWritten(), nullptr);
607+
}

0 commit comments

Comments
 (0)