Skip to content
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

BindReference in translation semantics #2 #522

Merged
merged 5 commits into from
Jul 30, 2019

Conversation

h0nzZik
Copy link
Contributor

@h0nzZik h0nzZik commented Jul 4, 2019

No description provided.

@h0nzZik
Copy link
Contributor Author

h0nzZik commented Jul 5, 2019

I can reproduce it localy (using --reverse-rules). The left argument to bindReference is of non-reference type:

bindReference(
	lecpp(
		`_.___CPP-SYNTAX`(
			`*__CPP-SYNTAX`(`This`(.KList)),
			`no-template_CPP-SYNTAX`(.KList),
			`Name`(classId(`GlobalNamespace`(.KList),classSpecifier(`Struct`(.KList),`Identifier`(#token("\"S\"","String")),`.List{"_,__CPP-DYNAMIC-OTHER-SORTS"}`(.KList))),`Identifier`(#token("\"b\"","String")))),
		hasTrace(`ExecName`(classId(`GlobalNamespace`(.KList),classSpecifier(`Struct`(.KList),`Identifier`(#token("\"S\"","String")),`.List{"_,__CPP-DYNAMIC-OTHER-SORTS"}`(.KList))),`Identifier`(#token("\"b\"","String")))),

		tcpp(quals(`.Set`(.KList)),`.Set`(.KList),`int_CPP-TYPING-SYNTAX`(.KList))
	),

	lecpp(`_.___CPP-SYNTAX`(`*__CPP-SYNTAX`(`This`(.KList)),`no-template_CPP-SYNTAX`(.KList),`Name`(classId(`GlobalNamespace`(.KList),classSpecifier(`Struct`(.KList),`Identifier`(#token("\"S\"","String")),`.List{"_,__CPP-DYNAMIC-OTHER-SORTS"}`(.KList))),`Identifier`(#token("\"a\"","String")))),hasTrace(`ExecName`(`NoNNS`(.KList),`Identifier`(#token("\"a\"","String")))),tcpp(quals(`.Set`(.KList)),`.Set`(.KList),`int_CPP-TYPING-SYNTAX`(.KList))))~>
`#freezer#SemanticCastToK0_54`(.KList)

This happens because of these rules in dynamic.k:

rule le(E::Expr, Tr::Trace, cppRefType #as T::CPPType) => le(E, Tr, innerType(T))
rule xe(E::Expr, Tr::Trace, cppRefType #as T::CPPType) => xe(E, Tr, innerType(T))

Most likely, we need these rules, because le,xe, and pre of reference types are not KResults - at least not in the translation semantics, see this rule:

rule isKResult(le(_, _, T::CPPType) #Or xe(_, _, T::CPPType) #Or pre(_, _, T::CPPType)) => notBool isCPPRefType(T)

But why we need that rule?

@h0nzZik
Copy link
Contributor Author

h0nzZik commented Jul 25, 2019

I still have problems binding a reference to temporary. The only support for temporaries is here in execution semantics -- temp(...).

The standard says:

12.2/5 [...] The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except:
(5.1) — A temporary object bound to a reference parameter in a function call (5.2.2) persists until the completion of the full-expression containing the call.

Multiple cases may happen:

  1. The reference have automatic storage duration.
  2. The reference have static storage duration (e.g. it is a global or local static variable).
  3. The reference is a function parameter.
  4. The reference is bound to a subobject of a temporary object, e.g. a member of a class.

Currently, bindReference (in translation semantics) does not have any information about which case is currently happening. To move forward with this PR, I will first ignore the third and fourth case, as I believe we do not have any tests for those yet.

One option would be figureInit(temp(!I:Int, ...), ...). However, temp(...) only constructs non-static local objects (with automatic storage duration), which does not work for the test cases like:

const int &i = 42;

int main()
{
  // another variant
  //static const int &i = 42;
  if (i != 42)
    return 1;
}

which would keep the temporary object uninitialized.
Another option is:

NormalizedDecl(NoNNS(), #NoName(!I:Int), Identifier(""), T, V2, Var(CopyInit()))
~>
bindReference'(V1, Name(NoNNS(), #NoName(!I:Int)))

which uses <curr-tr-scope> to create an unnamed variable with automatic or static storage duration. This works for the global-reference case, but not for static local one.

Also, this is an interesting corner case for binding reference to a temporary:

struct S {
    int const &t = 3;
};
// S s1; // fails in implicitly-defined default constructor
S s{4}; // ok

Also, I heard that C++17 changed some rules about temporaries to support guaranteed copy elision - does that affect reference binding?

@h0nzZik
Copy link
Contributor Author

h0nzZik commented Jul 26, 2019

To create a temporary, bindReference may use DeclareObject from translation/decl/declarator.k. However, bindReference would need to know the duration (AutoStorage/StaticStorage) of the reference (or the complete object) that is being created/initialized. DeclareObject has this information. How do we transfer it down to bindReference?

One option is to add a new parameter to #figureInit, figureInit, aggInit, classAndUnionAggInit, classAggInit, arrayInit, //maybe figureConstructorInit, figureConstructItem, figureConstruct.
listInit

Another option is to add a new cell containing the duration of the object being created.

Example:

struct S { int const &r; };
S s1[2] {3,4};
int main()
{
    S s2{4};
}

the translation gets stuck on
```innerTypeOfSimpleType(`int_CPP-TYPING-SYNTAX`(.KList))```
(A fix of the error detected in the previous commit.)
Track duration of references.

The temporary to which the reference is bound
persists for the lifetime of the reference.
@h0nzZik
Copy link
Contributor Author

h0nzZik commented Jul 29, 2019

@h0nzZik h0nzZik merged commit 4f1e9da into kframework:master Jul 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants