Skip to content

Commit 696946f

Browse files
authored
[clang] Add a valid begin source location for abbreviated function templates (#174723)
The begin source location for function templates is determined by the source location of the template keyword. Pure abbreviated function templates do not have the template keyword. This results in an invalid begin source location for abbreviated function templates. Without a valid begin source location, comments cannot be attached to the function template which leads to the bug described in clangd/clangd#2565. This patch introduces new begin locations for abbreviated function templates (begin of the templated function) and generic lambdas (begin of the introducer `[...]`) when creating the template parameter lists in Sema.
1 parent 41079da commit 696946f

File tree

7 files changed

+454
-10
lines changed

7 files changed

+454
-10
lines changed

clang-tools-extra/clangd/unittests/HoverTests.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,137 @@ TEST(Hover, Structured) {
5757
HI.Type = "void ()";
5858
HI.Parameters.emplace();
5959
}},
60+
{R"cpp(
61+
// Best foo ever.
62+
void [[fo^o]](auto x) {}
63+
)cpp",
64+
[](HoverInfo &HI) {
65+
HI.NamespaceScope = "";
66+
HI.Name = "foo";
67+
HI.Kind = index::SymbolKind::Function;
68+
HI.Documentation = "Best foo ever.";
69+
HI.Definition = "void foo(auto x)";
70+
HI.ReturnType = "void";
71+
HI.Type = "void (auto)";
72+
HI.TemplateParameters = {
73+
{{"class"}, std::string("x:auto"), std::nullopt},
74+
};
75+
HI.Parameters = {
76+
{{"auto"}, std::string("x"), std::nullopt},
77+
};
78+
}},
79+
{R"cpp(
80+
// Best foo ever.
81+
template <class T>
82+
void [[fo^o]](T x) {}
83+
)cpp",
84+
[](HoverInfo &HI) {
85+
HI.NamespaceScope = "";
86+
HI.Name = "foo";
87+
HI.Kind = index::SymbolKind::Function;
88+
HI.Documentation = "Best foo ever.";
89+
HI.Definition = "template <class T> void foo(T x)";
90+
HI.ReturnType = "void";
91+
HI.Type = "void (T)";
92+
HI.TemplateParameters = {
93+
{{"class"}, std::string("T"), std::nullopt},
94+
};
95+
HI.Parameters = {
96+
{{"T"}, std::string("x"), std::nullopt},
97+
};
98+
}},
99+
{R"cpp(
100+
// Best foo ever.
101+
template <class T>
102+
void [[fo^o]](T x, auto y) {}
103+
)cpp",
104+
[](HoverInfo &HI) {
105+
HI.NamespaceScope = "";
106+
HI.Name = "foo";
107+
HI.Kind = index::SymbolKind::Function;
108+
HI.Documentation = "Best foo ever.";
109+
HI.Definition = "template <class T> void foo(T x, auto y)";
110+
HI.ReturnType = "void";
111+
HI.Type = "void (T, auto)";
112+
HI.TemplateParameters = {
113+
{{"class"}, std::string("T"), std::nullopt},
114+
{{"class"}, std::string("y:auto"), std::nullopt},
115+
};
116+
HI.Parameters = {
117+
{{"T"}, std::string("x"), std::nullopt},
118+
{{"auto"}, std::string("y"), std::nullopt},
119+
};
120+
}},
121+
{R"cpp(
122+
template<typename T1, typename T2>
123+
concept C = requires () { true; };
124+
125+
// Best foo ever.
126+
template<C<int> T>
127+
void [[fo^o]](T x) {}
128+
)cpp",
129+
[](HoverInfo &HI) {
130+
HI.NamespaceScope = "";
131+
HI.Name = "foo";
132+
HI.Kind = index::SymbolKind::Function;
133+
HI.Documentation = "Best foo ever.";
134+
HI.Definition = "template <C<int> T> void foo(T x)";
135+
HI.ReturnType = "void";
136+
HI.Type = "void (T)";
137+
HI.TemplateParameters = {
138+
{{"class"}, std::string("T"), std::nullopt},
139+
};
140+
HI.Parameters = {
141+
{{"T"}, std::string("x"), std::nullopt},
142+
};
143+
}},
144+
{R"cpp(
145+
template<typename T1, typename T2>
146+
concept C = requires () { true; };
147+
148+
// Best foo ever.
149+
void [[fo^o]](C<int> auto x) {}
150+
)cpp",
151+
[](HoverInfo &HI) {
152+
HI.NamespaceScope = "";
153+
HI.Name = "foo";
154+
HI.Kind = index::SymbolKind::Function;
155+
HI.Documentation = "Best foo ever.";
156+
HI.Definition = "void foo(C<int> auto x)";
157+
HI.ReturnType = "void";
158+
HI.Type = "void (C<int> auto)";
159+
HI.TemplateParameters = {
160+
{{"class"}, std::string("x:auto"), std::nullopt},
161+
};
162+
HI.Parameters = {
163+
{{"C<int> auto"}, std::string("x"), std::nullopt},
164+
};
165+
}},
166+
{R"cpp(
167+
template<typename T1, typename T2>
168+
concept C = requires () { true; };
169+
170+
// Best foo ever.
171+
template<C<int> T>
172+
void [[fo^o]](T x, C<int> auto y) {}
173+
)cpp",
174+
[](HoverInfo &HI) {
175+
HI.NamespaceScope = "";
176+
HI.Name = "foo";
177+
HI.Kind = index::SymbolKind::Function;
178+
HI.Documentation = "Best foo ever.";
179+
HI.Definition = "template <C<int> T> void foo(T x, C<int> auto y)";
180+
HI.ReturnType = "void";
181+
HI.Type = "void (T, C<int> auto)";
182+
HI.TemplateParameters = {
183+
{{"class"}, std::string("T"), std::nullopt},
184+
{{"class"}, std::string("y:auto"), std::nullopt},
185+
};
186+
HI.Parameters = {
187+
{{"T"}, std::string("x"), std::nullopt},
188+
{{"C<int> auto"}, std::string("y"), std::nullopt},
189+
};
190+
}},
60191
// Inside namespace
61192
{R"cpp(
62193
namespace ns1 { namespace ns2 {

clang/docs/ReleaseNotes.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ ABI Changes in This Version
140140
---------------------------
141141
- Fix AArch64 argument passing for C++ empty classes with large explicitly specified alignment.
142142

143+
AST Potentially Breaking Changes
144+
--------------------------------
145+
- Abbreviated function templates and generic lambdas now have a valid begin source location.
146+
The begin source location of abbreviated function templates is the begin source location of the templated function.
147+
The begin source location of generic lambdas is the begin source location of the lambda introducer ``[...]``.
148+
143149
AST Dumping Potentially Breaking Changes
144150
----------------------------------------
145151
- How nested name specifiers are dumped and printed changes, keeping track of clang AST changes.

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19635,10 +19635,10 @@ void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) {
1963519635
ExplicitParams->getRAngleLoc(),
1963619636
ExplicitParams->getRequiresClause()));
1963719637
} else {
19638-
Declarator.setInventedTemplateParameterList(
19639-
TemplateParameterList::Create(
19640-
Context, SourceLocation(), SourceLocation(), FSI.TemplateParams,
19641-
SourceLocation(), /*RequiresClause=*/nullptr));
19638+
Declarator.setInventedTemplateParameterList(TemplateParameterList::Create(
19639+
Context, Declarator.getBeginLoc(), SourceLocation(),
19640+
FSI.TemplateParams, Declarator.getEndLoc(),
19641+
/*RequiresClause=*/nullptr));
1964219642
}
1964319643
}
1964419644
InventedParameterInfos.pop_back();

clang/lib/Sema/SemaLambda.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,10 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) {
235235
if (!LSI->GLTemplateParameterList && !LSI->TemplateParams.empty()) {
236236
LSI->GLTemplateParameterList = TemplateParameterList::Create(
237237
SemaRef.Context,
238-
/*Template kw loc*/ SourceLocation(),
238+
/*Begin loc of the lambda expression*/ LSI->IntroducerRange.getBegin(),
239239
/*L angle loc*/ LSI->ExplicitTemplateParamsRange.getBegin(),
240240
LSI->TemplateParams,
241-
/*R angle loc*/LSI->ExplicitTemplateParamsRange.getEnd(),
241+
/*R angle loc*/ LSI->ExplicitTemplateParamsRange.getEnd(),
242242
LSI->RequiresClause.get());
243243
}
244244
return LSI->GLTemplateParameterList;

clang/test/AST/ast-dump-record-definition-data-json.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,11 @@ struct DoesNotAllowConstDefaultInit {
408408
// CHECK-NEXT: "tokLen": 1
409409
// CHECK-NEXT: },
410410
// CHECK-NEXT: "range": {
411-
// CHECK-NEXT: "begin": {},
411+
// CHECK-NEXT: "begin": {
412+
// CHECK-NEXT: "offset": 190,
413+
// CHECK-NEXT: "col": 26,
414+
// CHECK-NEXT: "tokLen": 1
415+
// CHECK-NEXT: },
412416
// CHECK-NEXT: "end": {
413417
// CHECK-NEXT: "offset": 199,
414418
// CHECK-NEXT: "col": 35,
@@ -523,7 +527,11 @@ struct DoesNotAllowConstDefaultInit {
523527
// CHECK-NEXT: "tokLen": 1
524528
// CHECK-NEXT: },
525529
// CHECK-NEXT: "range": {
526-
// CHECK-NEXT: "begin": {},
530+
// CHECK-NEXT: "begin": {
531+
// CHECK-NEXT: "offset": 190,
532+
// CHECK-NEXT: "col": 26,
533+
// CHECK-NEXT: "tokLen": 1
534+
// CHECK-NEXT: },
527535
// CHECK-NEXT: "end": {
528536
// CHECK-NEXT: "offset": 199,
529537
// CHECK-NEXT: "col": 35,
@@ -598,7 +606,11 @@ struct DoesNotAllowConstDefaultInit {
598606
// CHECK-NEXT: "tokLen": 1
599607
// CHECK-NEXT: },
600608
// CHECK-NEXT: "range": {
601-
// CHECK-NEXT: "begin": {},
609+
// CHECK-NEXT: "begin": {
610+
// CHECK-NEXT: "offset": 190,
611+
// CHECK-NEXT: "col": 26,
612+
// CHECK-NEXT: "tokLen": 1
613+
// CHECK-NEXT: },
602614
// CHECK-NEXT: "end": {
603615
// CHECK-NEXT: "offset": 199,
604616
// CHECK-NEXT: "col": 35,

0 commit comments

Comments
 (0)