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