mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-10 18:11:19 +00:00
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:
parent
8489349fdc
commit
3ef3e899a9
@ -416,13 +416,12 @@ 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,
|
||||
DynamicExceptionRanges,
|
||||
NoexceptExpr.isUsable()?
|
||||
NoexceptExpr.get() : nullptr);
|
||||
Actions.actOnDelayedExceptionSpecification(LM.Method, EST,
|
||||
SpecificationRange,
|
||||
DynamicExceptions,
|
||||
DynamicExceptionRanges,
|
||||
NoexceptExpr.isUsable()?
|
||||
NoexceptExpr.get() : nullptr);
|
||||
|
||||
assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
|
||||
Tok.getLocation()) &&
|
||||
|
@ -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,
|
||||
|
@ -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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user