llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Andrey Ali Khan Bolshakov (bolshakov-a)
<details>
<summary>Changes</summary>
`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.
---
Full diff: https://github.com/llvm/llvm-project/pull/156329.diff
6 Files Affected:
- (modified) clang/include/clang/Sema/Sema.h (+2-2)
- (modified) clang/include/clang/Sema/Template.h (+1-2)
- (modified) clang/lib/Sema/SemaExprMember.cpp (+3-2)
- (modified) clang/lib/Sema/SemaTemplate.cpp (+10-6)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+18-13)
- (modified) clang/unittests/AST/DeclTest.cpp (+19)
``````````diff
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index c3fb57774c8dc..224095070cbe3 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -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);
/// Form a reference to the specialization of the given variable template
/// corresponding to the specified argument list, or a null-but-valid result
@@ -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,
diff --git a/clang/include/clang/Sema/Template.h
b/clang/include/clang/Sema/Template.h
index fe907078af275..115c19d4f1540 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -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);
diff --git a/clang/lib/Sema/SemaExprMember.cpp
b/clang/lib/Sema/SemaExprMember.cpp
index 4a31a139eaf4f..aedfc5e88b1c6 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -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();
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 3d8416ac7dc1b..3533871ad4dad 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -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.
@@ -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.
@@ -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();
@@ -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;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index ee1b520fa46e9..910f99d3eb160 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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) {
@@ -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);
@@ -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) {
@@ -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(
@@ -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();
diff --git a/clang/unittests/AST/DeclTest.cpp b/clang/unittests/AST/DeclTest.cpp
index 4c83ff9142e87..e76edbfe95b68 100644
--- a/clang/unittests/AST/DeclTest.cpp
+++ b/clang/unittests/AST/DeclTest.cpp
@@ -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);
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/156329
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits