From c4027c82ad4a61f2da1b893ac8fe47bf11e5d50d Mon Sep 17 00:00:00 2001 From: David Blaikie Date: Sat, 10 Nov 2012 01:04:23 +0000 Subject: PR14296: function parameter name collisions in function try/catch C++11 3.3.3/2 "A parameter name shall not be redeclared in the outermost block of the function definition nor in the outermost block of any handler associated with a function-try-block." It's not totally clear to me whether the "FIXME" case is covered by this, but Richard Smith thinks it probably should be. It's just a bit more involved to fix that case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167650 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Parser.h | 4 ++-- include/clang/Sema/Scope.h | 8 ++++++- lib/Parse/ParseStmt.cpp | 14 ++++++------ lib/Sema/IdentifierResolver.cpp | 7 +++++- .../CXX/basic/basic.scope/basic.scope.local/p2.cpp | 25 ++++++++++++++++++++++ 5 files changed, 48 insertions(+), 10 deletions(-) create mode 100644 test/CXX/basic/basic.scope/basic.scope.local/p2.cpp diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0968d9c276..c433344602 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1563,8 +1563,8 @@ private: // C++ 6: Statements and Blocks StmtResult ParseCXXTryBlock(); - StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc); - StmtResult ParseCXXCatchBlock(); + StmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry = false); + StmtResult ParseCXXCatchBlock(bool FnCatch = false); //===--------------------------------------------------------------------===// // MS: SEH Statements and Blocks diff --git a/include/clang/Sema/Scope.h b/include/clang/Sema/Scope.h index b78556e65a..fa508cfc22 100644 --- a/include/clang/Sema/Scope.h +++ b/include/clang/Sema/Scope.h @@ -82,7 +82,13 @@ public: SwitchScope = 0x800, /// TryScope - This is the scope of a C++ try statement. - TryScope = 0x1000 + TryScope = 0x1000, + + /// FnTryScope - This is the scope of a function-level C++ try scope. + FnTryScope = 0x3000, + + /// FnCatchScope - This is the scope of a function-level C++ catch scope. + FnCatchScope = 0x4000 }; private: /// The parent scope for this scope. This is null for the translation-unit diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 4b5bdc24bb..f604e038d2 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -2051,7 +2051,7 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { } SourceLocation LBraceLoc = Tok.getLocation(); - StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); + StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true)); // If we failed to parse the try-catch, we just give the function an empty // compound statement as the body. if (FnBody.isInvalid()) { @@ -2117,13 +2117,14 @@ StmtResult Parser::ParseCXXTryBlock() { /// 'try' compound-statement seh-except-block /// 'try' compound-statment seh-finally-block /// -StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { +StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope|Scope::TryScope)); + Scope::DeclScope | + (FnTry ? Scope::FnTryScope : Scope::TryScope))); if (TryBlock.isInvalid()) return TryBlock; @@ -2159,7 +2160,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { - StmtResult Handler(ParseCXXCatchBlock()); + StmtResult Handler(ParseCXXCatchBlock(FnTry)); if (!Handler.isInvalid()) Handlers.push_back(Handler.release()); } @@ -2183,7 +2184,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { /// type-specifier-seq /// '...' /// -StmtResult Parser::ParseCXXCatchBlock() { +StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); SourceLocation CatchLoc = ConsumeToken(); @@ -2195,7 +2196,8 @@ StmtResult Parser::ParseCXXCatchBlock() { // C++ 3.3.2p3: // The name in a catch exception-declaration is local to the handler and // shall not be redeclared in the outermost block of the handler. - ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope); + ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope | + (FnCatch ? Scope::FnCatchScope : 0)); // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 4d62cab167..50413c3d95 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -135,8 +135,13 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, // of the controlled statement. // assert(S->getParent() && "No TUScope?"); - if (S->getParent()->getFlags() & Scope::ControlScope) + if (S->getFlags() & Scope::FnTryScope) return S->getParent()->isDeclScope(D); + if (S->getParent()->getFlags() & Scope::ControlScope) { + if (S->getParent()->getFlags() & Scope::FnCatchScope) + S = S->getParent(); + return S->getParent()->isDeclScope(D); + } } return false; } diff --git a/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp b/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp new file mode 100644 index 0000000000..624118cc36 --- /dev/null +++ b/test/CXX/basic/basic.scope/basic.scope.local/p2.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -fcxx-exceptions -fexceptions -verify %s + +void func1(int i) { // expected-note{{previous definition is here}} + int i; // expected-error{{redefinition of 'i'}} +} + +void func2(int i) try { // expected-note{{previous definition is here}} + int i; // expected-error{{redefinition of 'i'}} +} catch (...) { +} + +void func3(int i) try { // FIXME: note {{previous definition is here}} +} catch (int i) { // FIXME: error {{redefinition of 'i'}} +} + +void func4(int i) try { // expected-note{{previous definition is here}} +} catch (...) { + int i; // expected-error{{redefinition of 'i'}} +} + +void func5() try { + int i; +} catch (...) { + int j = i; // expected-error{{use of undeclared identifier 'i'}} +} -- cgit v1.2.3