[cfe-dev] [RFC] Preliminary patch to support MSVC __declspec(property)
endlessroad1991 at gmail.com
endlessroad1991 at gmail.com
Mon Dec 17 01:06:14 PST 2012
On Sat, Dec 15, 2012 at 2:50 AM, John McCall <rjmccall at apple.com> wrote:
> On Dec 13, 2012, at 10:01 PM, endlessroad1991 at gmail.com wrote:
>
> On Thu, Dec 13, 2012 at 4:23 PM, John McCall <rjmccall at apple.com> wrote:
>
>> On Dec 12, 2012, at 11:45 PM, endlessroad1991 at gmail.com wrote:
>>
>> Thanks, that's a very detailed and thorough comment.
>>
>> MSDN page for __declspec(property):
>> http://msdn.microsoft.com/en-us/library/yhfk0thd.aspx
>> we can declare "array-like" property:
>> __declspec(property(get=GetX, put=PutX)) int x[][];
>> and access it with indices:
>> var = obj->x[expr1][expr2];
>> it will be translated into:
>> var = obj->GetX(expr1, expr2);
>>
>> And that's what "ParamCount" in "PropertyAttr" is for.
>> We don't know how many params until we parse to "int x[][]", so we have
>> to modify the Attr when we get here.
>>
>>
>> That documentation says you can declare this as "int x[]" and it permits
>> an arbitrary amount of subscripts, but apparently you can *also* add
>> multiple []s. It would be good to understand the requirements and
>> limitations of this language feature as implemented in MSVC. In particular:
>>
>> 1. Can you directly template these declarations? (template <class T>
>> _declspec(property) T foo;)
>>
> No
>
>> 1a. Are any of the following answers different if T is dependent, and if
>> so, are those likely to be bugs or actually intended?
>> 1b. What if you have template <class T> struct A { _declspec(property) T
>> foo; }; and then instantiate the template at T=int[]?
>>
> Yes, this works fine.
>
>
> Does it add an expected index argument?
> template <class T> struct A {
> int *getFoo() { .. }
> int getFoo(int index) { ... }
> _declspec(property(get=getFoo)) T foo;
> };
>
> int test(A<int[]> &a) {
> return a.foo[0];
> }
>
> Does this call getFoo() or getFoo(int)?
>
Doesn't compile. Return type of getters must be exactly the same as
property type.
>
> 2. What's the relationship between []s and the number of indices?
>> 2a. Given _declspec(property) int x[], can you in fact use multiple
>> indices with it, like foo.x[2][3]?
>>
> No
>
>
> Okay, that actually explicitly contradicts MS's own documentation that you
> linked above. Make sure you test this with an unscriptable element type —
> like int, not int*.
>
If getter with more/less parameters is defined, you can. Otherwise, you
can't.
>
> 2b. If so, what happens if the "element type" is itself subscriptable?
>> 2b.i. _declspec(property) std::vector<int> x[] and foo.x[0][1]?
>>
> No
>
>
> What do you mean by "no" here? Are you saying this program was rejected?
> What's the error?
>
Doesn't compile. Error says "GetX() doesn't accept 2 arguments", just like
std::vector<int> is not subscriptable.
>
> 2b.ii. _declspec(property) int *x[] and foo.x[0][1]?
>>
> Yes, this works fine.
>
>> 2c. Do parentheses change these answers at all?
>> 2c.i. _declspec(property) int* x[] and (foo.x[0])[1]?
>>
> Yes, this works fine.
>
>
> What about _declspec(property) int x[][] and (foo.x[0])[1]?
>
Compiles and runs as expected.
>
> 2c.ii. For that matter, given _declspec(property) int x[], is (foo.x)[0]
>> legal at all?
>>
> Yes, this works fine.
>
>
> Okay, good.
>
> 2d. Given _declspec(property) int x[][], can you use fewer subscripts
>> than that? Can you still use more?
>>
> Answer for both questions is NO.
>
>
> Good.
>
> 3. Are there restrictions on the element type?
>>
> 3a. Can it be a reference?
>>
> Yes
>
>
> Okay. If I have _declspec(property(get=getFoo)) int &foo, can I do
> x.foo = 7
> with the semantics of x.getFoo() = 7?
>
No. Seems that it's not that smart. All assignments will be translated into
setters.
>
> 3b. Can it be a bounded array type? (_declspec(property) int x[][10])
>>
> No. Seems that whatever you put in the brackets will be ignored, and
> treated as a param to getter/setter.
>
>
> Okay.
>
> 3c. Can it be an unbounded array type if you use, e.g., a typedef?
>> (typedef int intarr[]; _declspec(property) intarr x;, or intarr x[] for
>> that matter.) Does this change the behavior of subscripting?
>>
> Surprisingly, in this situation, the [] in intarr is still interpreted as
> a param to getter/setter.
>
>
> Alright. My question above about template arguments is designed to figure
> out whether this is a hack for non-dependent type sugar, or whether it
> works through anything that extends the type this way.
>
> 4. What exactly does the element type do there? Is it just for
>> type-checking the property against the accessors?
>> 4a. I'd been assuming that the accessors were selected by overload
>> resolution at access time using the name given/inferred in the property
>> attribute. Is this not true? Are they selected/filtered by initial
>> type-checking somehow?
>>
> It is true. You can define "T GetV(int, int)" and "T GetV(double,
> double)". And getter will choose the best match like normal overload
> functions.
>
>
> Okay.
>
> 4b. Is access control checked on the accessors from the declaration point
>> of the property or from the use point?
>> 4c. Can the accessors be inherited from base classes? Are normal
>> ambiguity controls enforced? Can you scope-qualify the accessor names,
>> e.g. get=Base1::getElt?
>>
> Inherit: yes. Ambiguity: yes. Scope-quailify: No, seems that there can
> only be one identifier after get= or put=.
>
>> 4d. Are the index types in the accessors limited in some way, or can
>> they be e.g. arbitrary class types?
>>
> They can be arbitary types.
>
>>
>> I'm sure we can find more questions. :)
>>
>> Considering this situation, is it still possible to do it in your
>> suggested way?
>>
>>
>> Sure, that's not really a problem. One very important thing — something
>> I seem to have unconscionably forgotten put in my initial review — is that
>> this is way, way more than just a property on a FieldDecl; this really
>> needs to be some new kind of Decl, probably named MSPropertyDecl. That
>> node would then be a reasonable place to stash things like the expected
>> (minimum?) number of indices and any other important information from
>> type-checking the declaration, e.g. the possibly-filtered lookup results.
>> You'll probably need to recognize the presence of the attribute in the
>> parser and enter into a completely different Sema entrypoint, kindof like
>> how the 'friend' keyword does.
>>
>> John.
>>
>
>
> Based on answers of these questions, let's guess how VC implements
> property.
> I think the design principle for them is, reuse existing compiler code as
> much as possible, and make the solution as simple as possible.
> Here are my opinions:
> 1. Any [], [10], or [] that comes from typedef, is treated as a param to
> getter/setter. Hence, they lose their origin semantics meaning.
>
>
> Right, you need to walk through type sugar. If template instantiation
> can't add to the number of arguments, then you'll need to do this at
> template parse time and then remember it in the MSPropertyDecl.
>
> 2. For accessors, they will be translated into getter/setter.
> i. property can be private, as long as getter/setter is public, they
> work well.
>
>
> Oh, now that's interesting. Okay, you'll have to suppress access control
> on a member lookup that resolves to one of these.
>
> ii. getter/setter will be chosen like any normal overloaded functions.
> 3. property are treated like normal members. So they can be inherited, and
> have ambiguity problem when a class has multiple base classes.
> The only problem here, is when the element type is subscriptable itself.
> i. When it's pointer type, subscripting the property works as expected.
> ii. When it's class type which has overwritten operator[] (no matter
> vector or self-defined class), subscripting the property doesn't compile.
> I can't guess why this happens.
>
>
> If int x[] can, in fact, take more than one subscript (as documented),
> then I would guess that the rule is that all possible subscripts are
> consumed by the property *unless* the element type is "obviously
> subscriptable", which is probably defined as "a pointer type" and doesn't
> recognize classes with operator[]s. Interesting corner cases here would be
> int *&x[]; // does it realize that this result type is still "obviously
> subscriptable"?
> int *x[]; // if I do a.x[0][1][2], does it steal both [0] and [1] for
> the subscript, or does it steal just [0] and then try to subscript int*
> twice (which will fail, of course)?
>
Here's two good samples, I think:
#include <iostream>
class C
{
public:
__declspec(property(get=GetA, put=SetA)) int **A[];
int** GetA(int i) { std::cout << "Get\n"; return &v; }
void SetA(int i, int **value) { std::cout << "Set\n";}
int *v;
};
int main()
{
C c;
c.A[123][0][0] = 2; // GetA()
// c.A[123][0] = 2; // doesn't compile! "Cannot convert int to int*"
c.A[1] = 0; // SetA()
}
#include <iostream>
class C
{
public:
__declspec(property(get=GetA, put=SetA)) int *A[];
int* GetA(int i) { std::cout << "Get 1\n"; return v; }
int* GetA(int i, int j) { std::cout << "Get 2\n"; return v; }
void SetA(int i, int *value) { std::cout << "Set 1\n"; }
void SetA(int i, int j, int *value) { std::cout << "Set 2\n"; }
int *v;
};
int main()
{
C c;
c.A[123][0] = 2; // Get 1
c.A[1] = 0; // Set 1
}
>
> If int x[] really cannot take more than one subscript, then I have no idea
> why subscripting vector<int> x[] twice wouldn't compile; probably just a
> compiler bug.
>
> John.
>
And, can you summarize how we should implement property, based on these
results?
--
Best Regards, Tong Shen (沈彤)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20121217/b34b50b2/attachment.html>
More information about the cfe-dev
mailing list