New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enable parser to accept transient
as data location or identifier
#15001
base: develop
Are you sure you want to change the base?
Conversation
7bea970
to
c0ec00e
Compare
...ns/externalFunction/function_argument_location_specifier_test_external_transient_storage.sol
Outdated
Show resolved
Hide resolved
0293833
to
5edd9de
Compare
6e15e6c
to
b0e31af
Compare
test/libsolidity/syntaxTests/immutable/state_var_transient_data_location.sol
Outdated
Show resolved
Hide resolved
test/libsolidity/syntaxTests/dataLocations/transient_function_type.sol
Outdated
Show resolved
Hide resolved
test/libsolidity/syntaxTests/constants/constant_transient_state_variable.sol
Outdated
Show resolved
Hide resolved
Just realized that it's also missing a changelog entry. Is it because it's considered experimental at this point? |
I guess I always forget about the changelog entry 😅 |
Well, it's actually a good question whether it should have an entry. The feature is not really usable to users in the current state so not much point advertising it. On the other hand we do include an entry when an experimental feature is introduced (just not when we change it), so maybe we should still have it. Also, it's not so much experimental as just incomplete... |
29e04e2
to
9064a16
Compare
b8174b5
to
dbdbb33
Compare
f222839
to
aff3909
Compare
test/libsolidity/syntaxTests/constants/constant_transient_state_variable.sol
Show resolved
Hide resolved
1a02699
to
ccaec3a
Compare
@cameel , I have restricted the parser to only accept |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did a final pass through the PR and found only one more serious thing - we should not be generating storage layouts that include transient variables. These layouts are not correct and should result in an unimplemented error instead.
Other than that, there's a bunch of small corrections that should all be straightforward to apply.
test/cmdlineTests/storage_layout_transient_value_types/input.json
Outdated
Show resolved
Hide resolved
"language": "Solidity", | ||
"sources": { | ||
"fileA": { | ||
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0;\ncontract A { uint transient x; bytes32 transient b; address transient addr; }" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some non-transient variables here? Best if they're interleaved with the transient ones. Also, you should put the code in a standalone .sol file so that it can be normally formatted.
And yeah, looks like we have a problem here because the returned storage layout will probably be wrong in presence of transient variables. It looks like they'll be assigned slots like normal storage variables. It's not the end of the world, since no one will be able to actually generate bytecode to go with such a layout, but I still think it's wrong to output something like that without producing an error. I think we should use solUnimplementedAssert()
when generating the stack layout and only allow if if there are no transient variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, also, I think we should check what the SMTChecker will do in presence of transient
storage variables, because I expect it will not simply fail, but just confidently tell you something that's wrong and this is dangerous.
Take this contract for example:
contract C {
uint /* transient */ x = 42;
function test() public view { assert(x == 42); }
}
solc test.sol --model-checker-engine all
Info: CHC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.
If you get the same answer after uncommenting transient
, we need to stick an unimplemented assert somewhere in it to make sure that it will just fail when you try to use it with transient variables.
On the other hand if you get an ICE, it's fine to leave it as is.
...lidity/syntaxTests/dataLocations/libraries/library_function_with_data_location_transient.sol
Outdated
Show resolved
Hide resolved
test/libsolidity/syntaxTests/dataLocations/state_variable_storage_transient.sol
Show resolved
Hide resolved
Changelog.md
Outdated
@@ -2,6 +2,7 @@ | |||
|
|||
Language Features: | |||
* Introduce a new overload ``require(bool, Error)`` that allows usage of ``require`` functions with custom errors. This feature is available in the ``via-ir`` pipeline only. | |||
* Accept declaration of state variables with ``transient`` data location. This is only supported at the parsing stage of the compiler, further steps such as code generation are nor supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a heads-up that this will have to be moved over to 0.8.27 before we merge since it won't go into 0.8.26.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. Should I already move it to a 0.8.27
section? I guess I will get a conflict anyway when rebasing after the release.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's fine to wait. Just leave this thread unresolved so it's clear we still have to do it.
"errors": [ | ||
{ | ||
"component": "general", | ||
"formattedMessage": "Internal exception in StandardCompiler::compile: /solidity/libsolidity/interface/StorageLayout.cpp(49): Throw in function solidity::Json solidity::frontend::StorageLayout::generate(const solidity::frontend::VariableDeclaration&, const u256&, unsigned int) | ||
Dynamic exception type: boost::wrapexcept<solidity::langutil::UnimplementedFeatureError> | ||
std::exception::what: Unimplemented feature | ||
[solidity::util::tag_comment*] = Unimplemented feature | ||
", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't normally test ICEs, one of the reason being that this output is not necessarily portable (as you can see from failing CI).
The other reason is that they should be fixed instead. Though the issue here is of course that UnimplementedFeatureError
is not really an ICE and should not be treated as such. We have some limited mechanism for catching it, but for some odd reason it was implemented to only catch ones with source locations attached.
So if you want to test it, I think you'd have to replace the call to solUnimplementedAssert()
with manual throwing of this error with a location attached.
So unless you find a way to get this to show up as a proper error, we're probably better of not testing this output until the feature is properly implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decide to just remove it. StorageLayout
does not have a errorReporter
member, so I think it is simpler to just not test this for now.
However, this made me question about other outputs from codegen which are being generated basically ignoring transient
and assuming storage
. Should we also throw UnimplementedFeatureError
for those cases too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking that we could also throw a fatalTypeError
during type checking, I guess. Or just throw UnimplementedFeatureError
in type checking but then most of the tests will have to be removed (and saved for later) and we could add tests using the stopAfter
flag set to parsing
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depends on the output. If there are any others that are wrong with transient storage, they should fail. But I don't think we need to do that with the whole type checking. The variables are getting transient
location in the AST so it's clear what's happening.
It's the cases like storage layout that are bad - the compiler was giving outright wrong information - telling you that transient variables live in storage, and using wrong slots for the actual storage variables.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about codegen output, like, for example, opcodes, asm and bin which will just generate code considering the variables to be located on storage.
Compiling this with solc --opcodes
:
contract C {
uint transient x = 42;
}
generates output which uses SSTORE
for the x
var:
Opcodes:
PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x2A PUSH0 SSTORE ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, great point. I somehow assumed that this would already be happening here, but you're totally right, we only added unimplemented asserts for stuff like reference types. Value types are allowed and will proceed to the codegen and just ignore the location. We definitely should block that, because otherwise anyone who mistakenly assumes that transient is fully implemented and starts using it will get a bad surprise. Declaring a variable as transient and getting code using storage variable instead is something we'd normally consider a serious codegen error.
The main complication though is that if we add asserts, syntax tests will start failing because they are hard-coded to run compilation:
solidity/test/libsolidity/SyntaxTest.cpp
Line 75 in 028cf33
runFramework(withPreamble(m_sources.sources), PipelineStage::Compilation); |
stopAfter: parsing
in syntax tests.
So the choices here are to add this as a setting you can enable in certain syntax tests and then use it in this PR or to just leave this PR unmerged until the codegen part is implemented. Fortunately it did not make it into 0.8.26, but there's still no 100% certainty we'll have the rest ready by 0.8.27 so merging it otherwise is risky.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was thinking about how this would be confusing for someone using the compiler and assuming that since transient
was parsed and code generated, then it is working with transient storage.
I will look into implementing stopAfter: parsing
for syntax tests. Seems like should not be complicated or time consuming.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, should be quite simple. It's just a matter of parsing the new setting in SyntaxTest
constructor and later passing the selected target stage to AnalysisFramework
in SyntaxTest::parseAndAnalyze()
.
I'd recommend doing that in a separate PR though.
And I think it'll generally be useful for future cases where we'll want to implement only parsing or only analysis. It would already have been useful for experimental - we had the same problem back then and we solved it by hacking in a condition for experimental, but this would have been a more general solution.
f7a7cf4
to
2892ee4
Compare
First step on providing Solidity high-level support for transient storage.
closes #15006.
depends on #15121