Skip to content

Commit 6c5170c

Browse files
committed
improve template argument parsing
1 parent edc9af3 commit 6c5170c

8 files changed

+150
-50
lines changed

source/AST/ASTVisitor.cpp

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -359,12 +359,12 @@ buildTemplateParam(
359359
return info;
360360
}
361361

362-
template<typename R>
362+
template<typename Range>
363363
void
364364
ASTVisitor::
365365
buildTemplateArgs(
366-
TemplateInfo& I,
367-
R&& args)
366+
std::vector<TArg>& result,
367+
Range&& range)
368368
{
369369
// TypePrinter generates an internal placeholder name (e.g. type-parameter-0-0)
370370
// for template type parameters used as arguments. it also cannonicalizes
@@ -376,12 +376,12 @@ buildTemplateArgs(
376376
// FIXME: constant folding behavior should be consistent with that of other
377377
// constructs, e.g. noexcept specifiers & explicit specifiers
378378
const auto& policy = astContext_->getPrintingPolicy();
379-
for(const TemplateArgument& arg : args)
379+
for(const TemplateArgument& arg : range)
380380
{
381381
std::string arg_str;
382382
llvm::raw_string_ostream stream(arg_str);
383383
arg.print(policy, stream, false);
384-
I.Args.emplace_back(std::move(arg_str));
384+
result.emplace_back(std::move(arg_str));
385385
}
386386
}
387387

@@ -401,12 +401,13 @@ parseTemplateArgs(
401401
}
402402
// KRYSTIAN NOTE: when this is a partial specialization, we could use
403403
// ClassTemplatePartialSpecializationDecl::getTemplateArgsAsWritten
404-
const TypeSourceInfo* tsi = spec->getTypeAsWritten();
405-
// type source information *should* be non-null
406-
Assert(tsi);
407-
auto args = tsi->getType()->getAs<
404+
const TypeSourceInfo* type_written = spec->getTypeAsWritten();
405+
// if the type as written is nullptr (it should never be), bail
406+
if(! type_written)
407+
return;
408+
auto args = type_written->getType()->getAs<
408409
TemplateSpecializationType>()->template_arguments();
409-
buildTemplateArgs(I, args);
410+
buildTemplateArgs(I.Args, args);
410411
}
411412

412413
void
@@ -427,20 +428,18 @@ parseTemplateArgs(
427428
// the USR of the templated VarDecl seems to be the correct one.
428429
extractSymbolID(primary->getTemplatedDecl(), I.Primary.emplace());
429430
}
430-
431-
// spec->getTemplateArgsInfo()
432-
if(auto* partial = dyn_cast<VarTemplatePartialSpecializationDecl>(spec);
433-
partial && partial->getTemplateArgsAsWritten())
434-
{
435-
auto args = partial->getTemplateArgsAsWritten()->arguments();
436-
buildTemplateArgs(I, std::views::transform(
437-
args, [](auto& x) -> auto& { return x.getArgument(); }));
438-
}
431+
const ASTTemplateArgumentListInfo* args_written = nullptr;
432+
// getTemplateArgsInfo returns nullptr for partial specializations,
433+
// so we use getTemplateArgsAsWritten if this is a partial specialization
434+
if(auto* partial = dyn_cast<VarTemplatePartialSpecializationDecl>(spec))
435+
args_written = partial->getTemplateArgsAsWritten();
439436
else
440-
{
441-
buildTemplateArgs(I, spec->getTemplateArgs().asArray());
442-
}
443-
// buildTemplateArgs(I, spec->getTemplateInstantiationArgs().asArray());
437+
args_written = spec->getTemplateArgsInfo();
438+
if(! args_written)
439+
return;
440+
auto args = args_written->arguments();
441+
buildTemplateArgs(I.Args, std::views::transform(
442+
args, [](auto& x) -> auto& { return x.getArgument(); }));
444443
}
445444

446445
void
@@ -458,11 +457,11 @@ parseTemplateArgs(
458457
primary = MT;
459458
extractSymbolID(primary, I.Primary.emplace());
460459
}
460+
// TemplateArguments is used instead of TemplateArgumentsAsWritten
461+
// because explicit specializations of function templates may have
462+
// template arguments deduced from their return type and parameters
461463
if(auto* args = spec->TemplateArguments)
462-
{
463-
// spec->TemplateArgumentsAsWritten->arguments();
464-
buildTemplateArgs(I, args->asArray());
465-
}
464+
buildTemplateArgs(I.Args, args->asArray());
466465
}
467466

468467
void
@@ -473,12 +472,15 @@ parseTemplateArgs(
473472
{
474473
// if(! spec->hasExplicitTemplateArgs())
475474
// return;
476-
// KRYSTIAN NOTE: we have no way to get the ID of the primary template.
475+
// KRYSTIAN NOTE: we have no way to get the ID of the primary template;
476+
// it is unknown what function template this will be an explicit
477+
// specialization of until the enclosing class template is instantiated.
478+
// this also means that we can only extract the explicit template arguments.
477479
// in the future, we could use name lookup to find matching declarations
478480
if(auto* args_written = spec->getTemplateArgsAsWritten())
479481
{
480482
auto args = args_written->arguments();
481-
buildTemplateArgs(I, std::views::transform(
483+
buildTemplateArgs(I.Args, std::views::transform(
482484
args, [](auto& x) -> auto& { return x.getArgument(); }));
483485
}
484486
}

source/AST/ASTVisitor.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ class ASTVisitor
148148
buildTemplateParam(
149149
const NamedDecl* ND);
150150

151-
template<typename R>
151+
template<typename Range>
152152
void
153153
buildTemplateArgs(
154-
TemplateInfo& I,
155-
R&& args);
154+
std::vector<TArg>& result,
155+
Range&& range);
156156

157157
void
158158
parseTemplateArgs(
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
template<typename T>
2+
struct A
3+
{
4+
template<typename U, typename V>
5+
struct B { };
6+
7+
template<typename U>
8+
struct B<U*, T> { };
9+
10+
template<>
11+
struct B<T, long> { };
12+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<mrdox xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="https://github.com/cppalliance/mrdox/raw/develop/mrdox.rnc">
4+
<namespace name="">
5+
<struct name="A" id="5tUSuMtQqtYE49jBjSYSWp0DJAM=">
6+
<file path="class-template-partial-spec.cpp" line="2" class="def"/>
7+
<template>
8+
<tparam name="T" class="type"/>
9+
</template>
10+
<struct name="B" id="oAtKB0INIy/QCSdQExvcQwsaZJA=">
11+
<file path="class-template-partial-spec.cpp" line="5" class="def"/>
12+
<template>
13+
<tparam name="U" class="type"/>
14+
<tparam name="V" class="type"/>
15+
</template>
16+
</struct>
17+
<struct name="B" id="Y/lm1lkT88vf1Ml123mbuN6Fp2Y=">
18+
<file path="class-template-partial-spec.cpp" line="7" class="def"/>
19+
<template class="partial" id="oAtKB0INIy/QCSdQExvcQwsaZJA=">
20+
<tparam name="U" class="type"/>
21+
<targ value="U *"/>
22+
<targ value="T"/>
23+
</template>
24+
</struct>
25+
<struct name="B" id="RB9DBMAJDxjxuRQCinQOVPFSNek=">
26+
<file path="class-template-partial-spec.cpp" line="10" class="def"/>
27+
<template class="explicit" id="oAtKB0INIy/QCSdQExvcQwsaZJA=">
28+
<targ value="T"/>
29+
<targ value="long"/>
30+
</template>
31+
</struct>
32+
</struct>
33+
</namespace>
34+
</mrdox>

test-files/old-tests/template-spec.xml renamed to test-files/old-tests/class-template-spec.xml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,90 +3,90 @@
33
xsi:noNamespaceSchemaLocation="https://github.com/cppalliance/mrdox/raw/develop/mrdox.rnc">
44
<namespace name="">
55
<struct name="A" id="AKwlChAOi+0ttIAPsD7uitS+gk0=">
6-
<file path="template-spec.cpp" line="7" class="def"/>
6+
<file path="class-template-spec.cpp" line="7" class="def"/>
77
<template class="explicit" id="5tUSuMtQqtYE49jBjSYSWp0DJAM=">
88
<targ value="int"/>
99
</template>
1010
<function name="g" id="NCn1LYKSU8X/x/ejZTTGKsJQLug=">
11-
<file path="template-spec.cpp" line="10"/>
11+
<file path="class-template-spec.cpp" line="10"/>
1212
</function>
1313
</struct>
1414
<struct name="B" id="Bu/3QcmNOdsc7RSM3OKHnuCxGPU=">
15-
<file path="template-spec.cpp" line="20" class="def"/>
15+
<file path="class-template-spec.cpp" line="20" class="def"/>
1616
<template>
1717
<tparam name="T" class="type"/>
1818
</template>
1919
<function name="f" id="toIq7IwIU6fbbbkqhsEmDYWVF00=">
20-
<file path="template-spec.cpp" line="22"/>
20+
<file path="class-template-spec.cpp" line="22"/>
2121
</function>
2222
</struct>
2323
<struct name="B" id="ZjUaxeOoGJ0Jol9Nmn7cGRE7RCo=">
24-
<file path="template-spec.cpp" line="31" class="def"/>
24+
<file path="class-template-spec.cpp" line="31" class="def"/>
2525
<template class="partial" id="Bu/3QcmNOdsc7RSM3OKHnuCxGPU=">
2626
<tparam name="T" class="type"/>
2727
<targ value="T &amp;"/>
2828
</template>
2929
<function name="h" id="Y1o9DjZarkgpmS4JVrc/XkZMn3k=">
30-
<file path="template-spec.cpp" line="34"/>
30+
<file path="class-template-spec.cpp" line="34"/>
3131
</function>
3232
</struct>
3333
<struct name="B" id="dydGCFMdrM4nOwuv3RCXqg2KCUA=">
34-
<file path="template-spec.cpp" line="25" class="def"/>
34+
<file path="class-template-spec.cpp" line="25" class="def"/>
3535
<template class="partial" id="Bu/3QcmNOdsc7RSM3OKHnuCxGPU=">
3636
<tparam name="T" class="type"/>
3737
<targ value="T *"/>
3838
</template>
3939
<function name="g" id="YqMF7qPhrCzrLLwscZ76goyLl0k=">
40-
<file path="template-spec.cpp" line="28"/>
40+
<file path="class-template-spec.cpp" line="28"/>
4141
</function>
4242
</struct>
4343
<struct name="C" id="qrcrkE8Br83XKNMh95Dvwpph/M8=">
44-
<file path="template-spec.cpp" line="43" class="def"/>
44+
<file path="class-template-spec.cpp" line="43" class="def"/>
4545
<template class="explicit" id="8nYw0KA23eAszqSOs0wOXAD1DYQ=">
4646
<targ value="int"/>
4747
<targ value="int"/>
4848
</template>
4949
<function name="g" id="xGwiZK/5LGsqcQUgiFrCHkH3zFU=">
50-
<file path="template-spec.cpp" line="46"/>
50+
<file path="class-template-spec.cpp" line="46"/>
5151
</function>
5252
</struct>
5353
<struct name="A" id="y/8TvVlacBAIG2ds2aYgZE+zGUU=">
54-
<file path="template-spec.cpp" line="13" class="def"/>
54+
<file path="class-template-spec.cpp" line="13" class="def"/>
5555
<template class="explicit" id="5tUSuMtQqtYE49jBjSYSWp0DJAM=">
5656
<targ value="long"/>
5757
</template>
5858
<function name="h" id="t1Sc28cdaNrQCdMKo/gCBCog34Q=">
59-
<file path="template-spec.cpp" line="16"/>
59+
<file path="class-template-spec.cpp" line="16"/>
6060
</function>
6161
</struct>
6262
<struct name="A" id="5tUSuMtQqtYE49jBjSYSWp0DJAM=">
63-
<file path="template-spec.cpp" line="2" class="def"/>
63+
<file path="class-template-spec.cpp" line="2" class="def"/>
6464
<template>
6565
<tparam name="T" class="type"/>
6666
</template>
6767
<function name="f" id="c4jAAYDw9qnOxUCpXquNT7fALUY=">
68-
<file path="template-spec.cpp" line="4"/>
68+
<file path="class-template-spec.cpp" line="4"/>
6969
</function>
7070
</struct>
7171
<struct name="C" id="6zS87fCNnLtFfHbRWEmcdeAT1Zg=">
72-
<file path="template-spec.cpp" line="49" class="def"/>
72+
<file path="class-template-spec.cpp" line="49" class="def"/>
7373
<template class="partial" id="8nYw0KA23eAszqSOs0wOXAD1DYQ=">
7474
<tparam name="T" class="type"/>
7575
<targ value="T *"/>
7676
<targ value="int"/>
7777
</template>
7878
<function name="h" id="N2KH/LGAYrCEUFXj6hyS4bkzaIs=">
79-
<file path="template-spec.cpp" line="52"/>
79+
<file path="class-template-spec.cpp" line="52"/>
8080
</function>
8181
</struct>
8282
<struct name="C" id="8nYw0KA23eAszqSOs0wOXAD1DYQ=">
83-
<file path="template-spec.cpp" line="38" class="def"/>
83+
<file path="class-template-spec.cpp" line="38" class="def"/>
8484
<template>
8585
<tparam name="T" class="type"/>
8686
<tparam name="U" class="type"/>
8787
</template>
8888
<function name="f" id="mhp5LhlIUPVO0i2zQmcJLvBQAlk=">
89-
<file path="template-spec.cpp" line="40"/>
89+
<file path="class-template-spec.cpp" line="40"/>
9090
</function>
9191
</struct>
9292
</namespace>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
template<typename T>
2+
struct A
3+
{
4+
template<typename U, typename V>
5+
constexpr static T x = 0;
6+
7+
template<typename U>
8+
constexpr static T x<U*, T> = 1;
9+
10+
template<>
11+
constexpr static bool x<T, long> = 2;
12+
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<mrdox xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:noNamespaceSchemaLocation="https://github.com/cppalliance/mrdox/raw/develop/mrdox.rnc">
4+
<namespace name="">
5+
<struct name="A" id="5tUSuMtQqtYE49jBjSYSWp0DJAM=">
6+
<file path="static-data-template.cpp" line="2" class="def"/>
7+
<template>
8+
<tparam name="T" class="type"/>
9+
</template>
10+
<variable name="x" id="7L90lvoKPW80F2cnMs0e05abtuk=">
11+
<file path="static-data-template.cpp" line="5" class="def"/>
12+
<template>
13+
<tparam name="U" class="type"/>
14+
<tparam name="V" class="type"/>
15+
</template>
16+
<attr id="storage-class" name="static" value="2"/>
17+
<type name="const T"/>
18+
</variable>
19+
<variable name="x" id="odTOUblgmooUozrBqW3qKzPWSO4=">
20+
<file path="static-data-template.cpp" line="7" class="def"/>
21+
<template class="partial" id="7L90lvoKPW80F2cnMs0e05abtuk=">
22+
<tparam name="U" class="type"/>
23+
<targ value="U *"/>
24+
<targ value="T"/>
25+
</template>
26+
<attr id="storage-class" name="static" value="2"/>
27+
<type name="const T"/>
28+
</variable>
29+
<variable name="x" id="eKdgKT44WwfN7UkQXGEqVJssIPM=">
30+
<file path="static-data-template.cpp" line="10" class="def"/>
31+
<template class="explicit" id="7L90lvoKPW80F2cnMs0e05abtuk=">
32+
<targ value="T"/>
33+
<targ value="long"/>
34+
</template>
35+
<attr id="storage-class" name="static" value="2"/>
36+
<type name="const bool"/>
37+
</variable>
38+
</struct>
39+
</namespace>
40+
</mrdox>

0 commit comments

Comments
 (0)