[PATCH] __attribute__((enable_if)) and non-overloaded member functions

Nick Lewycky nlewycky at google.com
Thu May 28 12:34:37 PDT 2015


On 27 May 2015 at 10:44, Ettore Speziale <speziale.ettore at gmail.com> wrote:

> Hello Nick,
>
> thanks for taking a look at the patch.
>
> > I think this will cause the enable_if expression to be evaluated
> multiple times if the expression is not dependent but appertains to a
> function template, such as:
> >
> >   template <typename T> void foo(int i, T t)
> __attribute__((enable_if(i==0, ""))) {}
> >
> > I'm not sure how to fix that without hoisting it up to ActOnCallExpr?
> Could you check whether this is a real problem?
>
> I tried to run this small example:
>
> // RUN: clang++ -emit-llvm -S -o - test.cpp
>
> struct foo {
>   template <typename T>
>   int f(int i, T t) __attribute__((enable_if(i == 0, "only when 'i' is
> zero")));
>
>   template <typename T>
>   int g(int i, float j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>   template <typename T>
>   int g(int i, double j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
> };
>
> int bar(foo in, int ti, float tf) {
>   return in.f(1, ti) + in.f(1, tf);
> }
>
> int baz(foo in, float fj, double dj, int ti, float tf) {
>   return in.g(1, fj, ti) + in.g(1, fj, tf) + in.g(1, dj, ti) + in.g(1, dj,
> tf);
> }
>
> With a modified version of clang that dump the expression just before it
> is being computed in CheckEnableIf:
>
> diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
> index 95af64e..361a4f3 100644
> --- a/lib/Sema/SemaOverload.cpp
> +++ b/lib/Sema/SemaOverload.cpp
> @@ -5887,6 +5887,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl
> *Function, ArrayRef<Expr *> Args,
>        continue;
>      }
>
> +    llvm::errs() << "EVALUATE EXPR\n"; EIA->getCond()->dump();
>      if (!EIA->getCond()->EvaluateWithSubstitution(
>              Result, Context, Function,
> llvm::makeArrayRef(ConvertedArgs))) {
>        if (!ContainsValueDependentExpr)
>
> The bar function exercise the code in my patch, the baz function exercise
> existing code.
>
> This is what I get:
>
> ┌─[ettore at vesta] - [/tmp] - [2015-05-27 10:11:24]
> └─[1] <> clang++ -emit-llvm -S -o - test.cpp
> EVALUATE EXPR
> BinaryOperator 0x7fc06507e2c8 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507e2b0 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507e288 'int' lvalue ParmVar 0x7fc06507df98 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507be00 'int' 0
> test.cpp:13:13: error: no matching member function for call to 'f'
>   return in.f(1, ti) + in.f(1, tf);
>          ~~~^
> test.cpp:4:7: note: candidate disabled: only when 'i' is zero
>   int f(int i, T t) __attribute__((enable_if(i == 0, "only when 'i' is
> zero")));
>       ^                                      ~~~~~~
> EVALUATE EXPR
> BinaryOperator 0x7fc06507e780 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507e768 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507e740 'int' lvalue ParmVar 0x7fc06507e480 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507be00 'int' 0
> test.cpp:13:27: error: no matching member function for call to 'f'
>   return in.f(1, ti) + in.f(1, tf);
>                        ~~~^
> test.cpp:4:7: note: candidate disabled: only when 'i' is zero
>   int f(int i, T t) __attribute__((enable_if(i == 0, "only when 'i' is
> zero")));
>       ^                                      ~~~~~~
> EVALUATE EXPR
> BinaryOperator 0x7fc06507f188 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507f170 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507f148 'int' lvalue ParmVar 0x7fc06507ee00 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c338 'int' 0
> EVALUATE EXPR
> BinaryOperator 0x7fc06507f698 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507f680 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507f658 'int' lvalue ParmVar 0x7fc06507f308 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c828 'int' 0
> test.cpp:17:13: error: no matching member function for call to 'g'
>   return in.g(1, fj, ti) + in.g(1, fj, tf) + in.g(1, dj, ti) + in.g(1, dj,
> tf);
>          ~~~^
> test.cpp:7:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, float j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                               ~~~~~~
> test.cpp:9:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, double j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                                ~~~~~~
> EVALUATE EXPR
> BinaryOperator 0x7fc06507fc38 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507fc20 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507fbf8 'int' lvalue ParmVar 0x7fc06507f8b0 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c338 'int' 0
> EVALUATE EXPR
> BinaryOperator 0x7fc0650804c8 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc0650804b0 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc065080488 'int' lvalue ParmVar 0x7fc06507fd30 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c828 'int' 0
> test.cpp:17:31: error: no matching member function for call to 'g'
>   return in.g(1, fj, ti) + in.g(1, fj, tf) + in.g(1, dj, ti) + in.g(1, dj,
> tf);
>                            ~~~^
> test.cpp:7:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, float j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                               ~~~~~~
> test.cpp:9:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, double j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                                ~~~~~~
> EVALUATE EXPR
> BinaryOperator 0x7fc06507f188 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507f170 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507f148 'int' lvalue ParmVar 0x7fc06507ee00 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c338 'int' 0
> EVALUATE EXPR
> BinaryOperator 0x7fc06507f698 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507f680 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507f658 'int' lvalue ParmVar 0x7fc06507f308 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c828 'int' 0
> test.cpp:17:49: error: no matching member function for call to 'g'
>   return in.g(1, fj, ti) + in.g(1, fj, tf) + in.g(1, dj, ti) + in.g(1, dj,
> tf);
>                                              ~~~^
> test.cpp:7:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, float j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                               ~~~~~~
> test.cpp:9:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, double j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                                ~~~~~~
> EVALUATE EXPR
> BinaryOperator 0x7fc06507fc38 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc06507fc20 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc06507fbf8 'int' lvalue ParmVar 0x7fc06507f8b0 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c338 'int' 0
> EVALUATE EXPR
> BinaryOperator 0x7fc0650804c8 '_Bool' '=='
> |-ImplicitCastExpr 0x7fc0650804b0 'int' <LValueToRValue>
> | `-DeclRefExpr 0x7fc065080488 'int' lvalue ParmVar 0x7fc06507fd30 'i'
> 'int'
> `-IntegerLiteral 0x7fc06507c828 'int' 0
> test.cpp:17:67: error: no matching member function for call to 'g'
>   return in.g(1, fj, ti) + in.g(1, fj, tf) + in.g(1, dj, ti) + in.g(1, dj,
> tf);
>                                                                ~~~^
> test.cpp:7:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, float j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                               ~~~~~~
> test.cpp:9:7: note: candidate disabled: only when 'i' is zero
>   int g(int i, double j, T t) __attribute__((enable_if(i == 0, "only when
> 'i' is zero")));
>       ^                                                ~~~~~~
> 6 errors generated.
>
> I can see the expression being evaluated once for each call to f, and
> twice for each call to g, as it has two overloads. So it seems that my
> patch and the current implementation works in the same way from this point
> of view.
>
> Did I understand correctly?
>

Yep. LGTM!


>
> Thanks,
> Ettore Speziale
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150528/23582d15/attachment.html>


More information about the cfe-commits mailing list