erik.pilkington added inline comments.

================
Comment at: clang/test/SemaCXX/using-if-exists.cpp:11
+
+using NotNS::x UIE; // expected-error{{use of undeclared identifier 'NotNS'}}
+} // test_basic
----------------
Quuxplusone wrote:
> Do you also have a test for `using NS::NotNS::x UIE;`?
> (Both of these `NotNS` tests produce hard errors; `[[using_if_exists]]` does 
> the silent-ignore thing only when the tippymost identifier is nonexistent, 
> not if some intermediate name is nonexistent. This seems reasonable enough.)
Yeah, this is only about the tippymost name :). New patch adds a test for 
non-existent names in the middle, which was previously untested.


================
Comment at: clang/test/SemaCXX/using-if-exists.cpp:60
+  typedef int mt;
+};
+
----------------
Quuxplusone wrote:
> An inheritance case not yet covered here errors out with `error: no matching 
> constructor for initialization of 'Derived<Base>'`:
> ```
> struct Base { Base(int); };
> template<class T> struct Derived : T {
>     using T::T [[clang::using_if_exists]];
> };
> Derived<Base> d(1);
> ```
> Does this make sense? Should this attribute perhaps give a hard error if you 
> try to use it to inherit a constructor overload set like this, instead of 
> (apparently) just no-opping the construct?
Hmm, yeah, I don't think that inheriting constructors really make sense with 
this attribute. New patch adds an error.


================
Comment at: clang/test/SemaCXX/using-if-exists.cpp:79
+  using B::mf UIE; // expected-note {{using declaration annotated with 
'using_if_exists' here}}
+  using typename B::mt UIE; // expected-note 2 {{using declaration annotated 
with 'using_if_exists' here}}
+
----------------
Quuxplusone wrote:
> I notice there's a hard `error: 'using_if_exists' attribute cannot be applied 
> to types` on
> 
>     using B::operator int UIE;
> 
> Any thoughts on how to disambiguate that grammar?
Hmm, that's an interesting case. I'm not sure what the right approach is. I 
think it would be a bit awkward to decide where to attach the attribute 
depending on what kind of entities the attribute could potentially apply to. 
FWIW this isn't a semantic restriction, since you can always just use the 
prefix syntax: `UIE using B::operator int;`. Maybe @aaron.ballman has some 
thoughts here?


================
Comment at: clang/test/SemaCXX/using-if-exists.cpp:107
+  using typename Ts::x... UIE; // expected-error 2 {{target of using 
declaration conflicts with declaration already in scope}} 
expected-note{{conflicting declaration}} expected-note{{target of using 
declaration}}
+};
+
----------------
Quuxplusone wrote:
> This is a very good test, but it feels to me as if
> ```
> struct B { static int f(int); };
> struct C { };
> template<class... Ts> struct D : Ts... {
>     using Ts::f... [[clang::using_if_exists]];
> };
> int main() { D<B, C>::f(1); }
> ```
> ought to be //at least// as well-formed as
> ```
> struct B { static int f(int); };
> struct C { static void f(); };
> template<class... Ts> struct D : Ts... {
>     using Ts::f... [[clang::using_if_exists]];
> };
> int main() { D<B, C>::f(1); }
> ```
> I guess what's going on here is that an "unresolved using decl" is considered 
> a separate kind of entity, i.e. `using Ts::f...` will work if //all// 
> `Ts::f...` are variables, or if //all// of them are functions, or if //all// 
> of them are unresolved, but it doesn't work if you have a mix of variables 
> and functions, or variables and unresolveds, or functions and unresolveds. Is 
> that basically correct, and intended? 
> I guess what's going on here is that an "unresolved using decl" is considered 
> a separate kind of entity, i.e. using Ts::f... will work if all Ts::f... are 
> variables, or if all of them are functions, or if all of them are unresolved, 
> but it doesn't work if you have a mix of variables and functions, or 
> variables and unresolveds, or functions and unresolveds. Is that basically 
> correct, and intended?


Yeah, exactly. My mental model for how this attribute works is that an 
unresolved using-declaration introduces an entity that isn't a function, value, 
or type, and is incompatible with all of those. Sometimes, that isn't what you 
want for overloaded functions, like Louis ran into an issue while testing this 
where `remove(const char *)` in `<cstdio>` being unresolved lead to a compile 
error on the declaration of `remove(iter, iter, val)` in `<algorithm>`. That 
seems to basically be the same issue you're seeing in your first test case.

Personally, my inclination is to conservatively just disallow any interplay 
with an unresolved using-declaration and a function, and if we run into a lot 
of problems in practice then we can come up with a more nuanced approach for 
this case without breaking backwards compatibility. WDYT?


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D90188/new/

https://reviews.llvm.org/D90188

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to