[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