PR21565: Further refine the conditions for enabling eager parsing of

std::X::swap exception specifications (allowing parsing of non-conforming code
in libstdc++). The old conditions also matched the functions in MSVC's STL,
which were relying on deferred parsing here.

llvm-svn: 222471
This commit is contained in:
Richard Smith 2014-11-20 22:32:11 +00:00
parent 8489349fdc
commit 3ef3e899a9
3 changed files with 61 additions and 19 deletions

View File

@ -416,7 +416,6 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
Diag(Tok.getLocation(), diag::err_except_spec_unparsed);
// Attach the exception-specification to the method.
if (EST != EST_None)
Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
SpecificationRange,
DynamicExceptions,

View File

@ -5282,8 +5282,24 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
// Parse exception-specification[opt].
bool Delayed = D.isFirstDeclarationOfMember() &&
D.isFunctionDeclaratorAFunctionDeclaration() &&
!Actions.isLibstdcxxEagerExceptionSpecHack(D);
D.isFunctionDeclaratorAFunctionDeclaration();
if (Delayed && Actions.isLibstdcxxEagerExceptionSpecHack(D) &&
GetLookAheadToken(0).is(tok::kw_noexcept) &&
GetLookAheadToken(1).is(tok::l_paren) &&
GetLookAheadToken(2).is(tok::kw_noexcept) &&
GetLookAheadToken(3).is(tok::l_paren) &&
GetLookAheadToken(4).is(tok::identifier) &&
GetLookAheadToken(4).getIdentifierInfo()->isStr("swap")) {
// HACK: We've got an exception-specification
// noexcept(noexcept(swap(...)))
// or
// noexcept(noexcept(swap(...)) && noexcept(swap(...)))
// on a 'swap' member function. This is a libstdc++ bug; the lookup
// for 'swap' will only find the function we're currently declaring,
// whereas it expects to find a non-member swap through ADL. Turn off
// delayed parsing to give it a chance to find what it expects.
Delayed = false;
}
ESpecType = tryParseExceptionSpecification(Delayed,
ESpecRange,
DynamicExceptions,

View File

@ -1,20 +1,47 @@
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions
// This is a test for an egregious hack in Clang that works around
// an issue with GCC's <utility> implementation. std::pair::swap
// has an exception specification that makes an unqualified call to
// swap. This is invalid, because it ends up calling itself with
// the wrong number of arguments.
//
// The same problem afflicts a bunch of other class templates. Those
// affected are array, pair, priority_queue, stack, and queue.
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=pair
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=priority_queue
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=stack
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=queue
// MSVC's standard library uses a very similar pattern that relies on delayed
// parsing of exception specifications.
//
// RUN: %clang_cc1 -fsyntax-only %s -std=c++11 -verify -fexceptions -fcxx-exceptions -DCLASS=array -DMSVC
#ifdef BE_THE_HEADER
#pragma GCC system_header
namespace std {
template<typename T> void swap(T &, T &);
template<typename T> void do_swap(T &a, T &b) noexcept(noexcept(swap(a, b))) {
swap(a, b);
}
template<typename A, typename B> struct pair {
void swap(pair &other) noexcept(noexcept(swap(*this, other)));
template<typename A, typename B> struct CLASS {
#ifdef MSVC
void swap(CLASS &other) noexcept(noexcept(do_swap(member, other.member)));
#endif
A member;
#ifndef MSVC
void swap(CLASS &other) noexcept(noexcept(swap(member, other.member)));
#endif
};
// template<typename T> void do_swap(T &, T &);
// template<typename A> struct vector {
// void swap(vector &other) noexcept(noexcept(do_swap(member, other.member)));
// A member;
// };
}
#else
@ -23,9 +50,9 @@ namespace std {
#include __FILE__
struct X {};
using PX = std::pair<X, X>;
using PI = std::pair<int, int>;
void swap(PX &, PX &) noexcept;
using PX = std::CLASS<X, X>;
using PI = std::CLASS<int, int>;
void swap(X &, X &) noexcept;
PX px;
PI pi;
@ -35,11 +62,11 @@ static_assert(!noexcept(pi.swap(pi)), "");
namespace sad {
template<typename T> void swap(T &, T &);
template<typename A, typename B> struct pair {
void swap(pair &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}}
template<typename A, typename B> struct CLASS {
void swap(CLASS &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}}
};
pair<int, int> pi;
CLASS<int, int> pi;
static_assert(!noexcept(pi.swap(pi)), ""); // expected-note {{in instantiation of}}
}