r222471 - PR21565: Further refine the conditions for enabling eager parsing of

Richard Smith richard-llvm at metafoo.co.uk
Thu Nov 20 14:32:11 PST 2014


Author: rsmith
Date: Thu Nov 20 16:32:11 2014
New Revision: 222471

URL: http://llvm.org/viewvc/llvm-project?rev=222471&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=222471&r1=222470&r2=222471&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Thu Nov 20 16:32:11 2014
@@ -416,13 +416,12 @@ void Parser::ParseLexedMethodDeclaration
       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()) &&

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=222471&r1=222470&r2=222471&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Thu Nov 20 16:32:11 2014
@@ -5282,8 +5282,24 @@ void Parser::ParseFunctionDeclarator(Dec
 
       // 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,

Modified: cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp?rev=222471&r1=222470&r2=222471&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp (original)
+++ cfe/trunk/test/SemaCXX/libstdcxx_pair_swap_hack.cpp Thu Nov 20 16:32:11 2014
@@ -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 A, typename B> struct pair {
-    void swap(pair &other) noexcept(noexcept(swap(*this, other)));
+  template<typename T> void do_swap(T &a, T &b) noexcept(noexcept(swap(a, b))) {
+    swap(a, b);
+  }
+
+  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}}
 }





More information about the cfe-commits mailing list