]> granicus.if.org Git - clang/commitdiff
Parser support for noexcept specifications.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 5 Mar 2011 14:45:16 +0000 (14:45 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Sat, 5 Mar 2011 14:45:16 +0000 (14:45 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127086 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
include/clang/Parse/Parser.h
include/clang/Sema/DeclSpec.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
test/CXX/except/except.spec/p1.cpp [new file with mode: 0644]
test/Parser/cxx-exception-spec.cpp [deleted file]

index 9a68af9c45caff1e9da6a64724167228b19e2e44..acf38e4f0f5d2b2c413350852133c85b453a735d 100644 (file)
@@ -300,6 +300,8 @@ def err_expected_lbrace_after_base_specifiers : Error<
   "expected '{' after base class list">;
 def ext_ellipsis_exception_spec : Extension<
   "exception specification of '...' is a Microsoft extension">;
+def err_dynamic_and_noexcept_specification : Error<
+  "cannot have both throw() and noexcept() clause on the same function">;
 def err_expected_catch : Error<"expected catch">;
 def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
 def err_using_namespace_in_class : Error<
index 78bd04b6bd106483757cba65b68bb7c147df4781..b8ae999fe5fe5fae320764118352f1d6e640c6ff 100644 (file)
@@ -1114,11 +1114,18 @@ private:
   //===--------------------------------------------------------------------===//
   // C++ 15: C++ Throw Expression
   ExprResult ParseThrowExpression();
+
+  ExceptionSpecificationType MaybeParseExceptionSpecification(
+                    SourceRange &SpecificationRange,
+                    llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
+                    llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+                    ExprResult &NoexceptExpr);
+
   // EndLoc is filled with the location of the last token of the specification.
-  bool ParseExceptionSpecification(SourceLocation &EndLoc,
-                                   llvm::SmallVectorImpl<ParsedType> &Exns,
-                                   llvm::SmallVectorImpl<SourceRange> &Ranges,
-                                   bool &hasAnyExceptionSpec);
+  ExceptionSpecificationType ParseDynamicExceptionSpecification(
+                                  SourceRange &SpecificationRange,
+                                  llvm::SmallVectorImpl<ParsedType> &Exceptions,
+                                  llvm::SmallVectorImpl<SourceRange> &Ranges);
 
   //===--------------------------------------------------------------------===//
   // C++0x 8: Function declaration trailing-return-type
index 2f343475335e23897adad06a1006dd09d31cd53c..1567baaaad91c137890410b3fb692cf90fddbc9f 100644 (file)
@@ -907,6 +907,15 @@ public:
 /// parsing.
 typedef llvm::SmallVector<Token, 4> CachedTokens;
 
+/// \brief The various types of exception specifications that exist in C++0x.
+enum ExceptionSpecificationType {
+  EST_None,            ///< no exception specification
+  EST_Dynamic,         ///< throw() or throw(T1, T2)
+  EST_DynamicAny,      ///< Microsoft throw(...) extension
+  EST_BasicNoexcept,   ///< noexcept
+  EST_ComputedNoexcept ///< noexcept(expression)
+};
+
 /// DeclaratorChunk - One instance of this struct is used for each type in a
 /// declarator that is parsed.
 ///
index 50ba7054fef2483fca8f84ec1bfb20d7eea86950..5cda4e6d5c5f13977ed6a8c9de77353d12acb0c5 100644 (file)
@@ -3127,6 +3127,10 @@ void Parser::ParseParenDeclarator(Declarator &D) {
 /// For C++, after the parameter-list, it also parses "cv-qualifier-seq[opt]",
 /// C++0x "ref-qualifier[opt]" and "exception-specification[opt]".
 ///
+/// [C++0x] exception-specification:
+///           dynamic-exception-specification
+///           noexcept-specification
+///
 void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
                                      ParsedAttributes &attrs,
                                      bool RequiresArg) {
@@ -3147,11 +3151,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
     DeclSpec DS;
     SourceLocation RefQualifierLoc;
     bool RefQualifierIsLValueRef = true;
-    bool hasExceptionSpec = false;
-    SourceLocation ThrowLoc;
-    bool hasAnyExceptionSpec = false;
-    llvm::SmallVector<ParsedType, 2> Exceptions;
-    llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+    ExceptionSpecificationType ESpecType = EST_None;
+    SourceRange ESpecRange;
+    llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+    llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+    ExprResult NoexceptExpr;
     if (getLang().CPlusPlus) {
       MaybeParseCXX0XAttributes(attrs);
 
@@ -3168,16 +3172,14 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
         RefQualifierLoc = ConsumeToken();
         EndLoc = RefQualifierLoc;
       }
-      
+
       // Parse exception-specification[opt].
-      if (Tok.is(tok::kw_throw)) {
-        hasExceptionSpec = true;
-        ThrowLoc = Tok.getLocation();
-        ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
-                                    hasAnyExceptionSpec);
-        assert(Exceptions.size() == ExceptionRanges.size() &&
-               "Produced different number of exception types and ranges.");
-      }
+      ESpecType = MaybeParseExceptionSpecification(ESpecRange,
+                                                   DynamicExceptions,
+                                                   DynamicExceptionRanges,
+                                                   NoexceptExpr);
+      if (ESpecType != EST_None)
+        EndLoc = ESpecRange.getEnd();
 
       // Parse trailing-return-type.
       if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
@@ -3195,11 +3197,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
                                                DS.getTypeQualifiers(),
                                                RefQualifierIsLValueRef,
                                                RefQualifierLoc,
-                                               hasExceptionSpec, ThrowLoc,
-                                               hasAnyExceptionSpec,
-                                               Exceptions.data(),
-                                               ExceptionRanges.data(),
-                                               Exceptions.size(),
+                                               ESpecType == EST_Dynamic ||
+                                                 ESpecType == EST_DynamicAny,
+                                               ESpecRange.getBegin(),
+                                               ESpecType == EST_DynamicAny,
+                                               DynamicExceptions.data(),
+                                               DynamicExceptionRanges.data(),
+                                               DynamicExceptions.size(),
                                                LParenLoc, RParenLoc, D,
                                                TrailingReturnType),
                   EndLoc);
@@ -3396,11 +3400,11 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
   DeclSpec DS;
   SourceLocation RefQualifierLoc;
   bool RefQualifierIsLValueRef = true;
-  bool hasExceptionSpec = false;
-  SourceLocation ThrowLoc;
-  bool hasAnyExceptionSpec = false;
-  llvm::SmallVector<ParsedType, 2> Exceptions;
-  llvm::SmallVector<SourceRange, 2> ExceptionRanges;
+  ExceptionSpecificationType ESpecType = EST_None;
+  SourceRange ESpecRange;
+  llvm::SmallVector<ParsedType, 2> DynamicExceptions;
+  llvm::SmallVector<SourceRange, 2> DynamicExceptionRanges;
+  ExprResult NoexceptExpr;
   
   if (getLang().CPlusPlus) {
     MaybeParseCXX0XAttributes(attrs);
@@ -3420,15 +3424,17 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
       EndLoc = RefQualifierLoc;
     }
 
+    // FIXME: We should leave the prototype scope before parsing the exception
+    // specification, and then reenter it when parsing the trailing return type.
+    // FIXMEFIXME: Why? That wouldn't be right for the noexcept clause.
+
     // Parse exception-specification[opt].
-    if (Tok.is(tok::kw_throw)) {
-      hasExceptionSpec = true;
-      ThrowLoc = Tok.getLocation();
-      ParseExceptionSpecification(EndLoc, Exceptions, ExceptionRanges,
-                                  hasAnyExceptionSpec);
-      assert(Exceptions.size() == ExceptionRanges.size() &&
-             "Produced different number of exception types and ranges.");
-    }
+    ESpecType = MaybeParseExceptionSpecification(ESpecRange,
+                                                 DynamicExceptions,
+                                                 DynamicExceptionRanges,
+                                                 NoexceptExpr);
+    if (ESpecType != EST_None)
+      EndLoc = ESpecRange.getEnd();
 
     // Parse trailing-return-type.
     if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) {
@@ -3436,9 +3442,6 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
     }
   }
 
-  // FIXME: We should leave the prototype scope before parsing the exception
-  // specification, and then reenter it when parsing the trailing return type.
-
   // Leave prototype scope.
   PrototypeScope.Exit();
 
@@ -3450,11 +3453,13 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
                                              DS.getTypeQualifiers(),
                                              RefQualifierIsLValueRef,
                                              RefQualifierLoc,
-                                             hasExceptionSpec, ThrowLoc,
-                                             hasAnyExceptionSpec,
-                                             Exceptions.data(),
-                                             ExceptionRanges.data(),
-                                             Exceptions.size(),
+                                             ESpecType == EST_Dynamic ||
+                                               ESpecType == EST_DynamicAny,
+                                             ESpecRange.getBegin(),
+                                             ESpecType == EST_DynamicAny,
+                                             DynamicExceptions.data(),
+                                             DynamicExceptionRanges.data(),
+                                             DynamicExceptions.size(),
                                              LParenLoc, RParenLoc, D,
                                              TrailingReturnType),
                 EndLoc);
index f6344248f8a5dc965ff43c6f16395b5f335db5bb..ad1d0015e11828672d3de220917348b09be0a676 100644 (file)
@@ -2001,10 +2001,76 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
                                      EllipsisLoc);
 }
 
-/// ParseExceptionSpecification - Parse a C++ exception-specification
-/// (C++ [except.spec]).
+/// \brief Parse a C++ exception-specification if present (C++0x [except.spec]).
 ///
 ///       exception-specification:
+///         dynamic-exception-specification
+///         noexcept-specification
+///
+///       noexcept-specification:
+///         'noexcept'
+///         'noexcept' '(' constant-expression ')'
+ExceptionSpecificationType
+Parser::MaybeParseExceptionSpecification(SourceRange &SpecificationRange,
+                    llvm::SmallVectorImpl<ParsedType> &DynamicExceptions,
+                    llvm::SmallVectorImpl<SourceRange> &DynamicExceptionRanges,
+                    ExprResult &NoexceptExpr) {
+  ExceptionSpecificationType Result = EST_None;
+
+  // See if there's a dynamic specification.
+  if (Tok.is(tok::kw_throw)) {
+    Result = ParseDynamicExceptionSpecification(SpecificationRange,
+                                                DynamicExceptions,
+                                                DynamicExceptionRanges);
+    assert(DynamicExceptions.size() == DynamicExceptionRanges.size() &&
+           "Produced different number of exception types and ranges.");
+  }
+
+  // If there's no noexcept specification, we're done.
+  if (Tok.isNot(tok::kw_noexcept))
+    return Result;
+
+  // If we already had a dynamic specification, parse the noexcept for,
+  // recovery, but emit a diagnostic and don't store the results.
+  SourceRange NoexceptRange;
+  ExceptionSpecificationType NoexceptType = EST_None;
+
+  SourceLocation KeywordLoc = ConsumeToken();
+  if (Tok.is(tok::l_paren)) {
+    // There is an argument.
+    SourceLocation LParenLoc = ConsumeParen();
+    NoexceptType = EST_ComputedNoexcept;
+    NoexceptExpr = ParseConstantExpression();
+    SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+    NoexceptRange = SourceRange(KeywordLoc, RParenLoc);
+  } else {
+    // There is no argument.
+    NoexceptType = EST_BasicNoexcept;
+    NoexceptRange = SourceRange(KeywordLoc, KeywordLoc);
+  }
+
+  if (Result == EST_None) {
+    SpecificationRange = NoexceptRange;
+    Result = NoexceptType;
+
+    // If there's a dynamic specification after a noexcept specification,
+    // parse that and ignore the results.
+    if (Tok.is(tok::kw_throw)) {
+      Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
+      ParseDynamicExceptionSpecification(NoexceptRange, DynamicExceptions,
+                                         DynamicExceptionRanges);
+    }
+  } else {
+    Diag(Tok.getLocation(), diag::err_dynamic_and_noexcept_specification);
+  }
+
+  return Result;
+}
+
+/// ParseDynamicExceptionSpecification - Parse a C++
+/// dynamic-exception-specification (C++ [except.spec]).
+///
+///       dynamic-exception-specification:
 ///         'throw' '(' type-id-list [opt] ')'
 /// [MS]    'throw' '(' '...' ')'
 ///
@@ -2012,46 +2078,47 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
 ///         type-id ... [opt]
 ///         type-id-list ',' type-id ... [opt]
 ///
-bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
-                                         llvm::SmallVectorImpl<ParsedType>
-                                             &Exceptions,
-                                         llvm::SmallVectorImpl<SourceRange>
-                                             &Ranges,
-                                         bool &hasAnyExceptionSpec) {
+ExceptionSpecificationType Parser::ParseDynamicExceptionSpecification(
+                                  SourceRange &SpecificationRange,
+                                  llvm::SmallVectorImpl<ParsedType> &Exceptions,
+                                  llvm::SmallVectorImpl<SourceRange> &Ranges) {
   assert(Tok.is(tok::kw_throw) && "expected throw");
 
-  ConsumeToken();
+  SpecificationRange.setBegin(ConsumeToken());
 
   if (!Tok.is(tok::l_paren)) {
-    return Diag(Tok, diag::err_expected_lparen_after) << "throw";
+    Diag(Tok, diag::err_expected_lparen_after) << "throw";
+    SpecificationRange.setEnd(SpecificationRange.getBegin());
+    return EST_Dynamic;
   }
   SourceLocation LParenLoc = ConsumeParen();
 
   // Parse throw(...), a Microsoft extension that means "this function
   // can throw anything".
   if (Tok.is(tok::ellipsis)) {
-    hasAnyExceptionSpec = true;
     SourceLocation EllipsisLoc = ConsumeToken();
     if (!getLang().Microsoft)
       Diag(EllipsisLoc, diag::ext_ellipsis_exception_spec);
-    EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-    return false;
+    SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+    SpecificationRange.setEnd(RParenLoc);
+    return EST_DynamicAny;
   }
 
   // Parse the sequence of type-ids.
   SourceRange Range;
   while (Tok.isNot(tok::r_paren)) {
     TypeResult Res(ParseTypeName(&Range));
-    
+
     if (Tok.is(tok::ellipsis)) {
       // C++0x [temp.variadic]p5:
       //   - In a dynamic-exception-specification (15.4); the pattern is a 
       //     type-id.
       SourceLocation Ellipsis = ConsumeToken();
+      Range.setEnd(Ellipsis);
       if (!Res.isInvalid())
         Res = Actions.ActOnPackExpansion(Res.get(), Ellipsis);
     }
-    
+
     if (!Res.isInvalid()) {
       Exceptions.push_back(Res.get());
       Ranges.push_back(Range);
@@ -2063,8 +2130,8 @@ bool Parser::ParseExceptionSpecification(SourceLocation &EndLoc,
       break;
   }
 
-  EndLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
-  return false;
+  SpecificationRange.setEnd(MatchRHSPunctuation(tok::r_paren, LParenLoc));
+  return EST_Dynamic;
 }
 
 /// ParseTrailingReturnType - Parse a trailing return type on a new-style
diff --git a/test/CXX/except/except.spec/p1.cpp b/test/CXX/except/except.spec/p1.cpp
new file mode 100644 (file)
index 0000000..b2cec97
--- /dev/null
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Simple parser tests, dynamic specification.
+
+namespace dyn {
+
+  struct X { };
+
+  struct Y { };
+
+  void f() throw() { }
+
+  void g(int) throw(X) { }
+
+  void h() throw(X, Y) { }
+
+  class Class {
+    void foo() throw (X, Y) { }
+  };
+
+  void (*fptr)() throw();
+
+}
+
+// Simple parser tests, noexcept specification.
+
+namespace noex {
+
+  void f() noexcept { }
+  void g() noexcept (true) { }
+  void h() noexcept (false) { }
+  void i() noexcept (1 < 2) { }
+
+  class Class {
+    void foo() noexcept { }
+    void bar() noexcept (true) { }
+  };
+
+  void (*fptr)() noexcept;
+  void (*gptr)() noexcept (true);
+
+}
+
+namespace bad {
+
+  void f() throw(int) noexcept { } // expected-error {{cannot have both}}
+  void g() noexcept throw(int) { } // expected-error {{cannot have both}}
+
+}
diff --git a/test/Parser/cxx-exception-spec.cpp b/test/Parser/cxx-exception-spec.cpp
deleted file mode 100644 (file)
index e6c3c75..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only  %s
-
-struct X { };
-
-struct Y { };
-
-void f() throw() { }
-
-void g(int) throw(X) { }
-
-void h() throw(X, Y) { }
-
-class Class {
-  void foo() throw (X, Y) { }
-};
-
-void (*fptr)() throw();