From 085a64ffc5d447a6a967bb1267396d7b6ee030e2 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Fri, 20 Jun 2014 19:57:12 +0000 Subject: [PATCH] [C++1z] Implement N3928: message in static_assert is optional. llvm-svn: 211394 --- clang/include/clang/Basic/DiagnosticSemaKinds.td | 7 ++++- clang/lib/Parse/ParseDeclCXX.cpp | 38 +++++++++++++++--------- clang/lib/Sema/SemaDeclCXX.cpp | 11 +++---- clang/test/SemaCXX/cxx0x-compat.cpp | 3 +- clang/test/SemaCXX/static-assert.cpp | 3 ++ 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f7f08fc..035a737 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -931,7 +931,12 @@ def warning_multiple_selectors: Warning< // C++ declarations def err_static_assert_expression_is_not_constant : Error< "static_assert expression is not an integral constant expression">; -def err_static_assert_failed : Error<"static_assert failed %0">; +def err_static_assert_failed : Error<"static_assert failed%select{ %1|}0">; +def ext_static_assert_no_message : ExtWarn< + "static_assert with no message is a C++1z extension">, InGroup; +def warn_cxx1y_compat_static_assert_no_message : Warning< + "static_assert with no message is incompatible with C++ standards before C++1z">, + DefaultIgnore, InGroup; def warn_inline_namespace_reopened_noninline : Warning< "inline namespace cannot be reopened as a non-inline namespace">; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 33e3cab..cd2e397 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -689,22 +689,32 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ return nullptr; } - if (ExpectAndConsume(tok::comma)) { - SkipUntil(tok::semi); - return nullptr; - } + ExprResult AssertMessage; + if (Tok.is(tok::r_paren)) { + Diag(Tok, getLangOpts().CPlusPlus1z + ? diag::warn_cxx1y_compat_static_assert_no_message + : diag::ext_static_assert_no_message) + << (getLangOpts().CPlusPlus1z + ? FixItHint() + : FixItHint::CreateInsertion(Tok.getLocation(), ", \"\"")); + } else { + if (ExpectAndConsume(tok::comma)) { + SkipUntil(tok::semi); + return nullptr; + } - if (!isTokenStringLiteral()) { - Diag(Tok, diag::err_expected_string_literal) - << /*Source='static_assert'*/1; - SkipMalformedDecl(); - return nullptr; - } + if (!isTokenStringLiteral()) { + Diag(Tok, diag::err_expected_string_literal) + << /*Source='static_assert'*/1; + SkipMalformedDecl(); + return nullptr; + } - ExprResult AssertMessage(ParseStringLiteralExpression()); - if (AssertMessage.isInvalid()) { - SkipMalformedDecl(); - return nullptr; + AssertMessage = ParseStringLiteralExpression(); + if (AssertMessage.isInvalid()) { + SkipMalformedDecl(); + return nullptr; + } } T.consumeClose(); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 85394bb..5ca53b0 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11405,7 +11405,8 @@ Decl *Sema::ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc) { - StringLiteral *AssertMessage = cast(AssertMessageExpr); + StringLiteral *AssertMessage = + AssertMessageExpr ? cast(AssertMessageExpr) : nullptr; if (DiagnoseUnexpandedParameterPack(AssertExpr, UPPC_StaticAssertExpression)) return nullptr; @@ -11419,8 +11420,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, StringLiteral *AssertMessage, SourceLocation RParenLoc, bool Failed) { - assert(AssertExpr != nullptr && AssertMessage != nullptr && - "Expected non-null Expr's"); + assert(AssertExpr != nullptr && "Expected non-null condition"); if (!AssertExpr->isTypeDependent() && !AssertExpr->isValueDependent() && !Failed) { // In a static_assert-declaration, the constant-expression shall be a @@ -11438,9 +11438,10 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, if (!Failed && !Cond) { SmallString<256> MsgBuffer; llvm::raw_svector_ostream Msg(MsgBuffer); - AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); + if (AssertMessage) + AssertMessage->printPretty(Msg, nullptr, getPrintingPolicy()); Diag(StaticAssertLoc, diag::err_static_assert_failed) - << Msg.str() << AssertExpr->getSourceRange(); + << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); Failed = true; } } diff --git a/clang/test/SemaCXX/cxx0x-compat.cpp b/clang/test/SemaCXX/cxx0x-compat.cpp index ffbd20f..a58a7f8 100644 --- a/clang/test/SemaCXX/cxx0x-compat.cpp +++ b/clang/test/SemaCXX/cxx0x-compat.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++98 -Wc++11-compat -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++1y -Wc++11-compat -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++1z -Wc++11-compat -verify %s #if __cplusplus < 201103L @@ -44,5 +44,6 @@ char c = 'x'_x; // expected-warning {{will be treated as a user-defined literal #else auto init_capture = [a(0)] {}; // expected-warning {{initialized lambda captures are incompatible with C++ standards before C++1y}} +static_assert(true); // expected-warning {{incompatible with C++ standards before C++1z}} #endif diff --git a/clang/test/SemaCXX/static-assert.cpp b/clang/test/SemaCXX/static-assert.cpp index 4a7560b..c9d9384 100644 --- a/clang/test/SemaCXX/static-assert.cpp +++ b/clang/test/SemaCXX/static-assert.cpp @@ -48,3 +48,6 @@ template struct StaticAssertProtected { struct X { ~X(); }; StaticAssertProtected sap1; StaticAssertProtected sap2; // expected-note {{instantiation}} + +static_assert(true); // expected-warning {{C++1z extension}} +static_assert(false); // expected-error-re {{failed$}} expected-warning {{extension}} -- 2.7.4