rsmith added inline comments.
================
Comment at: clang/include/clang/AST/DeclTemplate.h:213
+ else if (Idx >= TPL->size())
+ return false;
+ else {
----------------
We should return `true` in this case; we don't know what the corresponding
parameter is so we don't know if the type matters.
================
Comment at: clang/include/clang/AST/DeclTemplate.h:216
+ const NamedDecl *TemplParam = TPL->getParam(Idx);
+ if (auto *ParamValueDecl = dyn_cast<ValueDecl>(TemplParam))
+ if (ParamValueDecl->getType()->getContainedDeducedType())
----------------
May as well go straight to `NonTypeTemplateParamDecl` here; it can't be any
other kind of `ValueDecl`.
================
Comment at: clang/include/clang/AST/StmtDataCollectors.td:48-72
+ const TemplateParameterList *TPL = nullptr;
+ if (auto SD = dyn_cast<DeclRefExpr>(S))
+ if (!SD->hadMultipleCandidates())
+ if (auto *TD = dyn_cast<TemplateDecl>(D))
+ TPL = TD->getTemplateParameters();
if (auto Args = D->getTemplateSpecializationArgs()) {
std::string ArgString;
----------------
I'm not entirely sure what this is used for, but it looks like the goal is
uniqueness, not human-readability, given that the template arguments are
separated by newlines not by commas or similar. That being the case, I think we
should unconditionally pass `true` as `IncludeType` here.
================
Comment at: clang/include/clang/AST/StmtDataCollectors.td:61-64
+ } else if (i >= TPL->size()) {
+ Args->get(i).print(Context.getLangOpts(), OS, /*IncludeType*/
false);
+ }
+ else {
----------------
Nit: exactly one space between `}` and `else`. (You have two spaces in the
first instance here and a newline in the second instance.)
================
Comment at: clang/lib/AST/ASTContext.cpp:7462
+ OS, TemplateArgs.asArray(), getPrintingPolicy(),
+ Spec->getSpecializedTemplate()->getTemplateParameters());
}
----------------
Pass `nullptr` here; for ObjC `@encode` we presumably want fully-explicit
output always.
================
Comment at: clang/lib/AST/DeclPrinter.cpp:651-652
+ ->getTemplateParameters();
+ // FIXME: Check if function template is overloaded
+ bool TemplOverloaded = false;
if (TArgAsWritten && !Policy.PrintCanonicalTypes)
----------------
We should conservatively assume that it is, rather than potentially printing
out an ambiguous AST fragment.
================
Comment at: clang/lib/AST/DeclPrinter.cpp:994-995
Args = TST->template_arguments();
- printTemplateArguments(Args);
+ // FIXME: Check if function template is overloaded
+ bool TemplOverloaded = false;
+ printTemplateArguments(
----------------
This is a class template specialization, not a function template
specialization. It can't be overloaded.
================
Comment at: clang/lib/AST/DeclTemplate.cpp:1437
OS << "<";
+ // FIXME: Only pass parameter if template is not overloaded
+ // FIXME: Find corresponding parameter for argument
----------------
Concepts can't be overloaded; remove this FIXME.
================
Comment at: clang/lib/AST/Expr.cpp:702
TOut << Param << " = ";
- Args.get(i).print(Policy, TOut);
+ // FIXME: Only pass parameter if template is overloaded
+ Args.get(i).print(
----------------
Remove this FIXME: class template specializations can't be overloaded.
================
Comment at: clang/lib/AST/StmtPrinter.cpp:1450
+ if (auto *FD = dyn_cast<FunctionDecl>(Node->getMemberDecl()))
+ TPL = FD->getDescribedTemplateParams();
+ else if (auto *TD =
----------------
This isn't right: `getDescribedTemplateParams` handles the case where the
declaration is the pattern in a template definition, not where it's a template
instantiation. What you want here is:
```
if (auto *FTD = FD->getPrimaryTemplate())
TPL = FTD->getTemplateParameters();
```
You should also take into account `Node->hadMultipleCandidates()` here.
Testcase for this would be something like:
```
struct A {
template<long, auto> void f();
};
void g(A a) { a.f<0L, 0L>(); }
```
... for which `-ast-print` should produce `f<0, 0L>`.
================
Comment at: clang/lib/AST/StmtPrinter.cpp:1453
+ dyn_cast<VarTemplateSpecializationDecl>(Node->getMemberDecl()))
+ TPL = TD->getDescribedTemplateParams();
if (Node->hasExplicitTemplateArgs())
----------------
This is likewise not right. In this case we always know there's a template, so
it's slightly simpler:
```
TPL = TD->getSpecializedTemplate()->getTemplateParameters();
```
Please also rename `TD` to something more appropriate.
Testcase for this would be something like:
```
struct A {
template<long> static int x;
template<auto> static int y;
};
int k = A().x<0L> + A().y<0L>;
```
... for which `-ast-print` should produce `x<0>` but `y<0L>`.
================
Comment at: clang/lib/AST/TemplateBase.cpp:54
+///
+/// \param IncludeType the flag to determine printing type information.
+static void printIntegral(const TemplateArgument &TemplArg, raw_ostream &Out,
----------------
I don't think this is very clear about the purpose of the flag. How about:
```
\param IncludeType If set, ensure that the type of the expression printed
matches the type of the template argument.
```
================
Comment at: clang/lib/AST/TemplateBase.cpp:111-115
+ Out << "u8'" << Val << "'";
+ else if (T->isUnsignedIntegerType() && T->isChar16Type())
+ Out << "u16'" << Val << "'";
+ else if (T->isUnsignedIntegerType() && T->isChar32Type())
+ Out << "u32'" << Val << "'";
----------------
This isn't correct: `u8'x'` will print as `u8'120'`. Perhaps you can factor
code to do this properly out of `StmtPrinter::VisitCharacterLiteral`.
Also, the prefix for `char16_t` literals is `u`, not `u16`, and the prefix for
`char32_t` literals is `U`, not `u32`.
================
Comment at: clang/lib/AST/TemplateBase.cpp:79-84
+ if (IncludeType) {
+ if (T->isSignedIntegerType())
+ Out << "(signed char)";
+ else
+ Out << "(unsigned char)";
+ }
----------------
rsmith wrote:
> We should not include a cast for plain `char`, only for `signed char` and
> `unsigned char`.
This is marked 'done' but not done. Note that plain `char` is always either a
signed or unsigned type, so your check here does not work. You can check
`T->isSpecificBuiltinType(BuiltinType::SChar)` and
`T->isSpecificBuiltinType(BuiltinType::UChar)` instead.
================
Comment at: clang/lib/AST/TemplateBase.cpp:395
case Declaration: {
NamedDecl *ND = getAsDecl();
----------------
rsmith wrote:
> Please add a FIXME to handle `knownType` here.
This is marked as done but not done. (The template parameter object case has a
FIXME but the other cases do not and should.)
================
Comment at: clang/lib/AST/TemplateBase.cpp:71-72
if (T->isBooleanType() && !Policy.MSVCFormatting) {
Out << (Val.getBoolValue() ? "true" : "false");
} else if (T->isCharType()) {
----------------
rsmith wrote:
> rnk wrote:
> > rsmith wrote:
> > > reikdas wrote:
> > > > rsmith wrote:
> > > > > rsmith wrote:
> > > > > > It looks like `MSVCFormatting` wants `bool` values to be printed as
> > > > > > `0` and `1`, and this patch presumably changes that (along with the
> > > > > > printing of other builtin types). I wonder if this is a problem in
> > > > > > practice (eg, if such things are used as keys for debug info or
> > > > > > similar)...
> > > > > Do we need to suppress printing the suffixes below in
> > > > > `MSVCFormatting` mode too?
> > > > @rsmith The tests pass, so that is reassuring at least. Is there any
> > > > other way to find out whether we need to suppress printing the suffixes
> > > > for other types in MSVCFormatting mode?
> > > @rnk Can you take a look at this? Per
> > > rG60103383f097b6580ecb4519eeb87defdb7c05c9 and PR21528 it seems like
> > > there might be specific requirements for how template arguments are
> > > formatted for CodeView support; we presumably need to make sure we still
> > > satisfy those requirements.
> > Probably. This change looks like it preserves behavior from before when
> > `MSVCFormatting` is set, so I think this is OK. I checked, my version of
> > MSVC still uses 1/0 in debug info for boolean template args.
> My concern is that we're changing the behavior for the other cases below in
> `MSVCFormatting` mode, not that we're changing the behavior for `bool`. If we
> have specific formatting requirements in `MSVCFormatting` mode, they
> presumably apply to all types, not only to `bool`, so we should be careful to
> not change the output in `MSVCFormatting` mode for any type.
@rnk Ping.
================
Comment at: clang/lib/AST/TypePrinter.cpp:1980
bool FirstArg = true;
+ unsigned i = 0;
for (const auto &Arg : Args) {
----------------
Please capitalize this, following the naming convention of the surrounding code.
================
Comment at: clang/lib/AST/TypePrinter.cpp:1989
OS << Comma;
- printTo(ArgOS, Argument.getPackAsArray(), Policy, true, nullptr);
+ printTo(ArgOS, Argument.getPackAsArray(), Policy, true, TPL);
} else {
----------------
This is wrong; we'll incorrectly assume that element `i` of the pack
corresponds to element `i` of the original template parameter list. We should
use the same template parameter for all elements of the pack. (For example, you
could pass in `I` and instruct the inner invocation of `printTo` to not
increment `I` as it goes.)
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:992
TemplateArgumentListInfo &Args,
+ const TemplateParameterList *Params,
unsigned DiagID) {
----------------
It doesn't make sense to pass a parameter list in here, because we've not
selected a template yet.
================
Comment at: clang/lib/Sema/SemaDeclCXX.cpp:1035
Loc, TraitTy, DiagID,
- printTemplateArgs(S.Context.getPrintingPolicy(), Args));
+ printTemplateArgs(S.Context.getPrintingPolicy(), Args, Params));
return true;
----------------
In this case, the parameter list is `TraitTD->getTemplateParameters()`.
================
Comment at: clang/lib/Sema/SemaTemplateDeduction.cpp:4723-4726
+ if (!TPL)
+ Arg.print(S.getPrintingPolicy(), OS, /*IncludeType*/ true);
+ else if (i >= TPL->size())
+ Arg.print(S.getPrintingPolicy(), OS, /*IncludeType*/ false);
----------------
rsmith wrote:
> Hm, are we missing commas between these arguments?
>
> Please consider whether this and some of the other repeated instances of this
> code can be replaced by calls to `printTemplateArgumentList`.
Ping, can this be replaced by a call to `printTemplateArgumentList`?
================
Comment at: clang/lib/Sema/SemaTemplateInstantiate.cpp:814-818
+ if (!isa<FunctionDecl>(Active->Entity)) {
+ const TemplateParameterList *TPL = nullptr;
+ if (auto *TD = dyn_cast<TemplateDecl>(Active->Entity))
+ TPL = TD->getTemplateParameters();
+ // FIXME: Only pass parameter list if template is not overloaded
----------------
rsmith wrote:
> In this case, including substituted default argument values seems important.
Sorry, I wasn't clear: I think we should not include the template parameters
here, so that we do print out substituted template arguments even if they're
equivalent to the default argument.
================
Comment at: clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp:471
+ template <auto... N> struct X {};
+ X<1, 1u>::type y; // expected-error {{no type named 'type' in
'TypeSuffix::X<1, 1u>'}}
+ X<1, 1>::type z; // expected-error {{no type named 'type' in
'TypeSuffix::X<1, 1>'}}
----------------
reikdas wrote:
> @rsmith This test fails and we are unable to print the suffix here because
> the length of the TemplateParameterList is less than the length of the
> corresponding list of Template Arguments. Do you have any suggestions on how
> we can fix this?
Once we hit a template parameter pack, we should use the same parameter for all
subsequent arguments.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D77598/new/
https://reviews.llvm.org/D77598
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits