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

Ettore Speziale speziale.ettore at gmail.com
Thu May 28 09:03:32 PDT 2015


Gently ping.

> On May 27, 2015, at 10:44 AM, 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?
> 
> Thanks,
> Ettore Speziale





More information about the cfe-commits mailing list