diff options
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 15 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 9 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 85 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 101 | ||||
-rw-r--r-- | test/CXX/except/except.spec/p1.cpp | 49 | ||||
-rw-r--r-- | test/Parser/cxx-exception-spec.cpp | 17 |
7 files changed, 200 insertions, 78 deletions
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 9a68af9c45..acf38e4f0f 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -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< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 78bd04b6bd..b8ae999fe5 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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 diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index 2f34347533..1567baaaad 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/include/clang/Sema/DeclSpec.h @@ -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. /// diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 50ba7054fe..5cda4e6d5c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index f6344248f8..ad1d0015e1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -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 index 0000000000..b2cec97d78 --- /dev/null +++ b/test/CXX/except/except.spec/p1.cpp @@ -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 index e6c3c757f0..0000000000 --- a/test/Parser/cxx-exception-spec.cpp +++ /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(); |