patch: new attribute enable_if

Richard Smith richard at metafoo.co.uk
Mon Sep 23 16:22:18 PDT 2013


On Mon, Sep 23, 2013 at 10:02 AM, Aaron Ballman <aaron at aaronballman.com>wrote:

> On Sun, Sep 22, 2013 at 5:57 PM, Nick Lewycky <nicholas at mxc.ca> wrote:
> > Aaron Ballman wrote:
> >>
> >> Most of my comments are related to the attribute itself.  I've got to
> >> run, but can take another look tomorrow as well.
> >
> >
> > Thanks! Unless I replied to it here, I've done what you suggested.
> Updated
> > patch attached!
> >
> >
> >>> +def EnableIf : InheritableAttr {
> >>> +  let Spellings = [GNU<"enable_if">];
> >>
> >>
> >> Is this really a GNU attribute?  If not, perhaps since this is related
> >> to overloading, this could have a C++11 style clang:: attribute.
> >> (Reading further, I see tests for C as well, so perhaps not.)
> >
> >
> > As much as __attribute__((overloadable)) is. It's intended to be used
> with
> > the GNU syntax for attributes, but isn't implemented by GCC.
>
> Okay
>
> >
> >
> >>> +  if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(FDecl)) {
> >>> +    if (FD->hasAttr<EnableIfAttr>()) {
> >>> +      ArrayRef<Expr *>  NonConstArgs =
> >>> +        llvm::makeArrayRef<Expr*>(const_cast<Expr**>(Args.data()),
> >>> Args.size());
> >>
> >>
> >> This const_cast makes me a bit nervous; is there a way to avoid it?
> >
> >
> > Not really, I can move it around a bit or I can remove consts all over
> the
> > place. I tried sinking it into the callee, but it so happens that adding
> > const requires just as nasty a statement.
> >
> >>> Index: lib/Sema/SemaDeclAttr.cpp
> >>> ===================================================================
> >>> --- lib/Sema/SemaDeclAttr.cpp (revision 191171)
> >>> +++ lib/Sema/SemaDeclAttr.cpp (working copy)
> >>> @@ -982,6 +982,33 @@
> >>>
>  Attr.getAttributeSpellingListIndex()));
> >>>   }
> >>>
> >>> +static void handleEnableIfAttr(Sema&S, Decl *D, const
> >>> AttributeList&Attr) {
> >>> +  if (!isa<FunctionDecl>(D)&&  !isa<FunctionTemplateDecl>(D)) {
> >>>
> >>> +    S.Diag(Attr.getLoc(), diag::err_attribute_enable_if_not_function);
> >>> +    return;
> >>> +  }
> >>
> >>
> >> Does this apply to function-like things as well (such as function
> >> pointers, etc)?
> >
> >
> > No.
> >
> >
> >>> +
> >>> +  if (!checkAttributeNumArgs(S, Attr, 2))
> >>> +    return;
> >>> +
> >>> +  Expr *Cond = Attr.getArgAsExpr(0);
> >>> +  Expr *Message = Attr.getArgAsExpr(1);
> >>
> >>
> >> Attributes can take unresolved identifiers as well as expressions (for
> >> the first argument position), so you should be prepared to handle a
> >> case like that.
> >
> >
> > Sorry, are you saying that __attribute__((enable_if(id, ...))) could
> fail to
> > return an Expr? I tried that syntax and it works fine (and added a test),
> > but I'm wondering if there's another syntax you had in mind which I
> haven't
> > thought of?
>
> Actually, re-reading the code, I think you're fine because you're
> using an ExprArgument as the first parameter to the attribute.  So you
> will always get resolved expressions.  Sorry for the confusion!
>
> >
> >
> >> Missing test cases for everything in SemaDeclAttr.cpp.  Be sure to hit
> >> edge cases as well (such as unresolved identifier as the expression).
> >
> >
> > Thanks! I added a bunch, let me know if there's anything I missed.
>
> > +def EnableIf : InheritableAttr {
> > +  let Spellings = [GNU<"enable_if">];
> > +  let Subjects = [Function];
> > +  let Args = [ExprArgument<"Cond">, StringArgument<"Message">];
> > +  let TemplateDependent = 1;
> > +}
>
> Subjects should also include FunctionTemplate since that's what you're
> checking in SemaDeclAttr.cpp


I suspect the change should be to remove FunctionTemplateDecl there, not
add it here: this should apply to the FunctionDecl within a
FunctionTemplateDecl, not to the template itself, right?

> +static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList
> &Attr) {
> > +  if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) {
> > +    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type)
> > +      << Attr.getName() << ExpectedFunctionOrMethod;
>
> This should be ExpectedFunction (unless you mean to support Obj-C
> methods, in which case you'd need to update the Subjects and isa
> check).
>
> > +    return;
> > +  }
> > +
> > +  if (!checkAttributeNumArgs(S, Attr, 2))
> > +    return;
> > +
> > +  Expr *Cond = Attr.getArgAsExpr(0);
> > +  ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
> > +  if (Converted.isInvalid())
> > +    return;
> > +
> > +  StringRef Msg;
> > +  if (!checkStringLiteralArgument(S, Msg, Attr, 1))
> > +    return;
> > +
> > +  D->addAttr(::new (S.Context) EnableIfAttr(Attr.getRange(), S.Context,
> > +                                            Converted.take(), Msg));
>
> You should also pass in the spelling list index to the constructor.
>
> > +}
>
> One random question -- what happens if you do the following:
>
> int n __attribute__((deprecated));
> void f(int x) __attribute__((enable_if(n == 0, ""));
>
> Will you get a deprecated message with or without calling f?
>
> Thanks!
>
> ~Aaron
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130923/05d5c59e/attachment.html>


More information about the cfe-commits mailing list