This is an archive of the discontinued LLVM Phabricator instance.

[Fix] Allow implicit conversions of the address of overloadable functions in C + docs update
ClosedPublic

Authored by george.burgess.iv on Oct 13 2015, 11:57 AM.

Details

Summary

Two smallish patches in one. Happy to split into two (for review and/or commit) if that's preferred.

In C, we allow (as an extension) incompatible pointer conversions, like so:

int foo(int *);
int (*p)(void *) = foo; // Compiles; warns if -Wincompatible-pointer-types is specified

So, we should provide primitive support for this with overloadable functions. Specifically, this patch is trying to fix cases like this:

int foo(void *) __attribute__((overloadable));
int foo(double *d) __attribute__((overloadable, enable_if(d != nullptr, "")));

int (*p)(int *) = foo; // Before patch, error because we couldn't match the function type exactly. After patch, we see that 'int foo(void *)' is the only option, and choose it. A warning is emitted if -Wincompatible-pointer-types is given

Which means that explicit casts are necessary if there's more than one overload that isn't disabled by enable_if attrs. The updated docs have an example of this, but here's another:

int foo(void *) __attribute__((overloadable));
int foo(double *d) __attribute__((overloadable));

int (*p)(int *) = foo; // 0 candidates before patch, 2 after. Won't compile either way.
int (*p2)(int *) = (int (*)(void *))foo; // OK. Issues warning if -Wincompatible-pointer-types is given

Diff Detail

Repository
rL LLVM

Event Timeline

george.burgess.iv retitled this revision from to [Fix] Allow implicit conversions of the address of overloadable functions in C + docs update.
george.burgess.iv updated this object.
george.burgess.iv added a reviewer: rsmith.
george.burgess.iv added a subscriber: cfe-commits.

FYI: I noticed a few cases this patch misses. Will add them soon.

  • Reworded docs update
  • Added support for reinterpret_casts of overloaded functions in both C and C++
  • Added general facility in Sema to query if an overloaded expression can resolve to being not-overloaded on its own (e.g. if it's an address-of function expression *and* it's the only addressable overload with the given name)

I made it generally available because there's a problem that this patch doesn't fix (will submit as separate phabricator review), and I suspect that this new functionality will be useful for solving that problem. Namely, the problem is template argument deduction (joy):

template <typename Fn> int foo(Fn);

void bar();
void bar(int) __attribute__((enable_if(0, "")));
int a = foo(bar); // cannot deduce `Fn` because `bar` is an overload.

Rebased, and narrowed the scope of the patch a bit.

rsmith added inline comments.Mar 18 2016, 11:21 AM
lib/Sema/SemaOverload.cpp
10419 ↗(On Diff #49333)

Why is the void* check removed from this case? Note that clang and GCC intentionally treat these two cases differently today:

int f();
void *p = f; // ok (warning under -pedantic)
int *q = f; // warning: incompatible pointer types

(That is: the first is a silent-by-default extension and the second is a warn-by-default extension.)

lib/Sema/SemaOverload.cpp
10419 ↗(On Diff #49333)

Because this is overload resolution logic, so we shouldn't care about what warnings we will emit :)

This is how we act prior to applying this patch:

void f(int) __attribute__((overloadable));
void f(double) __attribute__((overloadable, enable_if(0, "")));

void *fp = f; // OK. This is C and the target is void*.
void (*fp)(void) = f; // Error. This is C, but the target isn't void*.

I'm simply removing the "the target must be a void*" restriction; the user should still get warnings in the latter case (the tests changed in test/Sema/pass-object-size.c make sure of this).

rsmith accepted this revision.Mar 22 2016, 6:57 PM
rsmith edited edge metadata.
rsmith added inline comments.
lib/Sema/SemaOverload.cpp
10419 ↗(On Diff #49333)

OK, this seems fine so long as we somewhere choose exact matches over inexact ones:

void f(int) __attribute__((overloadable));
void f(int, int) __attribute__((overloadable));
void g(void (*)(int));
void h() { g(f); } // should pick f(int)
This revision is now accepted and ready to land.Mar 22 2016, 6:57 PM
george.burgess.iv marked 3 inline comments as done.Mar 22 2016, 7:39 PM
george.burgess.iv added inline comments.
lib/Sema/SemaOverload.cpp
10419 ↗(On Diff #49333)

We do; the tests in test/CodeGen/overloadable.c make sure of this -- thanks for the review! :)

This revision was automatically updated to reflect the committed changes.