Skip to content

Commit 2e0a5fa

Browse files
committed
[clang] Remove written template args from implicit var tpl spec
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: 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 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. That said, setTemplateArgsAsWritten should be called only for variable template explicit specializations (it is already done inside Sema::ActOnVarTemplateSpecialization) 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 b980ff7 commit 2e0a5fa

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
@@ -11662,7 +11662,8 @@ class Sema final : public SemaBase {
1166211662
DeclResult CheckVarTemplateId(VarTemplateDecl *Template,
1166311663
SourceLocation TemplateLoc,
1166411664
SourceLocation TemplateNameLoc,
11665-
const TemplateArgumentListInfo &TemplateArgs);
11665+
const TemplateArgumentListInfo &TemplateArgs,
11666+
bool SetWrittenArgs);
1166611667

1166711668
/// Form a reference to the specialization of the given variable template
1166811669
/// corresponding to the specified argument list, or a null-but-valid result
@@ -14022,7 +14023,6 @@ class Sema final : public SemaBase {
1402214023
VarTemplateSpecializationDecl *BuildVarTemplateInstantiation(
1402314024
VarTemplateDecl *VarTemplate, VarDecl *FromVar,
1402414025
const TemplateArgumentList *PartialSpecArgs,
14025-
const TemplateArgumentListInfo &TemplateArgsInfo,
1402614026
SmallVectorImpl<TemplateArgument> &Converted,
1402714027
SourceLocation PointOfInstantiation,
1402814028
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)