-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Disallow returning references to temporary values (#712)
- Loading branch information
1 parent
1ca0f5f
commit b459e27
Showing
14 changed files
with
314 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,50 +1,87 @@ | ||
import "std/data/vector"; | ||
import "std/test/lifetime-object"; | ||
|
||
import "bootstrap/util/common-util"; | ||
import "bootstrap/source-file-intf"; | ||
|
||
type MockSourceFile struct : ISourceFile { | ||
string fileName | ||
unsigned long lineCount = 0l | ||
f<LifetimeObject> spawnLO() { | ||
return LifetimeObject(); | ||
} | ||
|
||
p MockSourceFile.ctor(string fileName, unsigned long lineCount = 0l) { | ||
this.fileName = fileName; | ||
this.lineCount = lineCount; | ||
} | ||
f<int> main() { | ||
// Ignored return value of ctor | ||
printf("Ignored return value of ctor"); | ||
{ | ||
LifetimeObject(); | ||
} | ||
|
||
f<unsigned long> MockSourceFile.getLineCount() { | ||
return this.lineCount; | ||
} | ||
// Normal lifecycle | ||
printf("Normal lifecycle:\n"); | ||
{ | ||
LifetimeObject lo = LifetimeObject(); // ctor call | ||
LifetimeObject loCopy = lo; // copy ctor call | ||
} // dtor calls for both lo and loCopy at end of scope | ||
|
||
f<string> MockSourceFile.getFileName() { | ||
return this.fileName; | ||
} | ||
// Return from lambda as value | ||
printf("Return from lambda as value:\n"); | ||
{ | ||
const f<LifetimeObject>() spawnLO = f<LifetimeObject>() { | ||
return LifetimeObject(); | ||
}; | ||
|
||
f<int> main() { | ||
// getLastFragment | ||
String lastFragment = getLastFragment(String("this.is.a.test.haystack"), "."); | ||
printf("%s", lastFragment); | ||
assert lastFragment == "haystack"; | ||
lastFragment = getLastFragment(String(""), ";"); | ||
assert lastFragment == ""; | ||
lastFragment = getLastFragment(String("x-y-z-"), "-"); | ||
assert lastFragment == ""; | ||
// getCircularImportMessage | ||
const MockSourceFile msf1 = MockSourceFile("file1.spice", 1l); | ||
const MockSourceFile msf2 = MockSourceFile("file2.spice", 12l); | ||
const MockSourceFile msf3 = MockSourceFile("file3.spice", 123l); | ||
const MockSourceFile msf4 = MockSourceFile("file4.spice", 1234l); | ||
Vector<const ISourceFile*> sourceFiles; | ||
unsafe { | ||
sourceFiles.pushBack((const ISourceFile*) &msf1); | ||
sourceFiles.pushBack((const ISourceFile*) &msf2); | ||
sourceFiles.pushBack((const ISourceFile*) &msf3); | ||
sourceFiles.pushBack((const ISourceFile*) &msf4); | ||
// No return value receiver | ||
spawnLO(); // Anonymous symbol | ||
// Return value receiver - value | ||
LifetimeObject lo = spawnLO(); // Assigned to lo | ||
// Return value receiver - const ref | ||
const LifetimeObject& loConstRef = spawnLO(); // Assigned to loConstRef | ||
} | ||
|
||
// Return from lambda as reference | ||
printf("Return from lambda as reference:\n"); | ||
{ | ||
LifetimeObject loOrig = LifetimeObject(); | ||
const f<LifetimeObject&>() spawnLO = f<LifetimeObject&>() { | ||
return loOrig; | ||
}; | ||
|
||
// No return value receiver | ||
spawnLO(); // Anonymous symbol | ||
// Return value receiver - value | ||
LifetimeObject lo = spawnLO(); // Assigned to lo | ||
// Return value receiver - const ref | ||
const LifetimeObject& loConstRef = spawnLO(); // Assigned to loConstRef | ||
} | ||
|
||
// Return from lambda as const reference | ||
printf("Return from lambda as const reference:\n"); | ||
{ | ||
LifetimeObject loOrig = LifetimeObject(); | ||
const f<const LifetimeObject&>() spawnLO = f<const LifetimeObject&>() { | ||
return loOrig; | ||
}; | ||
|
||
// No return value receiver | ||
spawnLO(); // Anonymous symbol | ||
// Return value receiver - value | ||
LifetimeObject lo = spawnLO(); // Assigned to lo | ||
// Return value receiver - const ref | ||
const LifetimeObject& loConstRef = spawnLO(); // Assigned to loConstRef | ||
} | ||
|
||
// Return from function as value | ||
printf("Return from function as value:\n"); | ||
{ | ||
// No return value receiver | ||
spawnLO(); // Anonymous symbol | ||
// Return value receiver - value | ||
LifetimeObject lo = spawnLO(); // Assigned to lo | ||
// Return value receiver - const ref | ||
const LifetimeObject& loConstRef = spawnLO(); // Assigned to loConstRef | ||
} | ||
|
||
printf("Ternary\n"); | ||
{ | ||
bool cond = false; | ||
LifetimeObject lo1 = LifetimeObject(); | ||
LifetimeObject lo2 = LifetimeObject(); | ||
LifetimeObject lo3 = cond ? lo1 : lo2; | ||
// ToDo: The dtor of lo2 is called twice | ||
} | ||
const String cim = getCircularImportMessage(sourceFiles); | ||
printf("Circular error message:\n%s\n", cim); | ||
const String versionInfo = buildVersionInfo(); | ||
printf("Version info:\n%s\n", versionInfo); | ||
printf("All assertions passed!"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
unsigned int OBJECT_COUNTER = 0; | ||
|
||
/** | ||
* Object that prints to cout when one of its lifetime methods is called. | ||
* This is useful for language verification and debugging purposes. | ||
*/ | ||
public type LifetimeObject struct { | ||
int objectNumber | ||
bool ctorCalled = false | ||
bool copyCtorCalled = false | ||
bool dtorCalled = false | ||
} | ||
|
||
public p LifetimeObject.ctor(int objectNumber = ++OBJECT_COUNTER) { | ||
if this.ctorCalled { | ||
printf("-- LifetimeObject %d ctor was called again. This indicates a compiler bug. Please report it!\n", this.objectNumber); | ||
} | ||
this.objectNumber = objectNumber; | ||
this.ctorCalled = true; | ||
printf("-- LifetimeObject %d was created (ctor)\n", this.objectNumber); | ||
} | ||
|
||
public p LifetimeObject.ctor(const LifetimeObject& other) { | ||
if this.copyCtorCalled { | ||
printf("-- LifetimeObject %d copy ctor was called again. This indicates a compiler bug. Please report it!\n", this.objectNumber); | ||
} | ||
this.objectNumber = ++OBJECT_COUNTER; | ||
this.copyCtorCalled = true; | ||
printf("-- LifetimeObject %d was copied to LifetimeObject %d (copy ctor)\n", other.objectNumber, this.objectNumber); | ||
} | ||
|
||
public p LifetimeObject.dtor() { | ||
if this.dtorCalled { | ||
printf("-- LifetimeObject %d dtor was called again. This indicates a compiler bug. Please report it!\n", this.objectNumber); | ||
} | ||
this.dtorCalled = true; | ||
printf("-- LifetimeObject %d (dtor)\n", this.objectNumber); | ||
} |
1 change: 1 addition & 0 deletions
1
test/test-files/irgenerator/structs/success-destructors3/cout.out
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
defaulttest |
53 changes: 53 additions & 0 deletions
53
test/test-files/irgenerator/structs/success-destructors3/ir-code.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
; ModuleID = 'source.spice' | ||
source_filename = "source.spice" | ||
|
||
%struct.String = type { ptr, i64, i64 } | ||
|
||
@anon.string.0 = private unnamed_addr constant [8 x i8] c"default\00", align 1 | ||
@printf.str.0 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 | ||
@printf.str.1 = private unnamed_addr constant [3 x i8] c"%s\00", align 1 | ||
@anon.string.1 = private unnamed_addr constant [5 x i8] c"test\00", align 1 | ||
|
||
define private void @_Z4testv() { | ||
%1 = alloca %struct.String, align 8 | ||
%t = alloca ptr, align 8 | ||
call void @_ZN6String4ctorEPKc(ptr noundef nonnull align 8 dereferenceable(24) %1, ptr @anon.string.0) | ||
store ptr %1, ptr %t, align 8 | ||
%2 = load ptr, ptr %t, align 8 | ||
%3 = load ptr, ptr %2, align 8 | ||
%4 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.0, ptr %3) | ||
call void @_ZN6String4dtorEv(ptr %1) | ||
ret void | ||
} | ||
|
||
declare void @_ZN6String4ctorEPKc(ptr, ptr) | ||
|
||
; Function Attrs: nofree nounwind | ||
declare noundef i32 @printf(ptr nocapture noundef readonly, ...) #0 | ||
|
||
declare void @_ZN6String4dtorEv(ptr) | ||
|
||
define private void @_Z4testRK6String(ptr %0) { | ||
%t = alloca ptr, align 8 | ||
store ptr %0, ptr %t, align 8 | ||
%2 = load ptr, ptr %t, align 8 | ||
%3 = load ptr, ptr %2, align 8 | ||
%4 = call i32 (ptr, ...) @printf(ptr noundef @printf.str.1, ptr %3) | ||
ret void | ||
} | ||
|
||
; Function Attrs: noinline nounwind optnone uwtable | ||
define dso_local i32 @main() #1 { | ||
%result = alloca i32, align 4 | ||
%1 = alloca %struct.String, align 8 | ||
store i32 0, ptr %result, align 4 | ||
call void @_Z4testv() | ||
call void @_ZN6String4ctorEPKc(ptr noundef nonnull align 8 dereferenceable(24) %1, ptr @anon.string.1) | ||
call void @_Z4testRK6String(ptr %1) | ||
call void @_ZN6String4dtorEv(ptr %1) | ||
%2 = load i32, ptr %result, align 4 | ||
ret i32 %2 | ||
} | ||
|
||
attributes #0 = { nofree nounwind } | ||
attributes #1 = { noinline nounwind optnone uwtable } |
11 changes: 11 additions & 0 deletions
11
test/test-files/irgenerator/structs/success-destructors3/source.spice
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// This function generates two substantiations: One with the default value and one with the given value from | ||
// the caller. If the default value is used, it has to be destroyed at the end of the scope. Therefore, the | ||
// first substantiation calls the dtor and the second one not. | ||
p test(const String& t = String("default")) { | ||
printf("%s", t); | ||
} | ||
|
||
f<int> main() { | ||
test(); | ||
test(String("test")); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
Ignored return value of ctor: | ||
-- LifetimeObject 1 was created (ctor) | ||
-- LifetimeObject 1 (dtor) | ||
Normal lifecycle: | ||
-- LifetimeObject 2 was created (ctor) | ||
-- LifetimeObject 2 was copied to LifetimeObject 3 (copy ctor) | ||
-- LifetimeObject 3 (dtor) | ||
-- LifetimeObject 2 (dtor) | ||
Return from lambda as value: | ||
-- LifetimeObject 4 was created (ctor) | ||
-- LifetimeObject 5 was created (ctor) | ||
-- LifetimeObject 6 was created (ctor) | ||
-- LifetimeObject 6 (dtor) | ||
-- LifetimeObject 5 (dtor) | ||
-- LifetimeObject 4 (dtor) | ||
Return from lambda as reference: | ||
-- LifetimeObject 7 was created (ctor) | ||
-- LifetimeObject 7 (dtor) | ||
Return from lambda as const reference: | ||
-- LifetimeObject 8 was created (ctor) | ||
-- LifetimeObject 8 (dtor) | ||
Return from function as value: | ||
-- LifetimeObject 9 was created (ctor) | ||
-- LifetimeObject 10 was created (ctor) | ||
-- LifetimeObject 11 was created (ctor) | ||
-- LifetimeObject 11 (dtor) | ||
-- LifetimeObject 10 (dtor) | ||
-- LifetimeObject 9 (dtor) |
Oops, something went wrong.