From 3ef3e899a9f0a640f179a4d50f1e8ab31b419fbb Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 20 Nov 2014 22:32:11 +0000 Subject: [PATCH] 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 --- clang/lib/Parse/ParseCXXInlineMethods.cpp | 13 ++++--- clang/lib/Parse/ParseDecl.cpp | 20 +++++++++-- clang/test/SemaCXX/libstdcxx_pair_swap_hack.cpp | 47 +++++++++++++++++++------ 3 files changed, 61 insertions(+), 19 deletions(-) diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 8469fb9..e1a5b8e 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -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()) && diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index f84b4da..518197e 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -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, diff --git a/clang/test/SemaCXX/libstdcxx_pair_swap_hack.cpp b/clang/test/SemaCXX/libstdcxx_pair_swap_hack.cpp index 8c7c782..02431e02 100644 --- a/clang/test/SemaCXX/libstdcxx_pair_swap_hack.cpp +++ b/clang/test/SemaCXX/libstdcxx_pair_swap_hack.cpp @@ -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 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 void swap(T &, T &); + template void do_swap(T &a, T &b) noexcept(noexcept(swap(a, b))) { + swap(a, b); + } - template struct pair { - void swap(pair &other) noexcept(noexcept(swap(*this, other))); + template 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 void do_swap(T &, T &); +// template 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; -using PI = std::pair; -void swap(PX &, PX &) noexcept; +using PX = std::CLASS; +using PI = std::CLASS; +void swap(X &, X &) noexcept; PX px; PI pi; @@ -35,11 +62,11 @@ static_assert(!noexcept(pi.swap(pi)), ""); namespace sad { template void swap(T &, T &); - template struct pair { - void swap(pair &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}} + template struct CLASS { + void swap(CLASS &other) noexcept(noexcept(swap(*this, other))); // expected-error {{too many arguments}} expected-note {{declared here}} }; - pair pi; + CLASS pi; static_assert(!noexcept(pi.swap(pi)), ""); // expected-note {{in instantiation of}} } -- 2.7.4