domdom created this revision. domdom added reviewers: lattner, rsmith. Herald added a subscriber: cfe-commits.
Ignore trailing NullStmts in compound expressions when determining the result type and value. This is to match the GCC behavior which ignores semicolons at the end of compound expressions. Repository: rC Clang https://reviews.llvm.org/D57086 Files: clang/lib/Parse/ParseStmt.cpp clang/lib/Sema/SemaExpr.cpp clang/test/Sema/statements.c Index: clang/test/Sema/statements.c =================================================================== --- clang/test/Sema/statements.c +++ clang/test/Sema/statements.c @@ -119,3 +119,17 @@ SIZE = sizeof(({unsigned long __ptr; __ptr;})) }; } + +// GCC ignores empty statements at the end of compound expressions where the +// result type is concerned. +void test13() { + int a; + a = ({1;}); + a = ({1;;}); + a = ({int x = 1; (void)x;}); // expected-error {{assigning to 'int' from incompatible type 'void'}} + a = ({int x = 1; (void)x;;}); // expected-error {{assigning to 'int' from incompatible type 'void'}} +} + +void test14() { return ({}); } +void test15() { return ({;;;;}); } +void test16() { return ({test:;;}); } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -13320,11 +13320,22 @@ // More semantic analysis is needed. // If there are sub-stmts in the compound stmt, take the type of the last one - // as the type of the stmtexpr. + // as the type of the stmtexpr. For GCC compatibility this excludes trailing + // NullStmts QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { - Stmt *LastStmt = Compound->body_back(); + // GCC ignores empty statements at the end of compound expressions + // i.e. ({ 5;;; }) + // ^^ ignored + // This code skips past these NullStmts + Stmt *LastStmt = nullptr; + for (Stmt *I : llvm::make_range(Compound->body_rbegin(), + Compound->body_rend())) { + LastStmt = I; + if (!isa<NullStmt>(LastStmt)) + break; + } LabelStmt *LastLabelStmt = nullptr; // If LastStmt is a label, skip down through into the body. while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) { Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -959,10 +959,18 @@ bool Parser::isExprValueDiscarded() { if (Actions.isCurCompoundStmtAStmtExpr()) { - // Look to see if the next two tokens close the statement expression; - // if so, this expression statement is the last statement in a - // statment expression. - return Tok.isNot(tok::r_brace) || NextToken().isNot(tok::r_paren); + // For gcc compatibility we skip past NullStmts + int lookahead = 0; + while(GetLookAheadToken(lookahead).is(tok::semi)) { + lookahead++; + } + + // Then look to see if the next two tokens close the statement expression; + // if so, this expression statement is the last statement in a statment + // expression. + + return GetLookAheadToken(lookahead).isNot(tok::r_brace) || + GetLookAheadToken(lookahead + 1).isNot(tok::r_paren); } return true; }
Index: clang/test/Sema/statements.c =================================================================== --- clang/test/Sema/statements.c +++ clang/test/Sema/statements.c @@ -119,3 +119,17 @@ SIZE = sizeof(({unsigned long __ptr; __ptr;})) }; } + +// GCC ignores empty statements at the end of compound expressions where the +// result type is concerned. +void test13() { + int a; + a = ({1;}); + a = ({1;;}); + a = ({int x = 1; (void)x;}); // expected-error {{assigning to 'int' from incompatible type 'void'}} + a = ({int x = 1; (void)x;;}); // expected-error {{assigning to 'int' from incompatible type 'void'}} +} + +void test14() { return ({}); } +void test15() { return ({;;;;}); } +void test16() { return ({test:;;}); } Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -13320,11 +13320,22 @@ // More semantic analysis is needed. // If there are sub-stmts in the compound stmt, take the type of the last one - // as the type of the stmtexpr. + // as the type of the stmtexpr. For GCC compatibility this excludes trailing + // NullStmts QualType Ty = Context.VoidTy; bool StmtExprMayBindToTemp = false; if (!Compound->body_empty()) { - Stmt *LastStmt = Compound->body_back(); + // GCC ignores empty statements at the end of compound expressions + // i.e. ({ 5;;; }) + // ^^ ignored + // This code skips past these NullStmts + Stmt *LastStmt = nullptr; + for (Stmt *I : llvm::make_range(Compound->body_rbegin(), + Compound->body_rend())) { + LastStmt = I; + if (!isa<NullStmt>(LastStmt)) + break; + } LabelStmt *LastLabelStmt = nullptr; // If LastStmt is a label, skip down through into the body. while (LabelStmt *Label = dyn_cast<LabelStmt>(LastStmt)) { Index: clang/lib/Parse/ParseStmt.cpp =================================================================== --- clang/lib/Parse/ParseStmt.cpp +++ clang/lib/Parse/ParseStmt.cpp @@ -959,10 +959,18 @@ bool Parser::isExprValueDiscarded() { if (Actions.isCurCompoundStmtAStmtExpr()) { - // Look to see if the next two tokens close the statement expression; - // if so, this expression statement is the last statement in a - // statment expression. - return Tok.isNot(tok::r_brace) || NextToken().isNot(tok::r_paren); + // For gcc compatibility we skip past NullStmts + int lookahead = 0; + while(GetLookAheadToken(lookahead).is(tok::semi)) { + lookahead++; + } + + // Then look to see if the next two tokens close the statement expression; + // if so, this expression statement is the last statement in a statment + // expression. + + return GetLookAheadToken(lookahead).isNot(tok::r_brace) || + GetLookAheadToken(lookahead + 1).isNot(tok::r_paren); } return true; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits