This is an archive of the discontinued LLVM Phabricator instance.

[Sema] ADL: Associated namespaces for class types and enumeration types (CWG 1691)
ClosedPublic

Authored by riccibruno on Apr 11 2019, 11:47 AM.

Details

Summary

CWG 1691 changed the definition of the namespaces associated with a class type or enumeration type.

For a class type, the associated namespaces are the innermost enclosing namespaces of the associated classes.
For an enumeration type, the associated namespace is the innermost enclosing namespace of its declaration.

This also fixes CWG 1690 and CWG 1692.

I have applied the fix to all language versions, even though I think that the DR only applies to C++14. The reason for this is that it is possible to return a local type from a lambda in C++11, and I don't think that this will affect anyone (although this can totally be a failure of my imagination...)

Diff Detail

Repository
rC Clang

Event Timeline

riccibruno created this revision.Apr 11 2019, 11:47 AM

Removed the call to isTransparentContext() in the loop in CollectEnclosingNamespace. It is not actually needed since we only care about finding the innermost enclosing namespace.

rjmccall accepted this revision.Apr 11 2019, 3:27 PM

Hmm. Does this never impact code that's just using a locally-defined type within its scope? I guess if ADL is involved, unqualified lookup must have reached the scope of the innermost namespace, and so it would be searching that namespace anyway.

In that case, I think I'm mollified that the source-compatibility risk is low and we should just unconditionally apply the new rule. LGTM.

This revision is now accepted and ready to land.Apr 11 2019, 3:27 PM
rsmith accepted this revision.Apr 11 2019, 4:11 PM
rsmith added a subscriber: rsmith.

I have applied the fix to all language versions, even though I think that the DR only applies to C++14

DRs don't have a specific version that they are intended to apply to; that's up to us to determine, and generally we apply them retroactively as far back as they make sense -- they are supposed to be bug fixes, after all. (From ISO's perspective, C++11 was retracted and replaced by C++14 when the latter was published, so it's simply not meaningful for a DR to officially target anything older than that, and the only version that DRs can meaningfully list is whatever version was most recently published when they were approved.)

This looks good to me. Thanks!

Hmm. Does this never impact code that's just using a locally-defined type within its scope? I guess if ADL is involved, unqualified lookup must have reached the scope of the innermost namespace, and so it would be searching that namespace anyway.

In that case, I think I'm mollified that the source-compatibility risk is low and we should just unconditionally apply the new rule. LGTM.

I am not sure about what you mean. It is certainly possible to construct a piece of C++11 code which breaks with this patch. A possible example is:

constexpr int f(void *) { return 1; }

static auto lambda = []() { struct S {} s; return s; };
using S = decltype(lambda());

template <typename T> void test() {
    constexpr T *p = nullptr;
    static_assert(f(p) == 1, "");
}

constexpr int f(S *) { return 2; }

template void test<S>();

Clang currently accept this because ADL does not currently find the second better matching f. After this patch it will be found and the static_assert will fail (which is the behavior of gcc, and as far as I can tell the specified behavior).

I have applied the fix to all language versions, even though I think that the DR only applies to C++14

DRs don't have a specific version that they are intended to apply to; that's up to us to determine, and generally we apply them retroactively as far back as they make sense -- they are supposed to be bug fixes, after all. (From ISO's perspective, C++11 was retracted and replaced by C++14 when the latter was published, so it's simply not meaningful for a DR to officially target anything older than that, and the only version that DRs can meaningfully list is whatever version was most recently published when they were approved.)

This looks good to me. Thanks!

Good to know, thanks for the explanation and review !

Hmm. Does this never impact code that's just using a locally-defined type within its scope? I guess if ADL is involved, unqualified lookup must have reached the scope of the innermost namespace, and so it would be searching that namespace anyway.

In that case, I think I'm mollified that the source-compatibility risk is low and we should just unconditionally apply the new rule. LGTM.

I am not sure about what you mean. It is certainly possible to construct a piece of C++11 code which breaks with this patch.

Yes, but these examples are contrived, so it's easy to rationalize that the source impact is low. The typical use-pattern of a local type is that you only use it locally, so the most important question would be whether it is possible to change the semantics of, say,

void test() {
  struct A { ... };
  foo(A{});
}

But I think the answer is "no", for the reasons I explained.

Hmm. Does this never impact code that's just using a locally-defined type within its scope? I guess if ADL is involved, unqualified lookup must have reached the scope of the innermost namespace, and so it would be searching that namespace anyway.

In that case, I think I'm mollified that the source-compatibility risk is low and we should just unconditionally apply the new rule. LGTM.

I am not sure about what you mean. It is certainly possible to construct a piece of C++11 code which breaks with this patch.

Yes, but these examples are contrived, so it's easy to rationalize that the source impact is low. The typical use-pattern of a local type is that you only use it locally, so the most important question would be whether it is possible to change the semantics of, say,

void test() {
  struct A { ... };
  foo(A{});
}

But I think the answer is "no", for the reasons I explained.

I can't imagine a way to change the result of the lookup for foo in an example like this without escaping the local type from the function.

Thanks for the review !

This revision was automatically updated to reflect the committed changes.