Skip to content

Commit 5b00b21

Browse files
authored
Merge pull request #2153 from matt-gretton-dann/cpp-447-support-non-type-template-parameters
RFC: C++ Support non type template parameter values
2 parents 47a292b + 20ae183 commit 5b00b21

File tree

27 files changed

+9474
-4842
lines changed

27 files changed

+9474
-4842
lines changed

change-notes/1.23/analysis-cpp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,8 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
5454
lead to regressions (or improvements) in how queries are optimized because
5555
optimization in QL relies on static size estimates, and the control-flow edge
5656
relations will now have different size estimates than before.
57+
* Support has been added for non-type template arguments. This means that the
58+
return type of `Declaration::getTemplateArgument()` and
59+
`Declaration::getATemplateArgument` have changed to `Locatable`. See the
60+
documentation for `Declaration::getTemplateArgument()` and
61+
`Declaration::getTemplateArgumentKind()` for details.

cpp/ql/src/semmle/code/cpp/Class.qll

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -605,15 +605,6 @@ class Class extends UserType {
605605
class_instantiation(underlyingElement(this), unresolveElement(c))
606606
}
607607

608-
/**
609-
* Gets the `i`th template argument used to instantiate this class from a
610-
* class template. When called on a class template, this will return the
611-
* `i`th template parameter.
612-
*/
613-
override Type getTemplateArgument(int i) {
614-
class_template_argument(underlyingElement(this), i, unresolveElement(result))
615-
}
616-
617608
/**
618609
* Holds if this class/struct is polymorphic (has a virtual function, or
619610
* inherits one).
@@ -623,7 +614,7 @@ class Class extends UserType {
623614
}
624615

625616
override predicate involvesTemplateParameter() {
626-
getATemplateArgument().involvesTemplateParameter()
617+
getATemplateArgument().(Type).involvesTemplateParameter()
627618
}
628619

629620
/** Holds if this class, struct or union was declared 'final'. */

cpp/ql/src/semmle/code/cpp/Declaration.qll

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,20 +193,83 @@ abstract class Declaration extends Locatable, @declaration {
193193

194194
/**
195195
* Gets a template argument used to instantiate this declaration from a template.
196-
* When called on a template, this will return a template parameter.
196+
* When called on a template, this will return a template parameter type for
197+
* both typed and non-typed parameters.
197198
*/
198-
final Type getATemplateArgument() { result = getTemplateArgument(_) }
199+
final Locatable getATemplateArgument() { result = getTemplateArgument(_) }
200+
201+
/**
202+
* Gets a template argument used to instantiate this declaration from a template.
203+
* When called on a template, this will return a non-typed template
204+
* parameter value.
205+
*/
206+
final Locatable getATemplateArgumentKind() { result = getTemplateArgumentKind(_) }
199207

200208
/**
201209
* Gets the `i`th template argument used to instantiate this declaration from a
202-
* template. When called on a template, this will return the `i`th template parameter.
210+
* template.
211+
*
212+
* For example:
213+
*
214+
* `template<typename T, T X> class Foo;`
215+
*
216+
* Will have `getTemplateArgument(0)` return `T`, and
217+
* `getTemplateArgument(1)` return `X`.
218+
*
219+
* `Foo<int, 1> bar;
220+
*
221+
* Will have `getTemplateArgument())` return `int`, and
222+
* `getTemplateArgument(1)` return `1`.
203223
*/
204-
Type getTemplateArgument(int index) { none() }
224+
final Locatable getTemplateArgument(int index) {
225+
if exists(getTemplateArgumentValue(index))
226+
then result = getTemplateArgumentValue(index)
227+
else result = getTemplateArgumentType(index)
228+
}
229+
230+
/**
231+
* Gets the `i`th template argument value used to instantiate this declaration
232+
* from a template. When called on a template, this will return the `i`th template
233+
* parameter value if it exists.
234+
*
235+
* For example:
236+
*
237+
* `template<typename T, T X> class Foo;`
238+
*
239+
* Will have `getTemplateArgumentKind(1)` return `T`, and no result for
240+
* `getTemplateArgumentKind(0)`.
241+
*
242+
* `Foo<int, 10> bar;
243+
*
244+
* Will have `getTemplateArgumentKind(1)` return `int`, and no result for
245+
* `getTemplateArgumentKind(0)`.
246+
*/
247+
final Locatable getTemplateArgumentKind(int index) {
248+
if exists(getTemplateArgumentValue(index))
249+
then result = getTemplateArgumentType(index)
250+
else none()
251+
}
205252

206253
/** Gets the number of template arguments for this declaration. */
207254
final int getNumberOfTemplateArguments() {
208255
result = count(int i | exists(getTemplateArgument(i)))
209256
}
257+
258+
private Type getTemplateArgumentType(int index) {
259+
class_template_argument(underlyingElement(this), index, unresolveElement(result))
260+
or
261+
function_template_argument(underlyingElement(this), index, unresolveElement(result))
262+
or
263+
variable_template_argument(underlyingElement(this), index, unresolveElement(result))
264+
}
265+
266+
private Expr getTemplateArgumentValue(int index) {
267+
class_template_argument_value(underlyingElement(this), index, unresolveElement(result))
268+
or
269+
function_template_argument_value(underlyingElement(this), index, unresolveElement(result))
270+
or
271+
variable_template_argument_value(underlyingElement(this), index, unresolveElement(result))
272+
}
210273
}
211274

212275
/**

cpp/ql/src/semmle/code/cpp/Function.qll

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -343,15 +343,6 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
343343
function_instantiation(underlyingElement(this), unresolveElement(f))
344344
}
345345

346-
/**
347-
* Gets the `i`th template argument used to instantiate this function from a
348-
* function template. When called on a function template, this will return the
349-
* `i`th template parameter.
350-
*/
351-
override Type getTemplateArgument(int index) {
352-
function_template_argument(underlyingElement(this), index, unresolveElement(result))
353-
}
354-
355346
/**
356347
* Holds if this function is defined in several files. This is illegal in
357348
* C (though possible in some C++ compilers), and likely indicates that

cpp/ql/src/semmle/code/cpp/Print.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ private string getParameterTypeString(Type parameterType) {
3535
else result = parameterType.(DumpType).getTypeIdentityString()
3636
}
3737

38+
private string getTemplateArgumentString(Declaration d, int i) {
39+
if exists(d.getTemplateArgumentKind(i))
40+
then
41+
result = d.getTemplateArgumentKind(i).(DumpType).getTypeIdentityString() + " " +
42+
d.getTemplateArgument(i)
43+
else result = d.getTemplateArgument(i).(DumpType).getTypeIdentityString()
44+
}
45+
3846
/**
3947
* A `Declaration` extended to add methods for generating strings useful only for dumps and debugging.
4048
*/
@@ -56,7 +64,7 @@ abstract private class DumpDeclaration extends Declaration {
5664
strictconcat(int i |
5765
exists(this.getTemplateArgument(i))
5866
|
59-
this.getTemplateArgument(i).(DumpType).getTypeIdentityString(), ", " order by i
67+
getTemplateArgumentString(this, i), ", " order by i
6068
) + ">"
6169
else result = ""
6270
}

cpp/ql/src/semmle/code/cpp/Type.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ class Type extends Locatable, @type {
210210
// A function call that provides an explicit template argument that refers to T uses T.
211211
// We exclude calls within instantiations, since they do not appear directly in the source.
212212
exists(FunctionCall c |
213-
c.getAnExplicitTemplateArgument().refersTo(this) and
213+
c.getAnExplicitTemplateArgument().(Type).refersTo(this) and
214214
result = c and
215215
not c.getEnclosingFunction().isConstructedFrom(_)
216216
)

cpp/ql/src/semmle/code/cpp/Variable.qll

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,6 @@ class Variable extends Declaration, @variable {
155155
variable_instantiation(underlyingElement(this), unresolveElement(v))
156156
}
157157

158-
/**
159-
* Gets the `i`th template argument used to instantiate this variable from a
160-
* variable template. When called on a variable template, this will return the
161-
* `i`th template parameter.
162-
*/
163-
override Type getTemplateArgument(int index) {
164-
variable_template_argument(underlyingElement(this), index, unresolveElement(result))
165-
}
166-
167158
/**
168159
* Holds if this is a compiler-generated variable. For example, a
169160
* [range-based for loop](http://en.cppreference.com/w/cpp/language/range-for)

cpp/ql/src/semmle/code/cpp/exprs/Call.qll

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,17 +139,29 @@ class FunctionCall extends Call, @funbindexpr {
139139
override string getCanonicalQLClass() { result = "FunctionCall" }
140140

141141
/** Gets an explicit template argument for this call. */
142-
Type getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
142+
Locatable getAnExplicitTemplateArgument() { result = getExplicitTemplateArgument(_) }
143+
144+
/** Gets an explicit template argument value for this call. */
145+
Locatable getAnExplicitTemplateArgumentKind() { result = getExplicitTemplateArgumentKind(_) }
143146

144147
/** Gets a template argument for this call. */
145-
Type getATemplateArgument() { result = getTarget().getATemplateArgument() }
148+
Locatable getATemplateArgument() { result = getTarget().getATemplateArgument() }
149+
150+
/** Gets a template argument value for this call. */
151+
Locatable getATemplateArgumentKind() { result = getTarget().getATemplateArgumentKind() }
146152

147153
/** Gets the nth explicit template argument for this call. */
148-
Type getExplicitTemplateArgument(int n) {
154+
Locatable getExplicitTemplateArgument(int n) {
149155
n < getNumberOfExplicitTemplateArguments() and
150156
result = getTemplateArgument(n)
151157
}
152158

159+
/** Gets the nth explicit template argument value for this call. */
160+
Locatable getExplicitTemplateArgumentKind(int n) {
161+
n < getNumberOfExplicitTemplateArguments() and
162+
result = getTemplateArgumentKind(n)
163+
}
164+
153165
/** Gets the number of explicit template arguments for this call. */
154166
int getNumberOfExplicitTemplateArguments() {
155167
if numtemplatearguments(underlyingElement(this), _)
@@ -161,7 +173,10 @@ class FunctionCall extends Call, @funbindexpr {
161173
int getNumberOfTemplateArguments() { result = count(int i | exists(getTemplateArgument(i))) }
162174

163175
/** Gets the nth template argument for this call (indexed from 0). */
164-
Type getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
176+
Locatable getTemplateArgument(int n) { result = getTarget().getTemplateArgument(n) }
177+
178+
/** Gets the nth template argument value for this call (indexed from 0). */
179+
Locatable getTemplateArgumentKind(int n) { result = getTarget().getTemplateArgumentKind(n) }
165180

166181
/** Holds if any template arguments for this call are implicit / deduced. */
167182
predicate hasImplicitTemplateArguments() {

cpp/ql/src/semmlecode.cpp.dbscheme

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,11 @@ class_template_argument(
731731
int index: int ref,
732732
int arg_type: @type ref
733733
);
734+
class_template_argument_value(
735+
int type_id: @usertype ref,
736+
int index: int ref,
737+
int arg_value: @expr ref
738+
);
734739

735740
is_proxy_class_for(
736741
unique int id: @usertype ref,
@@ -755,6 +760,11 @@ function_template_argument(
755760
int index: int ref,
756761
int arg_type: @type ref
757762
);
763+
function_template_argument_value(
764+
int function_id: @function ref,
765+
int index: int ref,
766+
int arg_value: @expr ref
767+
);
758768

759769
is_variable_template(unique int id: @variable ref);
760770
variable_instantiation(
@@ -766,6 +776,11 @@ variable_template_argument(
766776
int index: int ref,
767777
int arg_type: @type ref
768778
);
779+
variable_template_argument_value(
780+
int variable_id: @variable ref,
781+
int index: int ref,
782+
int arg_value: @expr ref
783+
);
769784

770785
/*
771786
Fixed point types

0 commit comments

Comments
 (0)