mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Merge pull request #5854 from dbartol/dbartol/smart-pointers/side-effects
C++: Generate side effect instructions for smart pointer indirections
This commit is contained in:
@@ -416,3 +416,46 @@ predicate addressOperandAllocationAndOffset(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicates used only for printing annotated IR dumps. These should not be used in production
|
||||
* queries.
|
||||
*/
|
||||
module Print {
|
||||
string getOperandProperty(Operand operand, string key) {
|
||||
key = "alloc" and
|
||||
result =
|
||||
strictconcat(Configuration::Allocation allocation, IntValue bitOffset |
|
||||
addressOperandAllocationAndOffset(operand, allocation, bitOffset)
|
||||
|
|
||||
allocation.toString() + Ints::getBitOffsetString(bitOffset), ", "
|
||||
)
|
||||
or
|
||||
key = "prop" and
|
||||
result =
|
||||
strictconcat(Instruction destInstr, IntValue bitOffset, string value |
|
||||
operandIsPropagatedIncludingByCall(operand, bitOffset, destInstr) and
|
||||
if destInstr = operand.getUse()
|
||||
then value = "@" + Ints::getBitOffsetString(bitOffset) + "->result"
|
||||
else value = "@" + Ints::getBitOffsetString(bitOffset) + "->" + destInstr.getResultId()
|
||||
|
|
||||
value, ", "
|
||||
)
|
||||
}
|
||||
|
||||
string getInstructionProperty(Instruction instr, string key) {
|
||||
key = "prop" and
|
||||
result =
|
||||
strictconcat(IntValue bitOffset, Operand sourceOperand, string value |
|
||||
operandIsPropagatedIncludingByCall(sourceOperand, bitOffset, instr) and
|
||||
if instr = sourceOperand.getUse()
|
||||
then value = sourceOperand.getDumpId() + Ints::getBitOffsetString(bitOffset) + "->@"
|
||||
else
|
||||
value =
|
||||
sourceOperand.getUse().getResultId() + "." + sourceOperand.getDumpId() +
|
||||
Ints::getBitOffsetString(bitOffset) + "->@"
|
||||
|
|
||||
value, ", "
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Include this module to annotate IR dumps with information computed by `AliasAnalysis.qll`.
|
||||
*/
|
||||
|
||||
private import AliasAnalysisInternal
|
||||
private import InputIR
|
||||
private import AliasAnalysisImports
|
||||
private import AliasAnalysis
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant
|
||||
|
||||
private class AliasPropertyProvider extends IRPropertyProvider {
|
||||
override string getOperandProperty(Operand operand, string key) {
|
||||
result = Print::getOperandProperty(operand, key)
|
||||
}
|
||||
|
||||
override string getInstructionProperty(Instruction instr, string key) {
|
||||
result = Print::getInstructionProperty(instr, key)
|
||||
}
|
||||
}
|
||||
@@ -1073,7 +1073,10 @@ module SSAConsistency {
|
||||
locationCount > 1 and
|
||||
func = operand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction()) and
|
||||
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
|
||||
message =
|
||||
operand.getUse().toString() + " " + "Operand has " + locationCount.toString() +
|
||||
" memory accesses in function '$@': " +
|
||||
strictconcat(Alias::getOperandMemoryLocation(operand).toString(), ", ")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.Opcode
|
||||
private import semmle.code.cpp.models.interfaces.PointerWrapper
|
||||
private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
|
||||
/**
|
||||
@@ -39,7 +40,8 @@ private predicate hasDefaultSideEffect(Call call, ParameterIndex i, boolean buff
|
||||
exists(Type t | t = expr.getUnspecifiedType() |
|
||||
t instanceof ArrayType or
|
||||
t instanceof PointerType or
|
||||
t instanceof ReferenceType
|
||||
t instanceof ReferenceType or
|
||||
t instanceof PointerWrapper
|
||||
) and
|
||||
(
|
||||
isWrite = true and
|
||||
|
||||
@@ -416,3 +416,46 @@ predicate addressOperandAllocationAndOffset(
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Predicates used only for printing annotated IR dumps. These should not be used in production
|
||||
* queries.
|
||||
*/
|
||||
module Print {
|
||||
string getOperandProperty(Operand operand, string key) {
|
||||
key = "alloc" and
|
||||
result =
|
||||
strictconcat(Configuration::Allocation allocation, IntValue bitOffset |
|
||||
addressOperandAllocationAndOffset(operand, allocation, bitOffset)
|
||||
|
|
||||
allocation.toString() + Ints::getBitOffsetString(bitOffset), ", "
|
||||
)
|
||||
or
|
||||
key = "prop" and
|
||||
result =
|
||||
strictconcat(Instruction destInstr, IntValue bitOffset, string value |
|
||||
operandIsPropagatedIncludingByCall(operand, bitOffset, destInstr) and
|
||||
if destInstr = operand.getUse()
|
||||
then value = "@" + Ints::getBitOffsetString(bitOffset) + "->result"
|
||||
else value = "@" + Ints::getBitOffsetString(bitOffset) + "->" + destInstr.getResultId()
|
||||
|
|
||||
value, ", "
|
||||
)
|
||||
}
|
||||
|
||||
string getInstructionProperty(Instruction instr, string key) {
|
||||
key = "prop" and
|
||||
result =
|
||||
strictconcat(IntValue bitOffset, Operand sourceOperand, string value |
|
||||
operandIsPropagatedIncludingByCall(sourceOperand, bitOffset, instr) and
|
||||
if instr = sourceOperand.getUse()
|
||||
then value = sourceOperand.getDumpId() + Ints::getBitOffsetString(bitOffset) + "->@"
|
||||
else
|
||||
value =
|
||||
sourceOperand.getUse().getResultId() + "." + sourceOperand.getDumpId() +
|
||||
Ints::getBitOffsetString(bitOffset) + "->@"
|
||||
|
|
||||
value, ", "
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Include this module to annotate IR dumps with information computed by `AliasAnalysis.qll`.
|
||||
*/
|
||||
|
||||
private import AliasAnalysisInternal
|
||||
private import InputIR
|
||||
private import AliasAnalysisImports
|
||||
private import AliasAnalysis
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant
|
||||
|
||||
private class AliasPropertyProvider extends IRPropertyProvider {
|
||||
override string getOperandProperty(Operand operand, string key) {
|
||||
result = Print::getOperandProperty(operand, key)
|
||||
}
|
||||
|
||||
override string getInstructionProperty(Instruction instr, string key) {
|
||||
result = Print::getInstructionProperty(instr, key)
|
||||
}
|
||||
}
|
||||
@@ -1073,7 +1073,10 @@ module SSAConsistency {
|
||||
locationCount > 1 and
|
||||
func = operand.getEnclosingIRFunction() and
|
||||
funcText = Language::getIdentityString(func.getFunction()) and
|
||||
message = "Operand has " + locationCount.toString() + " memory accesses in function '$@'."
|
||||
message =
|
||||
operand.getUse().toString() + " " + "Operand has " + locationCount.toString() +
|
||||
" memory accesses in function '$@': " +
|
||||
strictconcat(Alias::getOperandMemoryLocation(operand).toString(), ", ")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -157,11 +157,11 @@ private class SmartPtrSetterFunction extends MemberFunction, AliasFunction, Side
|
||||
// parameter.
|
||||
result.isParameter(1)
|
||||
else result.isParameterDeref(0)
|
||||
or
|
||||
// One of the functions that takes ownership of a raw pointer.
|
||||
param0.getUnspecifiedType() instanceof PointerType and
|
||||
result.isParameter(0)
|
||||
)
|
||||
or
|
||||
// One of the functions that takes ownership of a raw pointer.
|
||||
param0.getUnspecifiedType() instanceof PointerType and
|
||||
result.isParameter(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11365,6 +11365,86 @@ perf-regression.cpp:
|
||||
# 12| Type = [IntType] int
|
||||
# 12| Value = [Literal] 0
|
||||
# 12| ValueCategory = prvalue
|
||||
smart_ptr.cpp:
|
||||
# 8| [TopLevelFunction] void unique_ptr_arg(std::unique_ptr<int, std::default_delete<int>>)
|
||||
# 8| <params>:
|
||||
# 8| getParameter(0): [Parameter] up
|
||||
# 8| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
|
||||
# 10| [TopLevelFunction] void call_unique_ptr_arg(int*)
|
||||
# 10| <params>:
|
||||
# 10| getParameter(0): [Parameter] p
|
||||
# 10| Type = [IntPointerType] int *
|
||||
# 10| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 11| getStmt(0): [DeclStmt] declaration
|
||||
# 11| getDeclarationEntry(0): [VariableDeclarationEntry] definition of up
|
||||
# 11| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
|
||||
# 11| getVariable().getInitializer(): [Initializer] initializer for up
|
||||
# 11| getExpr(): [ConstructorCall] call to unique_ptr
|
||||
# 11| Type = [VoidType] void
|
||||
# 11| ValueCategory = prvalue
|
||||
# 11| getArgument(0): [VariableAccess] p
|
||||
# 11| Type = [IntPointerType] int *
|
||||
# 11| ValueCategory = prvalue(load)
|
||||
# 12| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 12| getExpr(): [FunctionCall] call to unique_ptr_arg
|
||||
# 12| Type = [VoidType] void
|
||||
# 12| ValueCategory = prvalue
|
||||
# 12| getArgument(0): [FunctionCall] call to move
|
||||
# 12| Type = [RValueReferenceType] type &&
|
||||
# 12| ValueCategory = prvalue
|
||||
# 12| getArgument(0): [VariableAccess] up
|
||||
# 12| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
|
||||
# 12| ValueCategory = lvalue
|
||||
# 12| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 12| Type = [LValueReferenceType] unique_ptr<int, default_delete<int>> &
|
||||
# 12| ValueCategory = prvalue
|
||||
# 12| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 12| Type = [ClassTemplateInstantiation] unique_ptr<int, default_delete<int>>
|
||||
# 12| ValueCategory = lvalue
|
||||
# 12| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 12| Type = [CTypedefType,NestedTypedefType] type
|
||||
# 12| ValueCategory = prvalue(load)
|
||||
# 13| getStmt(2): [ReturnStmt] return ...
|
||||
# 15| [TopLevelFunction] void shared_ptr_arg(std::shared_ptr<float>)
|
||||
# 15| <params>:
|
||||
# 15| getParameter(0): [Parameter] sp
|
||||
# 15| Type = [ClassTemplateInstantiation] shared_ptr<float>
|
||||
# 17| [TopLevelFunction] void call_shared_ptr_arg(float*)
|
||||
# 17| <params>:
|
||||
# 17| getParameter(0): [Parameter] p
|
||||
# 17| Type = [PointerType] float *
|
||||
# 17| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 18| getStmt(0): [DeclStmt] declaration
|
||||
# 18| getDeclarationEntry(0): [VariableDeclarationEntry] definition of sp
|
||||
# 18| Type = [ClassTemplateInstantiation] shared_ptr<float>
|
||||
# 18| getVariable().getInitializer(): [Initializer] initializer for sp
|
||||
# 18| getExpr(): [ConstructorCall] call to shared_ptr
|
||||
# 18| Type = [VoidType] void
|
||||
# 18| ValueCategory = prvalue
|
||||
# 18| getArgument(0): [VariableAccess] p
|
||||
# 18| Type = [PointerType] float *
|
||||
# 18| ValueCategory = prvalue(load)
|
||||
# 19| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 19| getExpr(): [FunctionCall] call to shared_ptr_arg
|
||||
# 19| Type = [VoidType] void
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getArgument(0): [ConstructorCall] call to shared_ptr
|
||||
# 19| Type = [VoidType] void
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getArgument(0): [VariableAccess] sp
|
||||
# 19| Type = [ClassTemplateInstantiation] shared_ptr<float>
|
||||
# 19| ValueCategory = lvalue
|
||||
# 19| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 19| Type = [LValueReferenceType] const shared_ptr<float> &
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getExpr(): [CStyleCast] (const shared_ptr<float>)...
|
||||
# 19| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 19| Type = [SpecifiedType] const shared_ptr<float>
|
||||
# 19| ValueCategory = lvalue
|
||||
# 19| getArgument(0).getFullyConverted(): [TemporaryObjectExpr] temporary object
|
||||
# 19| Type = [ClassTemplateInstantiation] shared_ptr<float>
|
||||
# 19| ValueCategory = lvalue
|
||||
# 20| getStmt(2): [ReturnStmt] return ...
|
||||
struct_init.cpp:
|
||||
# 1| [TopLevelFunction] int handler1(void*)
|
||||
# 1| <params>:
|
||||
|
||||
11
cpp/ql/test/library-tests/ir/ir/PrintAST.ql
Normal file
11
cpp/ql/test/library-tests/ir/ir/PrintAST.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.PrintAST
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintASTConfiguration {
|
||||
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
semmle/code/cpp/PrintAST.ql
|
||||
10
cpp/ql/test/library-tests/ir/ir/PrintConfig.qll
Normal file
10
cpp/ql/test/library-tests/ir/ir/PrintConfig.qll
Normal file
@@ -0,0 +1,10 @@
|
||||
private import cpp
|
||||
|
||||
/**
|
||||
* Holds if the AST or IR for the specified function should be printed in the test output.
|
||||
*
|
||||
* This predicate excludes functions defined in standard headers.
|
||||
*/
|
||||
predicate shouldDumpFunction(Function func) {
|
||||
not func.getLocation().getFile().getAbsolutePath().regexpMatch(".*/include/[^/]+")
|
||||
}
|
||||
@@ -6,6 +6,7 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -7903,6 +7903,80 @@ perf-regression.cpp:
|
||||
# 9| v9_6(void) = AliasedUse : ~m?
|
||||
# 9| v9_7(void) = ExitFunction :
|
||||
|
||||
smart_ptr.cpp:
|
||||
# 10| void call_unique_ptr_arg(int*)
|
||||
# 10| Block 0
|
||||
# 10| v10_1(void) = EnterFunction :
|
||||
# 10| mu10_2(unknown) = AliasedDefinition :
|
||||
# 10| mu10_3(unknown) = InitializeNonLocal :
|
||||
# 10| r10_4(glval<int *>) = VariableAddress[p] :
|
||||
# 10| mu10_5(int *) = InitializeParameter[p] : &:r10_4
|
||||
# 10| r10_6(int *) = Load[p] : &:r10_4, ~m?
|
||||
# 10| mu10_7(unknown) = InitializeIndirection[p] : &:r10_6
|
||||
# 11| r11_1(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[up] :
|
||||
# 11| mu11_2(unique_ptr<int, default_delete<int>>) = Uninitialized[up] : &:r11_1
|
||||
# 11| r11_3(glval<unknown>) = FunctionAddress[unique_ptr] :
|
||||
# 11| r11_4(glval<int *>) = VariableAddress[p] :
|
||||
# 11| r11_5(int *) = Load[p] : &:r11_4, ~m?
|
||||
# 11| v11_6(void) = Call[unique_ptr] : func:r11_3, this:r11_1, 0:r11_5
|
||||
# 11| mu11_7(unknown) = ^CallSideEffect : ~m?
|
||||
# 11| mu11_8(unique_ptr<int, default_delete<int>>) = ^IndirectMustWriteSideEffect[-1] : &:r11_1
|
||||
# 12| r12_1(glval<unknown>) = FunctionAddress[unique_ptr_arg] :
|
||||
# 12| r12_2(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[#temp12:20] :
|
||||
# 12| r12_3(glval<unknown>) = FunctionAddress[move] :
|
||||
# 12| r12_4(glval<unique_ptr<int, default_delete<int>>>) = VariableAddress[up] :
|
||||
# 12| r12_5(unique_ptr<int, default_delete<int>> &) = CopyValue : r12_4
|
||||
# 12| r12_6(unique_ptr<int, default_delete<int>> &&) = Call[move] : func:r12_3, 0:r12_5
|
||||
# 12| r12_7(unique_ptr<int, default_delete<int>>) = Load[?] : &:r12_6, ~m?
|
||||
# 12| mu12_8(unique_ptr<int, default_delete<int>>) = Store[#temp12:20] : &:r12_2, r12_7
|
||||
# 12| r12_9(unique_ptr<int, default_delete<int>>) = Load[#temp12:20] : &:r12_2, ~m?
|
||||
# 12| v12_10(void) = Call[unique_ptr_arg] : func:r12_1, 0:r12_9
|
||||
# 12| mu12_11(unknown) = ^CallSideEffect : ~m?
|
||||
# 12| v12_12(void) = ^BufferReadSideEffect[0] : &:r12_9, ~m?
|
||||
# 13| v13_1(void) = NoOp :
|
||||
# 10| v10_8(void) = ReturnIndirection[p] : &:r10_6, ~m?
|
||||
# 10| v10_9(void) = ReturnVoid :
|
||||
# 10| v10_10(void) = AliasedUse : ~m?
|
||||
# 10| v10_11(void) = ExitFunction :
|
||||
|
||||
# 17| void call_shared_ptr_arg(float*)
|
||||
# 17| Block 0
|
||||
# 17| v17_1(void) = EnterFunction :
|
||||
# 17| mu17_2(unknown) = AliasedDefinition :
|
||||
# 17| mu17_3(unknown) = InitializeNonLocal :
|
||||
# 17| r17_4(glval<float *>) = VariableAddress[p] :
|
||||
# 17| mu17_5(float *) = InitializeParameter[p] : &:r17_4
|
||||
# 17| r17_6(float *) = Load[p] : &:r17_4, ~m?
|
||||
# 17| mu17_7(unknown) = InitializeIndirection[p] : &:r17_6
|
||||
# 18| r18_1(glval<shared_ptr<float>>) = VariableAddress[sp] :
|
||||
# 18| mu18_2(shared_ptr<float>) = Uninitialized[sp] : &:r18_1
|
||||
# 18| r18_3(glval<unknown>) = FunctionAddress[shared_ptr] :
|
||||
# 18| r18_4(glval<float *>) = VariableAddress[p] :
|
||||
# 18| r18_5(float *) = Load[p] : &:r18_4, ~m?
|
||||
# 18| v18_6(void) = Call[shared_ptr] : func:r18_3, this:r18_1, 0:r18_5
|
||||
# 18| mu18_7(unknown) = ^CallSideEffect : ~m?
|
||||
# 18| mu18_8(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r18_1
|
||||
# 19| r19_1(glval<unknown>) = FunctionAddress[shared_ptr_arg] :
|
||||
# 19| r19_2(glval<shared_ptr<float>>) = VariableAddress[#temp19:20] :
|
||||
# 19| mu19_3(shared_ptr<float>) = Uninitialized[#temp19:20] : &:r19_2
|
||||
# 19| r19_4(glval<unknown>) = FunctionAddress[shared_ptr] :
|
||||
# 19| r19_5(glval<shared_ptr<float>>) = VariableAddress[sp] :
|
||||
# 19| r19_6(glval<shared_ptr<float>>) = Convert : r19_5
|
||||
# 19| r19_7(shared_ptr<float> &) = CopyValue : r19_6
|
||||
# 19| v19_8(void) = Call[shared_ptr] : func:r19_4, this:r19_2, 0:r19_7
|
||||
# 19| mu19_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 19| mu19_10(shared_ptr<float>) = ^IndirectMustWriteSideEffect[-1] : &:r19_2
|
||||
# 19| v19_11(void) = ^IndirectReadSideEffect[0] : &:r19_7, ~m?
|
||||
# 19| r19_12(shared_ptr<float>) = Load[#temp19:20] : &:r19_2, ~m?
|
||||
# 19| v19_13(void) = Call[shared_ptr_arg] : func:r19_1, 0:r19_12
|
||||
# 19| mu19_14(unknown) = ^CallSideEffect : ~m?
|
||||
# 19| v19_15(void) = ^BufferReadSideEffect[0] : &:r19_12, ~m?
|
||||
# 20| v20_1(void) = NoOp :
|
||||
# 17| v17_8(void) = ReturnIndirection[p] : &:r17_6, ~m?
|
||||
# 17| v17_9(void) = ReturnVoid :
|
||||
# 17| v17_10(void) = AliasedUse : ~m?
|
||||
# 17| v17_11(void) = ExitFunction :
|
||||
|
||||
struct_init.cpp:
|
||||
# 16| void let_info_escape(Info*)
|
||||
# 16| Block 0
|
||||
|
||||
11
cpp/ql/test/library-tests/ir/ir/raw_ir.ql
Normal file
11
cpp/ql/test/library-tests/ir/ir/raw_ir.ql
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* @kind graph
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.implementation.raw.PrintIR
|
||||
private import PrintConfig
|
||||
|
||||
private class PrintConfig extends PrintIRConfiguration {
|
||||
override predicate shouldPrintFunction(Function func) { shouldDumpFunction(func) }
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
semmle/code/cpp/ir/implementation/raw/PrintIR.ql
|
||||
20
cpp/ql/test/library-tests/ir/ir/smart_ptr.cpp
Normal file
20
cpp/ql/test/library-tests/ir/ir/smart_ptr.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "../../../include/memory.h"
|
||||
#include "../../../include/utility.h"
|
||||
|
||||
using std::move;
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
void unique_ptr_arg(unique_ptr<int> up);
|
||||
|
||||
void call_unique_ptr_arg(int* p) {
|
||||
unique_ptr<int> up(p);
|
||||
unique_ptr_arg(move(up));
|
||||
}
|
||||
|
||||
void shared_ptr_arg(shared_ptr<float> sp);
|
||||
|
||||
void call_shared_ptr_arg(float* p) {
|
||||
shared_ptr<float> sp(p);
|
||||
shared_ptr_arg(sp);
|
||||
}
|
||||
Reference in New Issue
Block a user