bool isAddressOfOperand = false,
TypeCastState isTypeCast = NotTypeCast);
+ /// Returns true if the next token cannot start an expression.
+ bool isNotExpressionStart();
+
/// Returns true if the next token would start a postfix-expression
/// suffix.
bool isPostfixExpressionSuffixStart() {
/// specifier or if we're not sure.
bool isKnownToBeTypeSpecifier(const Token &Tok) const;
+ /// \brief Return true if we know that we are definitely looking at a
+ /// decl-specifier, and isn't part of an expression such as a function-style
+ /// cast. Return false if it's no a decl-specifier, or we're not sure.
+ bool isKnownToBeDeclarationSpecifier() {
+ if (getLangOpts().CPlusPlus)
+ return isCXXDeclarationSpecifier() == TPResult::True();
+ return isDeclarationSpecifier(true);
+ }
+
/// isDeclarationStatement - Disambiguates between a declaration or an
/// expression statement, when parsing function bodies.
/// Returns true for declaration, false for expression.
return Actions.ActOnConstantExpression(Res);
}
+bool Parser::isNotExpressionStart() {
+ tok::TokenKind K = Tok.getKind();
+ if (K == tok::l_brace || K == tok::r_brace ||
+ K == tok::kw_for || K == tok::kw_while ||
+ K == tok::kw_if || K == tok::kw_else ||
+ K == tok::kw_goto || K == tok::kw_try)
+ return true;
+ // If this is a decl-specifier, we can't be at the start of an expression.
+ return isKnownToBeDeclarationSpecifier();
+}
+
/// \brief Parse a binary expression that starts with \p LHS and has a
/// precedence of at least \p MinPrec.
ExprResult
Token OpToken = Tok;
ConsumeToken();
+ // Bail out when encountering a comma followed by a token which can't
+ // possibly be the start of an expression. For instance:
+ // int f() { return 1, }
+ // We can't do this before consuming the comma, because
+ // isNotExpressionStart() looks at the token stream.
+ if (OpToken.is(tok::comma) && isNotExpressionStart()) {
+ PP.EnterToken(Tok);
+ Tok = OpToken;
+ return LHS;
+ }
+
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
if (NextTokPrec == prec::Conditional) {
static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) {
switch (ExpectedTok) {
- case tok::semi: return Tok.is(tok::colon); // : for ;
+ case tok::semi:
+ return Tok.is(tok::colon) || Tok.is(tok::comma); // : or , for ;
default: return false;
}
}
&a == &b ? oopsMoreCommas() : removeUnusedLabels(a[0]);
}
+int commaAtEndOfStatement() {
+ int a = 1;
+ a = 5, // expected-error {{';'}}
+ int m = 5, // expected-error {{';'}}
+ return 0, // expected-error {{';'}}
+}
+
int noSemiAfterLabel(int n) {
switch (n) {
default:
asm volatile ("":: :"memory");
asm volatile ("": ::"memory");
}
+
+int f6() {
+ int k, // expected-note {{change this ',' to a ';' to call 'f6'}}
+ f6(), // expected-error {{expected ';'}} expected-warning {{interpreted as a function declaration}} expected-note {{replace paren}}
+ int n = 0, // expected-error {{expected ';'}}
+ return f5(), // ok
+ int(n);
+}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11
+
+struct S {
+ S(int, int) {}
+};
+
+void f(int, S const&, int) {}
+
+void test1()
+{
+ S X1{1, 1,};
+ S X2 = {1, 1,};
+
+ f(0, {1, 1}, 0);
+}
// Should not skip '}' and produce a "expected '}'" error.
undecl // expected-error {{use of undeclared identifier 'undecl'}}
}
+
+int test9() {
+ int T[] = {1, 2, };
+
+ int X;
+ X = 0, // expected-error {{expected ';' after expression}}
+ {
+ }
+
+ X = 0, // expected-error {{expected ';' after expression}}
+ if (0)
+ ;
+
+ return 4, // expected-error {{expected ';' after return statement}}
+}