This is an archive of the discontinued LLVM Phabricator instance.

[Sema] Make enable_if act correctly with value dependent conditions/arguments
AbandonedPublic

Authored by george.burgess.iv on Mar 23 2016, 6:42 PM.

Details

Reviewers
rsmith
Summary

Test case:

int foo(int A) __attribute__((enable_if(A == 0, "")));
template <int A> int bar() { return foo(A); }

int G = bar<1>(); // calls foo(1), which should be a compile-time error, but isn't.

We get around this by making CheckEnableIf fail all value dependent enable_if conditions, and report whether the condition may have failed due to a dependent value. If we fail for this reason during overload resolution, we hand back an unresolved, type-dependent call expression, because the following code is perfectly legal:

int ThisIsABadIdea(int A) __attribute__((enable_if(A == 1, "")));
double ThisIsABadIdea(int A) __attribute__((enable_if(A == 2, "")));

...But if we're not in overload resolution, we can get away with just marking the expression as value dependent, because we know our target. :)

Diff Detail

Event Timeline

george.burgess.iv retitled this revision from to [Sema] Make enable_if act correctly with value dependent conditions/arguments.
george.burgess.iv updated this object.
george.burgess.iv added a reviewer: rsmith.
george.burgess.iv updated this object.
george.burgess.iv added a subscriber: cfe-commits.
rsmith added inline comments.Apr 4 2016, 12:04 PM
include/clang/Sema/Sema.h
2491

I'd just call this Dependent -- that is, "here is a dependent enable_if attribute, so I couldn't tell whether this is enabled". The details of why it's dependent shouldn't be relevant to the caller.

lib/Sema/SemaExpr.cpp
5047–5098

You don't seem to make use of this refactoring in the functional change below. Either revert or commit separately, please (and if you commit it, fix the comment in Sema.h to reflect what this is used for).

5091–5106

Can you delete this FIXME? I'm pretty sure we've got that right for years :)

5218–5221

Does this need to be value-dependent? The only possible outcomes here are either that we call the designated function or that instantiation fails, which seems like instantiation-dependence is enough. (In practice, the setValueDependent call will be a no-op, because the only way the flag gets set is if one of the ArgExprs is value-dependent, which results in the call being value-dependent regardless, so there should be no functional change in removing the setValueDependent call.)

lib/Sema/SemaOverload.cpp
5879

I'm nervous about setting Viable to false for a function that *might be* viable; I expect a lot of code to "misinterpret" that. If we go ahead with this direction, I'd prefer for the Viable flag to become an enum of NonViable, Viable, Dependent, have overload resolution treat dependently-viable functions like viable functions, and add an OverloadingResult of OR_Dependent for the case where there was a unique best result that was dependently viable. All 31 callers of BestViableFunction would then need to check for and handle the new case, and build a dependent call expression in that case.

However, this seems like a lot of complexity to deal with this case. Let's talk offline and see if we can come up with something better.

george.burgess.iv marked 4 inline comments as done.

Addressed most feedback; see comments. :)

lib/Sema/SemaExpr.cpp
5047–5098

SG; will just revert.

5091–5106

r265341

5218–5221

If instantiation dependence is enough to be sure that we re-evaluate the enable_if condition(s) when we have all of the values we need, then not marking this as value-dependent seems like a better approach, yeah. :)

In practice, the setValueDependent call will be a no-op, because the only way the flag gets set is if one of the ArgExprs is value-dependent, which results in the call being value-dependent regardless, so there should be no functional change in removing the setValueDependent call

Given that we no longer care about value-dependence, it doesn't matter, but will this also happen when the enable_if condition itself is value-dependent?

lib/Sema/SemaOverload.cpp
5879

Works for me; will come bug you soonish.

rsmith added inline comments.Apr 4 2016, 5:10 PM
lib/Sema/SemaExpr.cpp
5218–5221

Hmm, good point, you might see a change in a contrived case like this:

constexpr bool g() __attribute__((enable_if(true, ""))) { return false; }
template<bool B> void f() {
  constexpr bool g() __attribute__((enable_if(B, "")));
  static_assert(g());
}

... where we can diagnose the static_assert failure at template definition time if the call is not value-dependent.