Fix shadowing error for inline assembly.

This commit is contained in:
chriseth 2021-08-04 12:10:49 +02:00
parent 838514a718
commit aeb2438eab
25 changed files with 67 additions and 56 deletions

View File

@ -2,6 +2,7 @@
Breaking changes: Breaking changes:
* `error` is now a keyword that can only be used for defining errors. * `error` is now a keyword that can only be used for defining errors.
* Inline Assembly: Consider functions, function parameters and return variables for shadowing checks.
### 0.8.8 (unreleased) ### 0.8.8 (unreleased)

View File

@ -274,28 +274,8 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl) void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
{ {
for (auto const& identifier: _varDecl.variables) for (auto const& identifier: _varDecl.variables)
{
validateYulIdentifierName(identifier.name, identifier.debugData->location); validateYulIdentifierName(identifier.name, identifier.debugData->location);
if (
auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str());
!declarations.empty()
)
{
SecondarySourceLocation ssl;
for (auto const* decl: declarations)
ssl.append("The shadowed declaration is here:", decl->location());
if (!ssl.infos.empty())
m_errorReporter.declarationError(
3859_error,
identifier.debugData->location,
ssl,
"This declaration shadows a declaration outside the inline assembly block."
);
}
}
if (_varDecl.value) if (_varDecl.value)
visit(*_varDecl.value); visit(*_varDecl.value);
} }
@ -385,4 +365,20 @@ void ReferencesResolver::validateYulIdentifierName(yul::YulString _name, SourceL
_location, _location,
"The identifier name \"" + _name.str() + "\" is reserved." "The identifier name \"" + _name.str() + "\" is reserved."
); );
auto declarations = m_resolver.nameFromCurrentScope(_name.str());
if (!declarations.empty())
{
SecondarySourceLocation ssl;
for (auto const* decl: declarations)
if (decl->location().hasText())
ssl.append("The shadowed declaration is here:", decl->location());
if (!ssl.infos.empty())
m_errorReporter.declarationError(
3859_error,
_location,
ssl,
"This declaration shadows a declaration outside the inline assembly block."
);
}
} }

View File

@ -323,7 +323,6 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
returnTypes = &_fun.returns; returnTypes = &_fun.returns;
} }
})) }))
else
{ {
if (!validateInstructions(_funCall)) if (!validateInstructions(_funCall))
m_errorReporter.declarationError( m_errorReporter.declarationError(

View File

@ -1,12 +0,0 @@
contract C {
function f() public returns (uint x) {
assembly {
function g() -> f { f := 2 }
x := g()
}
}
}
// ====
// compileViaYul: also
// ----
// f() -> 2

View File

@ -7,11 +7,11 @@ contract C {
uint256 off1; uint256 off1;
uint256 off2; uint256 off2;
assembly { assembly {
function f() -> o1 { function g() -> o1 {
sstore(z.slot, 7) sstore(z.slot, 7)
o1 := y.offset o1 := y.offset
} }
off2 := f() off2 := g()
} }
assert(off2 == 2); assert(off2 == 2);
return true; return true;

View File

@ -1,5 +1,5 @@
contract C { contract C {
function f() public pure returns (uint w) { function g() public pure returns (uint w) {
assembly { assembly {
function f() -> t { function f() -> t {
t := 2 t := 2
@ -14,4 +14,4 @@ contract C {
// compileToEwasm: also // compileToEwasm: also
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f() -> 2 // g() -> 2

View File

@ -1,7 +1,7 @@
contract C { contract C {
uint256 public z; uint256 public z;
function f() public { function g() public {
z = 42; z = 42;
uint i = 32; uint i = 32;
assembly { assembly {

View File

@ -1,7 +1,7 @@
contract C { contract C {
function f() public pure { function f() public pure {
assembly { assembly {
function f() { function g() {
// Make sure this doesn't trigger the unimplemented assertion in the control flow builder. // Make sure this doesn't trigger the unimplemented assertion in the control flow builder.
leave leave
} }

View File

@ -1,7 +1,7 @@
contract C { contract C {
struct S { bool f; } struct S { bool f; }
S s; S s;
function f() internal pure { function g() internal pure {
S storage c; S storage c;
// this should warn about unreachable code, but currently function flow is ignored // this should warn about unreachable code, but currently function flow is ignored
assembly { assembly {

View File

@ -1,7 +1,7 @@
contract C { contract C {
struct S { bool f; } struct S { bool f; }
S s; S s;
function f() internal pure { function g() internal pure {
S storage c; S storage c;
// this could be allowed, but currently control flow for functions is not analysed // this could be allowed, but currently control flow for functions is not analysed
assembly { assembly {

View File

@ -1,7 +1,7 @@
contract C { contract C {
struct S { bool f; } struct S { bool f; }
S s; S s;
function f() internal pure returns (S storage c) { function g() internal pure returns (S storage c) {
// this should warn about unreachable code, but currently function flow is ignored // this should warn about unreachable code, but currently function flow is ignored
assembly { assembly {
function f() { return(0, 0) } function f() { return(0, 0) }

View File

@ -4,8 +4,8 @@ contract C {
function f() internal pure returns (S storage c) { function f() internal pure returns (S storage c) {
// this could be allowed, but currently control flow for functions is not analysed // this could be allowed, but currently control flow for functions is not analysed
assembly { assembly {
function f() { revert(0, 0) } function g() { revert(0, 0) }
f() g()
} }
} }
} }

View File

@ -9,4 +9,5 @@ contract C {
} }
} }
// ---- // ----
// DeclarationError 3859: (103-104): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 6578: (123-124): Cannot access local Solidity variables from inside an inline assembly function. // DeclarationError 6578: (123-124): Cannot access local Solidity variables from inside an inline assembly function.

View File

@ -1,5 +1,5 @@
contract C { contract C {
function f() public pure { function g() public pure {
assembly { assembly {
function f(a) {} function f(a) {}

View File

@ -1,7 +1,7 @@
contract C { contract C {
function f() pure public { function f() pure public {
assembly { assembly {
function f (a, b , c ) -> y,x,z { function g (a, b , c ) -> y,x,z {
} }
} }
} }

View File

@ -1,8 +1,8 @@
contract C { contract C {
function f() public pure { function f() public pure {
assembly { assembly {
function f() {} function g() {}
f := 1 g := 1
} }
} }
} }

View File

@ -1,5 +1,5 @@
contract C { contract C {
function f() public pure { function g() public pure {
assembly { assembly {
function f(a., x.b) -> t.b, b.. {} function f(a., x.b) -> t.b, b.. {}
} }

View File

@ -1,5 +1,5 @@
contract C { contract C {
function f() public pure { function g() public pure {
assembly { assembly {
function f() -> x, y, z {} function f() -> x, y, z {}
let a., aa.b := f() let a., aa.b := f()

View File

@ -49,7 +49,5 @@ contract C {
// DeclarationError 4113: (595-600): The identifier name "super" is reserved. // DeclarationError 4113: (595-600): The identifier name "super" is reserved.
// DeclarationError 4113: (645-646): The identifier name "_" is reserved. // DeclarationError 4113: (645-646): The identifier name "_" is reserved.
// DeclarationError 4113: (759-763): The identifier name "this" is reserved. // DeclarationError 4113: (759-763): The identifier name "this" is reserved.
// DeclarationError 3859: (759-763): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 4113: (785-790): The identifier name "super" is reserved. // DeclarationError 4113: (785-790): The identifier name "super" is reserved.
// DeclarationError 3859: (785-790): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 4113: (812-813): The identifier name "_" is reserved. // DeclarationError 4113: (812-813): The identifier name "_" is reserved.

View File

@ -1,7 +1,7 @@
contract C { contract C {
function f() public pure { function f() public pure {
assembly { assembly {
function f() { function g() {
leave leave
} }
} }

View File

@ -0,0 +1,11 @@
contract C {
uint x;
function f() public pure {
assembly {
function g(f) -> x {}
}
}
}
// ----
// DeclarationError 3859: (98-99): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 3859: (104-105): This declaration shadows a declaration outside the inline assembly block.

View File

@ -0,0 +1,9 @@
contract C {
function f() public pure {
assembly {
function f() {}
}
}
}
// ----
// DeclarationError 3859: (75-90): This declaration shadows a declaration outside the inline assembly block.

View File

@ -0,0 +1,10 @@
contract C {
function f() public pure {
uint a;
assembly {
function g(a) {}
}
}
}
// ----
// DeclarationError 3859: (102-103): This declaration shadows a declaration outside the inline assembly block.

View File

@ -9,7 +9,5 @@ contract C {
} }
// ---- // ----
// DeclarationError 4113: (74-79): The identifier name "super" is reserved. // DeclarationError 4113: (74-79): The identifier name "super" is reserved.
// DeclarationError 3859: (74-79): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 4113: (101-105): The identifier name "this" is reserved. // DeclarationError 4113: (101-105): The identifier name "this" is reserved.
// DeclarationError 3859: (101-105): This declaration shadows a declaration outside the inline assembly block.
// DeclarationError 4113: (127-128): The identifier name "_" is reserved. // DeclarationError 4113: (127-128): The identifier name "_" is reserved.

View File

@ -12,7 +12,7 @@ contract C {
assembly { for {} 1 { pop(sload(0)) } { } pop(gas()) } assembly { for {} 1 { pop(sload(0)) } { } pop(gas()) }
} }
function h() view public { function h() view public {
assembly { function g() { pop(blockhash(20)) } } assembly { function g1() { pop(blockhash(20)) } }
} }
function i() public { function i() public {
assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) } assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) }