Skip to content

Commit

Permalink
Introduce the AlwaysIncludeTypeForNonTypeTemplateArgument into prin…
Browse files Browse the repository at this point in the history
…ting policy

If enabled, it will ensure that full type name is always printed.
This should fix issue reported here: llvm#57562

Currently, I've disabled the policy by default, as enabling it makes some tests fail, notably:
- CodeGenCXX/debug-info-template.cpp
- SemaCXX/constexpr-printing.cpp
- SemaCXX/cxx2a-nttp-printing.cpp
- SemaTemplate/temp_arg_string_printing.cpp

However, my opinion is that those tests should be updated and new policy always enabled, to mimic GCC's behavior.

I've added 2 new tests in AST/TypePrinterTest.cpp, one of which actually demonstrates the issue I've had in the first place (which was also reported on GitHub).

Differential Revision: https://reviews.llvm.org/D134453
  • Loading branch information
DoDoENT committed Sep 22, 2022
1 parent 66cae86 commit e665e29
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 3 deletions.
14 changes: 13 additions & 1 deletion clang/include/clang/AST/PrettyPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ struct PrintingPolicy {
PrintCanonicalTypes(false), PrintInjectedClassNameWithArguments(true),
UsePreferredNames(true), AlwaysIncludeTypeForTemplateArgument(false),
CleanUglifiedParameters(false), EntireContentsOfLargeArray(true),
UseEnumerators(true) {}
UseEnumerators(true), AlwaysIncludeTypeForNonTypeTemplateArgument(false) {}

/// Adjust this printing policy for cases where it's known that we're
/// printing C++ code (for instance, if AST dumping reaches a C++-only
Expand Down Expand Up @@ -295,6 +295,18 @@ struct PrintingPolicy {
/// enumerator name or via cast of an integer.
unsigned UseEnumerators : 1;

/// Whether to print full type names of non-type template arguments.
///
/// \code
/// struct Point { int x, y; };
/// template< Point p > struct S {};
/// S< Point{ 1, 2 } > s;
/// \endcode
///
/// decltype(s) will be printed as "S<Point{1,2}>" if enabled and as "S<{1,2}>" if disabled,
/// regardless if PrintCanonicalTypes is enabled.
unsigned AlwaysIncludeTypeForNonTypeTemplateArgument : 1;

/// Callbacks to use to allow the behavior of printing to be customized.
const PrintingCallbacks *Callbacks = nullptr;
};
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/APValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,8 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy,
assert(BI != CD->bases_end());
if (!First)
Out << ", ";
if (Policy.AlwaysIncludeTypeForNonTypeTemplateArgument)
BI->getType().getUnqualifiedType().print(Out, Policy);
getStructBase(I).printPretty(Out, Policy, BI->getType(), Ctx);
First = false;
}
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/TemplateBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,10 +432,11 @@ void TemplateArgument::print(const PrintingPolicy &Policy, raw_ostream &Out,
}

case Declaration: {
// FIXME: Include the type if it's not obvious from the context.
NamedDecl *ND = getAsDecl();
if (getParamTypeForDecl()->isRecordType()) {
if (auto *TPO = dyn_cast<TemplateParamObjectDecl>(ND)) {
if (Policy.AlwaysIncludeTypeForNonTypeTemplateArgument)
TPO->getType().getUnqualifiedType().print(Out, Policy);
TPO->printAsInit(Out, Policy);
break;
}
Expand Down
85 changes: 84 additions & 1 deletion clang/unittests/AST/TypePrinterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ TEST(TypePrinter, TemplateId) {
std::string Code = R"cpp(
namespace N {
template <typename> struct Type {};
template <typename T>
void Foo(const Type<T> &Param);
}
Expand Down Expand Up @@ -127,3 +127,86 @@ TEST(TypePrinter, TemplateIdWithNTTP) {
Policy.EntireContentsOfLargeArray = true;
}));
}

TEST(TypePrinter, TemplateIdWithFullTypeNTTP) {
constexpr char Code[] = R"cpp(
enum struct Encoding { UTF8, ASCII };
template <int N, Encoding E = Encoding::ASCII>
struct Str {
constexpr Str(char const (&s)[N]) { __builtin_memcpy(value, s, N); }
char value[N];
};
template <Str> class ASCII {};
ASCII<"some string"> x;
)cpp";
auto Matcher = classTemplateSpecializationDecl(
hasName("ASCII"), has(cxxConstructorDecl(
isMoveConstructor(),
has(parmVarDecl(hasType(qualType().bind("id")))))));

ASSERT_TRUE(PrintedTypeMatches(
Code, {"-std=c++20"}, Matcher,
R"(ASCII<Str<12, Encoding::ASCII>{"some string"}> &&)",
[](PrintingPolicy &Policy) {
Policy.AlwaysIncludeTypeForNonTypeTemplateArgument = true;
}));

ASSERT_TRUE(PrintedTypeMatches(
Code, {"-std=c++20"}, Matcher, R"(ASCII<{"some string"}> &&)",
[](PrintingPolicy &Policy) {
Policy.AlwaysIncludeTypeForNonTypeTemplateArgument = false;
}));
}

TEST(TypePrinter, TemplateIdWithComplexFullTypeNTTP) {
constexpr char Code[] = R"cpp(
template< typename T, auto ... dims >
struct NDArray {};
struct Dimension
{
using value_type = unsigned short;
value_type size{ value_type( 0 ) };
};
template < typename ConcreteDim >
struct DimensionImpl : Dimension {};
struct Width : DimensionImpl< Width > {};
struct Height : DimensionImpl< Height > {};
struct Channels : DimensionImpl< Channels > {};
inline constexpr Width W;
inline constexpr Height H;
inline constexpr Channels C;
template< auto ... Dims >
consteval auto makeArray() noexcept
{
return NDArray< float, Dims ... >{};
}
[[ maybe_unused ]] auto x { makeArray< H, W, C >() };
)cpp";
auto Matcher = varDecl(
allOf(hasAttr(attr::Kind::Unused), hasType(qualType().bind("id"))));

ASSERT_TRUE(PrintedTypeMatches(
Code, {"-std=c++20"}, Matcher,
R"(NDArray<float, {{{0}}}, {{{0}}}, {{{0}}}>)",
[](PrintingPolicy &Policy) {
Policy.PrintCanonicalTypes = true;
Policy.AlwaysIncludeTypeForNonTypeTemplateArgument = false;
}));

ASSERT_TRUE(PrintedTypeMatches(
Code, {"-std=c++20"}, Matcher,
R"(NDArray<float, Height{DimensionImpl<Height>{Dimension{0}}}, Width{DimensionImpl<Width>{Dimension{0}}}, Channels{DimensionImpl<Channels>{Dimension{0}}}>)",
[](PrintingPolicy &Policy) {
Policy.PrintCanonicalTypes = true;
Policy.AlwaysIncludeTypeForNonTypeTemplateArgument = true;
}));
}

0 comments on commit e665e29

Please sign in to comment.