<div dir="ltr">Rebased on r179523<div class="gmail_extra"><br></div><div class="gmail_extra">Replay to John:<br><br><div class="gmail_quote">On Tue, Apr 9, 2013 at 7:27 AM, John McCall <span dir="ltr"><<a href="mailto:rjmccall@apple.com" target="_blank">rjmccall@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="im">On Apr 1, 2013, at 6:00 AM, <a href="mailto:endlessroad1991@gmail.com">endlessroad1991@gmail.com</a> wrote:<br>
> Rebased on r178459<br>
><br>
> All original tests still pass, and 2 new tests(one for Parser, one for Sema).<br>
<br>
</div>Major cross-cutting problem: none of the places where you're manually<br>
calling CheckPlaceholderExpr should be necessary. I'm positive that<br>
we're already filtering out placeholders in these places; if we weren't,<br>
we'd have a serious bug that would hit a ton of Objective-C code.<br>
<br>
The other nice thing about relying on the existing machinery for this is<br>
that you wouldn't have a ton of latent bugs about not looking through parens. :)<br></blockquote><div style>Yes, I'm aware of that :-)</div><div style>I will explain each case of CheckPlaceholderExpr() in the last.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
SemaTemplateInstantiateDecl.cpp:<br>
<div class="im"><br>
+ if (DI->getType()->isInstantiationDependentType() ||<br>
+ DI->getType()->isVariablyModifiedType()) {<br>
<br>
</div>Why are you checking for variably-modified types here?<br></blockquote><div style>I just copied most of handleField() into handleMSProperty(),</div><div style>In the attached new patch, it will complain about VariablyModifiedType</div>
<div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
+ if (CXXRecordDecl *Parent =<br>
+ dyn_cast<CXXRecordDecl>(Property->getDeclContext())) {<br>
<div class="im">+ if (Parent->isAnonymousStructOrUnion() &&<br>
+ Parent->getRedeclContext()->isFunctionOrMethod())<br>
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, Property);<br>
+ }<br>
<br>
</div>There should be an invariant that the parent of an MSPropertyDecl is<br>
a CXXRecordDecl.<br></blockquote><div style>Done. This "if" is removed.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
SemaDecl.cpp:<br>
<br>
This is all C++-specific and should go in SemaDeclCXX.cpp.<br></blockquote><div style>Done. Moved to SemaDeclCXX.cpp</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
+ DiagnoseFunctionSpecifiers(D.getDeclSpec());<br>
<div class="im">+<br>
+ if (D.getDeclSpec().isThreadSpecified())<br>
+ Diag(D.getDeclSpec().getThreadSpecLoc(), diag::err_invalid_thread);<br>
+ if (D.getDeclSpec().isConstexprSpecified())<br>
+ Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)<br>
+ << 2;<br>
<br>
</div>You should also complain about the presence of a storage class specifier.<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
+ MSPropertyDecl *NewFD;<br>
<br>
Style nit: "NewPD" instead of "NewFD".<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="im"><br>
+ llvm::StringRef GetterName = MSPropertyAttr->getScopeName() ?<br>
+ MSPropertyAttr->getScopeName()->getName() : StringRef();<br>
+ llvm::StringRef SetterName = MSPropertyAttr->getParameterName() ?<br>
+ MSPropertyAttr->getParameterName()->getName() : StringRef();<br>
<br>
</div>Why are you storing getter/setter names as a StringRefs instead of an<br>
IdentifierInfo*? Identifiers are (1) more compact, (2) better supported by<br>
the serialization libraries, and (3) required by lookup anyway.<br></blockquote><div style>Done. And this does make the code much cleaner! I should have realized it before.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
SemaPseudoObject.cpp:<br>
<div class="im"><br>
+ } else if (MSPropertyRefExpr *refExpr<br>
+ = dyn_cast<MSPropertyRefExpr>(opaqueRef)) {<br>
+ return refExpr;<br>
<br>
</div>You need to implement this correctly; you should follow the lead<br>
of the existing implementations.<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
SemaDeclCXX.cpp:<br>
<br>
+static AttributeList *getMSPropertyAttr(AttributeList *list) {<br>
+ for (AttributeList* it = list; it != 0; it = it->getNext())<br>
<div class="im">+ if (it->getName()->getName() == "property")<br>
<br>
</div>if (it->getKind() == AttributeList::AT_property)<br>
<br>
I'm a little bothered by doing this here instead of filtering it out beforehand,<br>
but it's probably okay; attributes on fields are relatively uncommon.<br></blockquote><div style>I don't like this either, but ParsedAttr are only attached to FieldDecl after it's created...</div><div style>
And here, we need to judge whether we should create FieldDecl or MSPropertyDecl.</div><div style>So I just put it here.</div><div style>Any ideas?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
AttributeList.cpp:<br>
<br>
- if (ScopeName)<br>
- Buf += ScopeName->getName();<br>
- // Ensure that in the case of C++11 attributes, we look for '::foo' if it is<br>
- // unscoped.<br>
- if (ScopeName || SyntaxUsed == AS_CXX11)<br>
- Buf += "::";<br>
+ // For property, "ScopeName" is used to store getter function name<br>
+ if (AttrName != "property") {<br>
+ if (ScopeName)<br>
+ Buf += ScopeName->getName();<br>
+ // Ensure that in the case of C++11 attributes, we look for '::foo' if it is<br>
+ // unscoped.<br>
+ if (ScopeName || SyntaxUsed == AS_CXX11)<br>
+ Buf += "::";<br>
+ }<br>
<br>
Okay, this is actually a hot enough path that we'd really rather not introduce<br>
a string compare into it. Figure out some other way to store the second<br>
string; you could throw things like MessageExpr into a union.<br></blockquote><div style>Done. Turns out that this problem has been encountered before: availability and typetag attributes.</div><div style>I used the same mechanism as existing code: malloc more than sizeof(AttributeList), and use the extra space.</div>
<div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
ASTBitCodes.h:<br>
<div class="im"><br>
+ /// \brief A __delcpec(property) record.<br>
+ DECL_MS_PROPERTY,<br>
<br>
</div>By prevailing style in this file, this should be "An MSPropertyDecl record."<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
ExprCXX.h:<br>
<br>
+ SourceLocation MemberLoc;<br>
+ DeclarationNameLoc MemberDNLoc;<br>
+ bool IsArrow;<br>
<br>
Please put the bool immediately after the SourceLocation; it'll pack better<br>
on 64-bit architectures.<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
+ SourceLocation getLocStart() const {<br>
+ if (QualifierLoc) {<br>
+ return QualifierLoc.getBeginLoc();<br>
+ } else {<br>
+ SourceLocation result = BaseExpr->getLocStart();<br>
+ if (result.isValid())<br>
+ return result;<br>
+ else<br>
+ return MemberLoc;<br>
+ }<br>
+ }<br>
<br>
You've got this mixed up. The start loc is the start of the base<br>
expression, unless that's an implicit this access, in which case it's the<br>
start of the qualifier, unless that doesn't exist, in which case it's the<br>
member loc.<br>
<br>
You should have an isImplicitAccess() method like MemberExpr does.<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div class="im"><br>
+ Expr* getBaseExpr() const { return BaseExpr; }<br>
+ void setBaseExpr(Expr *baseExpr) { BaseExpr = baseExpr; }<br>
+ MSPropertyDecl* getMSPropertyDecl() const { return Decl; }<br>
+ void setMSPropertyDecl(MSPropertyDecl *decl) { Decl = decl; }<br>
+ bool isArrow() const { return IsArrow; }<br>
+ void setArrow(bool isArrow) { IsArrow = isArrow; }<br>
+ SourceLocation getMemberLoc() const { return MemberLoc; }<br>
+ void setMemberLoc(SourceLocation memberLoc) { MemberLoc = memberLoc; }<br>
</div>+ DeclarationNameLoc getMemberDNLoc() const { return MemberDNLoc; }<br>
+ void setMemberDNLoc(DeclarationNameLoc memberDNLoc) {<br>
+ MemberDNLoc = memberDNLoc;<br>
+ }<br>
+ NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }<br>
+ void setQualifierLoc(NestedNameSpecifierLoc qualifierLoc) {<br>
+ QualifierLoc = qualifierLoc;<br>
+ }<br>
<br>
The statement/expression AST classes are generally meant to be immutable,<br>
and there's really no need to have any of these setters.<br></blockquote><div style>Well, these setter's are for serialization. Every subclass of Expr has them...</div><div style>So they should be kept.</div><div style>
</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
Attr.td:<br>
<br>
+def MsProperty : InheritableAttr {<br>
<div class="im">+ let Spellings = [Declspec<"property">];<br>
+}<br>
</div>+<br>
<br>
It's not actually Inheritable; properties can't be redeclared.<br></blockquote><div style>Done.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
test/Parser/MicrosoftExtensions.c:<br>
<br>
Why is this in a C test case? Is this actually legal in C? I can't imagine<br>
it is, because it the entire language model relies on methods.<br>
<br>
You can parse the attribute in C, I guess, but you should always emit an<br>
error if you see it.<br></blockquote><div style>On top of this test file, it says "-x objective-c++".</div><div style>So this file is treated as C++...</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<br>
+struct S8 {<br>
+ __declspec(property) int V0; /* expected-error {{expected '(' after 'property'}} */<br>
+ __declspec(property()) int V1; /* expected-error {{expected 'get' or 'put' in __declspec(property)}} expected-error {{no getter or putter in __declspec(property)}} */<br>
+ __declspec(property(set)) int V2; /* expected-error {{expected 'get' or 'put' in __declspec(property)}} expected-error {{no getter or putter in __declspec(property)}} */<br>
+ __declspec(property(get)) int V3; /* expected-error {{expected '=' in __declspec(property)}} expected-error {{no getter or putter in __declspec(property)}} */<br>
+ __declspec(property(get&)) int V4; /* expected-error {{expected '=' in __declspec(property)}} expected-error {{no getter or putter in __declspec(property)}} */<br>
+ __declspec(property(get=)) int V5; /* expected-error {{expected identifier in __declspec(property)}} expected-error {{no getter or putter in __declspec(property)}} */<br>
+ __declspec(property(get=GetV)) int V6; /* no-warning */<br>
+ __declspec(property(get=GetV=)) int V7; /* expected-error {{expected ',' or ')' in __declspec(property)}} */<br>
+ __declspec(property(get=GetV,)) int V8; /* expected-error {{expected 'get' or 'put' in __declspec(property)}} */<br>
+ __declspec(property(get=GetV,put=SetV)) int V9; /* no-warning */<br>
+ __declspec(property(get=GetV,put=SetV,get=GetV)) int V10; /* expected-error {{duplicate accessor in __declspec(property)}} */<br>
+};<br>
<br>
You do not have a single test case that verifies that you can actually<br>
access one of these.<br></blockquote><div style>Added.</div><div style> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<span class=""><font color="#888888"><br>
John.<br>
</font></span></blockquote></div><div class="gmail_extra"><br></div><div class="gmail_extra"><br></div>Explanation for all CheckPlaceholderExpr():</div><div class="gmail_extra" style>1. in Parse/ParseExpr.cpp, ParsePostfixExpressionSuffix()</div>
<div class="gmail_extra" style>=== Code Start ===</div><div class="gmail_extra" style><div class="gmail_extra">class D</div><div class="gmail_extra">{</div><div class="gmail_extra">public:</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>bool operator()() { return true; }</div>
<div class="gmail_extra">};</div><div class="gmail_extra"><br></div><div class="gmail_extra">class C</div><div class="gmail_extra">{</div><div class="gmail_extra">public:</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>__declspec(property(get=GetV)) D V;</div>
<div class="gmail_extra"><span class="" style="white-space:pre"> </span>D GetV() { return D(); }</div><div class="gmail_extra">};</div><div class="gmail_extra"><br></div><div class="gmail_extra">int main() {</div><div class="gmail_extra">
<span class="" style="white-space:pre"> </span>C c;</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>bool b = c.V(); // If not added, clang will complain "c.V is not a function, nor function object"</div>
<div class="gmail_extra">}</div><div class="gmail_extra" style>=== Code End ===</div><div class="gmail_extra"><br></div><div style>2. In Sema/SemaExpr.cpp, ActOnCallExpr():</div><div style>I admit that I'm not very thorough about this one...</div>
<div style>But here the CheckPlaceholderExpr() call does solve the follwing problem.</div><div style>=== Code Start ===</div><div style><div>// If compiled with -ggdb, clang will crash and saying something about</div><div style>
// "unexpected builtin-type" in some CG code.</div><div><br></div><div>struct S2 {</div><div><span class="" style="white-space:pre"> </span>template <class T></div><div><span class="" style="white-space:pre"> </span>void f(T t) {}</div>
<div>};</div><div><br></div><div>template <class T></div><div>struct S</div><div>{</div><div><span class="" style="white-space:pre"> </span>__declspec(property(get=GetV)) int V;</div><div><span class="" style="white-space:pre"> </span>int GetV() { return 123; }</div>
<div><span class="" style="white-space:pre"> </span>void f() { S2 s2; s2.f(V); }</div><div>};</div><div><br></div><div>int main() {</div><div><span class="" style="white-space:pre"> </span>S<int> s;</div><div><span class="" style="white-space:pre"> </span>s.f();</div>
<div>}</div></div><div style>=== Code End ===</div></div><div class="gmail_extra"><br></div><div class="gmail_extra" style>3. In Sema/SemaExprCXX.cpp, BuildCXXNew()</div><div class="gmail_extra" style>=== Code Start ===</div>
<div class="gmail_extra" style><div class="gmail_extra">template <class T></div><div class="gmail_extra">class C</div><div class="gmail_extra">{</div><div class="gmail_extra">public:</div><div class="gmail_extra"> __declspec(property(get=GetV)) T V;</div>
<div class="gmail_extra"> int GetV() { return 123; }</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>void f() { int *p = new int[V]; } // If not added, clang will complain "V is dependent type, not integral type"</div>
<div class="gmail_extra">};</div><div class="gmail_extra"><br></div><div class="gmail_extra">int main() {</div><div class="gmail_extra">}</div></div><div class="gmail_extra" style>=== Code End ===</div><div class="gmail_extra" style>
<br></div><div class="gmail_extra" style>4. In Sema/SemaDecl.cpp, AddInitializerToDecl()</div><div class="gmail_extra" style>=== Code Start ===</div><div class="gmail_extra" style><div class="gmail_extra">template <class T></div>
<div class="gmail_extra">class C</div><div class="gmail_extra">{</div><div class="gmail_extra">public:</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>__declspec(property(get=GetV)) T V;</div>
<div class="gmail_extra"><span class="" style="white-space:pre"> </span>T GetV() { return 123; }</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>void f() { int t = V; } // If not added, clang will complain "V is dependent type"</div>
<div class="gmail_extra">};</div><div class="gmail_extra"><br></div><div class="gmail_extra">int main() {</div><div class="gmail_extra"><span class="" style="white-space:pre"> </span>C<int> c;</div><div class="gmail_extra">
<span class="" style="white-space:pre"> </span>c.f();</div><div class="gmail_extra">}</div></div><div class="gmail_extra" style>=== Code End ===</div><div class="gmail_extra"><div><br></div>-- <br>Best Regards, Tong Shen (沈彤)
</div></div>