From: Richard Smith Date: Sat, 15 Oct 2011 05:09:34 +0000 (+0000) Subject: Implement -Wc++98-compat warnings for the parser. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7fe6208c3fa91f835813bb78236ef5c2bbf81053;p=clang Implement -Wc++98-compat warnings for the parser. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142056 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 59fc1d6ea8..bd4970f98d 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -23,6 +23,9 @@ let CategoryName = "Parse Issue" in { def ext_empty_source_file : Extension<"ISO C forbids an empty source file">; def ext_top_level_semi : Extension< "extra ';' outside of a function">; +def warn_cxx98_compat_top_level_semi : Warning< + "extra ';' outside of a function is incompatible with C++98">, + InGroup, DefaultIgnore; def ext_extra_struct_semi : Extension< "extra ';' inside a %0">; def ext_extra_ivar_semi : Extension< @@ -55,6 +58,9 @@ def ext_c99_compound_literal : Extension< def ext_enumerator_list_comma : Extension< "commas at the end of enumerator lists are a %select{C99|C++11}0-specific " "feature">; +def warn_cxx98_compat_enumerator_list_comma : Warning< + "commas at the end of enumerator lists are incompatible with C++98">, + InGroup, DefaultIgnore; def err_enumerator_list_missing_comma : Error< "missing ',' between enumerators">; def err_enumerator_unnamed_no_def : Error< @@ -62,6 +68,9 @@ def err_enumerator_unnamed_no_def : Error< def ext_ms_enum_fixed_underlying_type : Extension< "enumeration types with a fixed underlying type are a Microsoft extension">, InGroup; +def warn_cxx98_compat_enum_fixed_underlying_type : Warning< + "enumeration types with a fixed underlying type are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_c1x_generic_selection : Extension< "generic selections are a C1X-specific feature">, InGroup; @@ -188,15 +197,30 @@ def err_illegal_decl_reference_to_reference : Error< "%0 declared as a reference to a reference">; def ext_rvalue_reference : ExtWarn< "rvalue references are a C++11 extension">, InGroup; +def warn_cxx98_compat_rvalue_reference : Warning< + "rvalue references are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_ref_qualifier : ExtWarn< "reference qualifiers on functions are a C++11 extension">, InGroup; +def warn_cxx98_compat_ref_qualifier : Warning< + "reference qualifiers on functions are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_inline_namespace : ExtWarn< "inline namespaces are a C++11 feature">, InGroup; +def warn_cxx98_compat_inline_namespace : Warning< + "inline namespaces are incompatible with C++98">, + InGroup, DefaultIgnore; def err_generalized_initializer_lists : Error< "generalized initializer lists are a C++11 extension unsupported in Clang">; def ext_generalized_initializer_lists : ExtWarn< "generalized initializer lists are a C++11 extension unsupported in Clang">, InGroup; +def warn_cxx98_compat_generalized_initializer_lists : Warning< + "generalized initializer lists are incompatible with C++98">, + InGroup, DefaultIgnore; +def warn_cxx98_compat_trailing_return_type : Warning< + "trailing return types are incompatible with C++98">, + InGroup, DefaultIgnore; def ext_auto_type_specifier : ExtWarn< "'auto' type specifier is a C++11 extension">, InGroup; def warn_auto_storage_class : Warning< @@ -207,6 +231,9 @@ def ext_auto_storage_class : ExtWarn< "be supported in future releases">; def ext_for_range : ExtWarn< "range-based for loop is a C++11 extension">, InGroup; +def warn_cxx98_compat_for_range : Warning< + "range-based for loop is incompatible with C++98">, + InGroup, DefaultIgnore; def err_argument_required_after_attribute : Error< "argument required after attribute">; def err_missing_param : Error<"expected parameter declarator">; @@ -363,6 +390,9 @@ def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; // C++ operator overloading def err_operator_string_not_empty : Error< "string literal after 'operator' must be '\"\"'">; +def warn_cxx98_compat_literal_operator : Warning< + "literal operators are incompatible with C++98">, + InGroup, DefaultIgnore; // Classes. def err_anon_type_definition : Error< @@ -405,6 +435,9 @@ def err_two_right_angle_brackets_need_space : Error< def warn_cxx0x_right_shift_in_template_arg : Warning< "use of right-shift operator ('>>') in template argument will require " "parentheses in C++11">; +def warn_cxx98_compat_two_right_angle_brackets : Warning< + "consecutive right angle brackets are incompatible with C++98 (use '> >')">, + InGroup, DefaultIgnore; def err_multiple_template_declarators : Error< "%select{|a template declaration|an explicit template specialization|" "an explicit template instantiation}0 can " @@ -466,14 +499,23 @@ def err_missing_whitespace_digraph : Error< def warn_deleted_function_accepted_as_extension: ExtWarn< "deleted function definition accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_deleted_function : Warning< + "deleted function definitions are incompatible with C++98">, + InGroup, DefaultIgnore; def warn_defaulted_function_accepted_as_extension: ExtWarn< "defaulted function definition accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_defaulted_function : Warning< + "defaulted function definitions are incompatible with C++98">, + InGroup, DefaultIgnore; // C++11 in-class member initialization def ext_nonstatic_member_init : ExtWarn< "in-class initialization of non-static data member accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_nonstatic_member_init : Warning< + "in-class initialization of non-static data members is incompatible with C++98">, + InGroup, DefaultIgnore; def err_bitfield_member_init: Error< "bitfield member cannot have an in-class initializer">; def err_incomplete_array_member_init: Error< @@ -482,6 +524,9 @@ def err_incomplete_array_member_init: Error< // C++11 alias-declaration def ext_alias_declaration : ExtWarn< "alias declarations accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_alias_declaration : Warning< + "alias declarations are incompatible with C++98">, + InGroup, DefaultIgnore; def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; def err_alias_declaration_specialization : Error< @@ -490,6 +535,9 @@ def err_alias_declaration_specialization : Error< // C++11 override control def ext_override_control_keyword : ExtWarn< "'%0' keyword accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_override_control_keyword : Warning< + "'%0' keyword is incompatible with C++98">, + InGroup, DefaultIgnore; def err_duplicate_virt_specifier : Error< "class member already marked '%0'">; @@ -498,6 +546,9 @@ def err_duplicate_class_virt_specifier : Error< def err_scoped_enum_missing_identifier : Error< "scoped enumeration requires a name">; +def warn_cxx98_compat_scoped_enum : Warning< + "scoped enumerations are incompatible with C++98">, + InGroup, DefaultIgnore; def err_expected_parameter_pack : Error< "expected the name of a parameter pack">; @@ -514,6 +565,9 @@ def err_this_captured_by_reference : Error< def err_expected_capture : Error< "expected variable name or 'this' in lambda capture list">; def err_expected_lambda_body : Error<"expected body of lambda expression">; +def warn_cxx98_compat_lambda : Warning< + "lambda expressions are incompatible with C++98">, + InGroup, DefaultIgnore; // Availability attribute def err_expected_version : Error< diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index b387e9e551..c9107b466d 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -67,15 +67,17 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, bool Delete = false; SourceLocation KWLoc; if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::warn_deleted_function_accepted_as_extension); KWLoc = ConsumeToken(); Actions.SetDeclDeleted(FnD, KWLoc); Delete = true; } else if (Tok.is(tok::kw_default)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::warn_defaulted_function_accepted_as_extension); KWLoc = ConsumeToken(); Actions.SetDeclDefaulted(FnD, KWLoc); diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 2aa178f5eb..948309a8ec 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1276,6 +1276,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } } else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { // Parse C++0x braced-init-list. + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + if (D.getCXXScopeSpec().isSet()) { EnterScope(0); Actions.ActOnCXXEnterDeclInitializer(getCurScope(), ThisDecl); @@ -2778,6 +2780,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (getLang().CPlusPlus0x && (Tok.is(tok::kw_class) || Tok.is(tok::kw_struct))) { + Diag(Tok, diag::warn_cxx98_compat_scoped_enum); IsScopedEnum = true; IsScopedUsingClassTag = Tok.is(tok::kw_class); ConsumeToken(); @@ -2894,6 +2897,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (!getLang().CPlusPlus0x && !getLang().ObjC2) Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) << Range; + if (getLang().CPlusPlus0x) + Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type); } } @@ -3054,11 +3059,15 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { break; SourceLocation CommaLoc = ConsumeToken(); - if (Tok.isNot(tok::identifier) && - !(getLang().C99 || getLang().CPlusPlus0x)) - Diag(CommaLoc, diag::ext_enumerator_list_comma) - << getLang().CPlusPlus - << FixItHint::CreateRemoval(CommaLoc); + if (Tok.isNot(tok::identifier)) { + if (!getLang().C99 && !getLang().CPlusPlus0x) + Diag(CommaLoc, diag::ext_enumerator_list_comma) + << getLang().CPlusPlus + << FixItHint::CreateRemoval(CommaLoc); + else if (getLang().CPlusPlus0x) + Diag(CommaLoc, diag::warn_cxx98_compat_enumerator_list_comma) + << FixItHint::CreateRemoval(CommaLoc); + } } // Eat the }. @@ -3682,8 +3691,10 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Complain about rvalue references in C++03, but then go on and build // the declarator. - if (Kind == tok::ampamp && !getLang().CPlusPlus0x) - Diag(Loc, diag::ext_rvalue_reference); + if (Kind == tok::ampamp) + Diag(Loc, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_rvalue_reference : + diag::ext_rvalue_reference); // C++ 8.3.2p1: cv-qualified references are ill-formed except when the // cv-qualifiers are introduced through the use of a typedef or of a @@ -4080,8 +4091,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // Parse ref-qualifier[opt]. if (Tok.is(tok::amp) || Tok.is(tok::ampamp)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_ref_qualifier); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_ref_qualifier : + diag::ext_ref_qualifier); RefQualifierIsLValueRef = Tok.is(tok::amp); RefQualifierLoc = ConsumeToken(); @@ -4098,6 +4110,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // Parse trailing-return-type[opt]. if (getLang().CPlusPlus0x && Tok.is(tok::arrow)) { + Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range).get(); if (Range.getEnd().isValid()) diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b9e2e9e701..09f8ab2fc1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -148,8 +148,9 @@ Decl *Parser::ParseNamespace(unsigned Context, } // If we're still good, complain about inline namespaces in non-C++0x now. - if (!getLang().CPlusPlus0x && InlineLoc.isValid()) - Diag(InlineLoc, diag::ext_inline_namespace); + if (InlineLoc.isValid()) + Diag(InlineLoc, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_inline_namespace : diag::ext_inline_namespace); // Enter a scope for the namespace. ParseScope NamespaceScope(this, Scope::DeclScope); @@ -481,8 +482,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, // Where can GNU attributes appear? ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_alias_declaration); + Diag(Tok.getLocation(), getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_alias_declaration : + diag::ext_alias_declaration); // Type alias templates cannot be specialized. int SpecKind = -1; @@ -1516,9 +1518,10 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - if (!getLang().CPlusPlus0x) - Diag(Tok.getLocation(), diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + Diag(Tok.getLocation(), getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); ConsumeToken(); } } @@ -1884,9 +1887,10 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // Handle the initializer. if (HasDeferredInitializer) { // The initializer was deferred; parse it and cache the tokens. - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_nonstatic_member_init); - + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_nonstatic_member_init : + diag::ext_nonstatic_member_init); + if (DeclaratorInfo.isArrayOfUnknownBound()) { // C++0x [dcl.array]p3: An array bound may also be omitted when the // declarator is followed by an initializer. @@ -2075,8 +2079,9 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, assert(isCXX0XFinalKeyword() && "not a class definition"); FinalLoc = ConsumeToken(); - if (!getLang().CPlusPlus0x) - Diag(FinalLoc, diag::ext_override_control_keyword) << "final"; + Diag(FinalLoc, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) << "final"; } if (Tok.is(tok::colon)) { @@ -2318,6 +2323,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { // Parse the '('. if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + ExprResult InitList = ParseBraceInitializer(); if (InitList.isInvalid()) return true; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index bc8bbf5640..aa86bb4d71 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -949,6 +949,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(Diag(Tok, diag::err_expected_lparen_after_type) << DS.getSourceRange()); + if (Tok.is(tok::l_brace)) + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); + Res = ParseCXXTypeConstructExpression(DS); break; } @@ -1207,9 +1210,10 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { T.consumeOpen(); Loc = T.getOpenLocation(); ExprResult Idx; - if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Idx = ParseBraceInitializer(); - else + } else Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); @@ -2157,9 +2161,10 @@ bool Parser::ParseExpressionList(SmallVectorImpl &Exprs, } ExprResult Expr; - if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) + if (getLang().CPlusPlus0x && Tok.is(tok::l_brace)) { + Diag(Tok, diag::warn_cxx98_compat_generalized_initializer_lists); Expr = ParseBraceInitializer(); - else + } else Expr = ParseAssignmentExpression(); if (Tok.is(tok::ellipsis)) diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index d079aa1d3d..33348a9aab 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -679,6 +679,8 @@ bool Parser::TryParseLambdaIntroducer(LambdaIntroducer &Intro) { /// expression. ExprResult Parser::ParseLambdaExpressionAfterIntroducer( LambdaIntroducer &Intro) { + Diag(Intro.Range.getBegin(), diag::warn_cxx98_compat_lambda); + // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::PrototypeContext); @@ -1743,6 +1745,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // operator "" identifier if (getLang().CPlusPlus0x && Tok.is(tok::string_literal)) { + Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); if (Tok.getLength() != 2) Diag(Tok.getLocation(), diag::err_operator_string_not_empty); ConsumeStringToken(); @@ -2104,6 +2107,8 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } } else if (Tok.is(tok::l_brace) && getLang().CPlusPlus0x) { + Diag(Tok.getLocation(), + diag::warn_cxx98_compat_generalized_initializer_lists); // FIXME: Have to communicate the init-list to ActOnCXXNew. ParseBraceInitializer(); } diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index a2b7cdd81b..3df761af44 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -1326,8 +1326,8 @@ StmtResult Parser::ParseForStatement(ParsedAttributes &attrs) { FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInit.ParsedForRangeDecl()) { - if (!getLang().CPlusPlus0x) - Diag(ForRangeInit.ColonLoc, diag::ext_for_range); + Diag(ForRangeInit.ColonLoc, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_for_range : diag::ext_for_range); ForRange = true; } else if (Tok.is(tok::semi)) { // for (int x = 4; @@ -1569,8 +1569,10 @@ StmtResult Parser::ParseReturnStatement(ParsedAttributes &attrs) { // parse libstdc++ 4.5's headers. if (Tok.is(tok::l_brace) && getLang().CPlusPlus) { R = ParseInitializer(); - if (R.isUsable() && !getLang().CPlusPlus0x) - Diag(R.get()->getLocStart(), diag::ext_generalized_initializer_lists) + if (R.isUsable()) + Diag(R.get()->getLocStart(), getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_generalized_initializer_lists : + diag::ext_generalized_initializer_lists) << R.get()->getSourceRange(); } else R = ParseExpression(); diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 3d68a4ab9d..b485f1e977 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -709,15 +709,15 @@ Parser::ParseTemplateIdAfterTemplateName(TemplateTy Template, RAngleLoc = Tok.getLocation(); if (Tok.is(tok::greatergreater)) { - if (!getLang().CPlusPlus0x) { - const char *ReplaceStr = "> >"; - if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) - ReplaceStr = "> > "; - - Diag(Tok.getLocation(), diag::err_two_right_angle_brackets_need_space) - << FixItHint::CreateReplacement( - SourceRange(Tok.getLocation()), ReplaceStr); - } + const char *ReplaceStr = "> >"; + if (NextToken().is(tok::greater) || NextToken().is(tok::greatergreater)) + ReplaceStr = "> > "; + + Diag(Tok.getLocation(), getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_two_right_angle_brackets : + diag::err_two_right_angle_brackets_need_space) + << FixItHint::CreateReplacement(SourceRange(Tok.getLocation()), + ReplaceStr); Tok.setKind(tok::greater); if (!ConsumeLastToken) { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index c90964381f..2a1e2a2de8 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -535,9 +535,9 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Decl *SingleDecl = 0; switch (Tok.getKind()) { case tok::semi: - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::ext_top_level_semi) - << FixItHint::CreateRemoval(Tok.getLocation()); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_top_level_semi : diag::ext_top_level_semi) + << FixItHint::CreateRemoval(Tok.getLocation()); ConsumeToken(); // TODO: Invoke action for top-level semicolon. @@ -918,15 +918,17 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, bool Delete = false; SourceLocation KWLoc; if (Tok.is(tok::kw_delete)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_deleted_function_accepted_as_extension); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_deleted_function : + diag::warn_deleted_function_accepted_as_extension); KWLoc = ConsumeToken(); Actions.SetDeclDeleted(Res, KWLoc); Delete = true; } else if (Tok.is(tok::kw_default)) { - if (!getLang().CPlusPlus0x) - Diag(Tok, diag::warn_defaulted_function_accepted_as_extension); + Diag(Tok, getLang().CPlusPlus0x ? + diag::warn_cxx98_compat_defaulted_function : + diag::warn_defaulted_function_accepted_as_extension); KWLoc = ConsumeToken(); Actions.SetDeclDefaulted(Res, KWLoc); diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp index 2ca0ae4d1e..b1fd807e75 100644 --- a/test/SemaCXX/cxx98-compat-pedantic.cpp +++ b/test/SemaCXX/cxx98-compat-pedantic.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat-pedantic -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -Werror %s // RUN: %clang_cc1 -fsyntax-only -std=c++98 -Werror %s // -Wc++98-compat-pedantic warns on C++11 features which we accept without a @@ -9,3 +10,9 @@ #define VA_MACRO(x, ...) x // expected-warning {{variadic macros are incompatible with C++98}} VA_MACRO(,x) // expected-warning {{empty macro argument list is incompatible with C++98}} + +; // expected-warning {{extra ';' outside of a function is incompatible with C++98}} + +enum Enum { + Enum_value, // expected-warning {{commas at the end of enumerator lists are incompatible with C++98}} +}; diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index 6a3881cf42..d4c433e008 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -27,4 +27,63 @@ void Literals() { } template struct S {}; -S<::S > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}} +namespace TemplateParsing { + S<::S > s; // expected-warning {{'<::' is treated as digraph '<:' (aka '[') followed by ':' in C++98}} + S< ::S> t; // expected-warning {{consecutive right angle brackets are incompatible with C++98 (use '> >')}} +} + +void Lambda() { + []{}; // expected-warning {{lambda expressions are incompatible with C++98}} +} + +int InitList() { + (void)new int {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} + (void)int{}; // expected-warning {{generalized initializer lists are incompatible with C++98}} + int x {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} + return {}; // expected-warning {{generalized initializer lists are incompatible with C++98}} +} + +int operator""_hello(const char *); // expected-warning {{literal operators are incompatible with C++98}} + +enum EnumFixed : int { // expected-warning {{enumeration types with a fixed underlying type are incompatible with C++98}} +}; + +enum class EnumScoped { // expected-warning {{scoped enumerations are incompatible with C++98}} +}; + +void Deleted() = delete; // expected-warning {{deleted function definitions are incompatible with C++98}} +struct Defaulted { + Defaulted() = default; // expected-warning {{defaulted function definitions are incompatible with C++98}} +}; + +int &&RvalueReference = 0; // expected-warning {{rvalue references are incompatible with C++98}} +struct RefQualifier { + void f() &; // expected-warning {{reference qualifiers on functions are incompatible with C++98}} +}; + +auto f() -> int; // expected-warning {{trailing return types are incompatible with C++98}} + +void RangeFor() { + int xs[] = {1, 2, 3}; + for (int &a : xs) { // expected-warning {{range-based for loop is incompatible with C++98}} + } +} + +struct InClassInit { + int n = 0; // expected-warning {{in-class initialization of non-static data members is incompatible with C++98}} +}; + +struct OverrideControlBase { + virtual void f(); + virtual void g(); +}; +struct OverrideControl final : OverrideControlBase { // expected-warning {{'final' keyword is incompatible with C++98}} + virtual void f() override; // expected-warning {{'override' keyword is incompatible with C++98}} + virtual void g() final; // expected-warning {{'final' keyword is incompatible with C++98}} +}; + +using AliasDecl = int; // expected-warning {{alias declarations are incompatible with C++98}} +template using AliasTemplate = T; // expected-warning {{alias declarations are incompatible with C++98}} + +inline namespace N { // expected-warning {{inline namespaces are incompatible with C++98}} +}