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/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(LastStmt)) + break; + } LabelStmt *LastLabelStmt = nullptr; // If LastStmt is a label, skip down through into the body. while (LabelStmt *Label = dyn_cast(LastStmt)) { 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:;;}); }