Skip to content

Commit 0642e5e

Browse files
committed
[clang-tidy] modernize-use-using: Fix broken fixit with 'template' keyword
Summary: Before this PR, `modernize-use-using` would transform the typedef in ``` template <typename a> class TemplateKeyword { typedef typename a::template f<> e; typedef typename a::template f<>::d e2; }; ``` into ``` template <typename a> class TemplateKeyword { using d = typename a::b<>; using d2 = typename a::template a::b<>::c; }; ``` The first one is missing the `template` keyword, the second one has an extra `a::` scope. Both result in compilation errors. Reviewers: aaron.ballman, alexfh, hokein, njames93 Subscribers: xazax.hun, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D78139
1 parent fd7a341 commit 0642e5e

File tree

4 files changed

+23
-4
lines changed

4 files changed

+23
-4
lines changed

clang-tools-extra/test/clang-tidy/checkers/modernize-use-using.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,17 @@ typedef TwoArgTemplate<TwoArgTemplate<int, Q<T{0 < 0}.b> >, S<(0 < 0), Q<b[0 < 0
249249
// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef'
250250
// CHECK-FIXES: using Nested_t = TwoArgTemplate<TwoArgTemplate<int, Q<T{0 < 0}.b>>, S<(0 < 0), Q<b[0 < 0]>>>;
251251

252+
template <typename a>
253+
class TemplateKeyword {
254+
typedef typename a::template b<> d;
255+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
256+
// CHECK-FIXES: using d = typename a::template b<>;
257+
258+
typedef typename a::template b<>::c d2;
259+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'using' instead of 'typedef'
260+
// CHECK-FIXES: using d2 = typename a::template b<>::c;
261+
};
262+
252263
template <typename... Args>
253264
class Variadic {};
254265

clang/lib/AST/NestedNameSpecifier.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,14 @@ void NestedNameSpecifier::print(raw_ostream &OS, const PrintingPolicy &Policy,
311311
// Print the template argument list.
312312
printTemplateArgumentList(OS, SpecType->template_arguments(),
313313
InnerPolicy);
314+
} else if (const auto *DepSpecType =
315+
dyn_cast<DependentTemplateSpecializationType>(T)) {
316+
// Print the template name without its corresponding
317+
// nested-name-specifier.
318+
OS << DepSpecType->getIdentifier()->getName();
319+
// Print the template argument list.
320+
printTemplateArgumentList(OS, DepSpecType->template_arguments(),
321+
InnerPolicy);
314322
} else {
315323
// Print the type normally
316324
QualType(T, 0).print(OS, InnerPolicy);

clang/lib/AST/TypePrinter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1388,7 +1388,7 @@ void TypePrinter::printDependentTemplateSpecializationBefore(
13881388

13891389
if (T->getQualifier())
13901390
T->getQualifier()->print(OS, Policy);
1391-
OS << T->getIdentifier()->getName();
1391+
OS << "template " << T->getIdentifier()->getName();
13921392
printTemplateArgumentList(OS, T->template_arguments(), Policy);
13931393
spaceBeforePlaceHolder(OS);
13941394
}

clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ static_assert(!requires { typename ::F<int>; });
109109
struct G { template<typename T> static T temp; };
110110

111111
template<typename T> requires requires { typename T::template temp<int>; }
112-
// expected-note@-1{{because 'typename T::temp<int>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
113-
// expected-note@-2{{because 'typename T::temp<int>' would be invalid: no member named 'temp' in 'D'}}
114-
// expected-note@-3{{because 'typename T::temp<int>' would be invalid: template name refers to non-type template 'G::template temp'}}
112+
// expected-note@-1{{because 'typename T::template temp<int>' would be invalid: type 'int' cannot be used prior to '::' because it has no members}}
113+
// expected-note@-2{{because 'typename T::template temp<int>' would be invalid: no member named 'temp' in 'D'}}
114+
// expected-note@-3{{because 'typename T::template temp<int>' would be invalid: template name refers to non-type template 'G::template temp'}}
115115
struct r7 {};
116116

117117
using r7i1 = r7<int>; // expected-error{{constraints not satisfied for class template 'r7' [with T = int]}}

0 commit comments

Comments
 (0)