From ebaf0e6ab743394dda086a01b457838cb6e589a8 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Tue, 18 Oct 2011 20:49:44 +0000 Subject: [PATCH] -Wc++98-compat and -Wc++98-compat-pedantic warnings for Sema, part 1. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@142419 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticSemaKinds.td | 59 +++++++++-- lib/Sema/SemaCast.cpp | 12 ++- lib/Sema/SemaDeclCXX.cpp | 36 ++++--- lib/Sema/SemaExpr.cpp | 13 ++- lib/Sema/SemaExprCXX.cpp | 23 +++-- lib/Sema/SemaTemplate.cpp | 111 +++++++++++++-------- lib/Sema/SemaType.cpp | 14 +-- test/SemaCXX/cxx98-compat-pedantic.cpp | 13 +++ test/SemaCXX/cxx98-compat.cpp | 62 +++++++++++- 9 files changed, 255 insertions(+), 88 deletions(-) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 354f231171..3993046b2a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -192,6 +192,9 @@ def err_using_decl_can_not_refer_to_namespace : Error< "using declaration can not refer to namespace">; def err_using_decl_constructor : Error< "using declaration can not refer to a constructor">; +def warn_cxx98_compat_using_decl_constructor : Warning< + "inherited constructors are incompatible with C++98">, + InGroup, DefaultIgnore; def err_using_decl_destructor : Error< "using declaration can not refer to a destructor">; def err_using_decl_template_id : Error< @@ -623,6 +626,9 @@ def ext_nonclass_type_friend : ExtWarn< "non-class friend type %0 is a C++11 extension">, InGroup; def err_friend_is_member : Error< "friends cannot be members of the declaring class">; +def warn_cxx98_compat_friend_is_member : Warning< + "friend declaration naming a member of the declaring class is incompatible " + "with C++98">, InGroup, DefaultIgnore; def ext_unelaborated_friend_type : ExtWarn< "specify '%select{struct|union|class|enum}0' to befriend %1; accepted " "as a C++11 extension">, InGroup; @@ -1160,8 +1166,11 @@ def err_incomplete_type_no_underlying_type : Error< "an incomplete enumeration type has no underlying type yet">; // C++11 delegating constructors -def err_delegation_0x_only : Error< +def err_delegating_ctor : Error< "delegating constructors are permitted only in C++11">; +def warn_cxx98_compat_delegating_ctor : Warning< + "delegating constructors are incompatible with C++98">, + InGroup, DefaultIgnore; def err_delegating_initializer_alone : Error< "an initializer for a delegating constructor must appear alone">; def warn_delegating_ctor_cycle : Warning< @@ -2071,6 +2080,9 @@ def err_template_param_default_arg_missing : Error< def ext_template_parameter_default_in_function_template : ExtWarn< "default template arguments for a function template are a C++11 extension">, InGroup; +def warn_cxx98_compat_template_parameter_default_in_function_template : Warning< + "default template arguments for a function template are incompatible with C++98">, + InGroup, DefaultIgnore; def err_template_parameter_default_template_member : Error< "cannot add a default template argument to the definition of a member of a " "class template">; @@ -2111,6 +2123,12 @@ def ext_template_arg_local_type : ExtWarn< "template argument uses local type %0">, InGroup; def ext_template_arg_unnamed_type : ExtWarn< "template argument uses unnamed type">, InGroup; +def warn_cxx98_compat_template_arg_local_type : Warning< + "local type %0 as template argument is incompatible with C++98">, + InGroup, DefaultIgnore; +def warn_cxx98_compat_template_arg_unnamed_type : Warning< + "unnamed type as template argument is incompatible with C++98">, + InGroup, DefaultIgnore; def note_template_unnamed_type_here : Note< "unnamed type used in template argument was declared here">; def err_template_arg_overload_type : Error< @@ -2178,6 +2196,9 @@ def err_template_arg_not_pointer_to_member_form : Error< "non-type template argument is not a pointer to member constant">; def ext_template_arg_extra_parens : ExtWarn< "address non-type template argument cannot be surrounded by parentheses">; +def warn_cxx98_compat_template_arg_extra_parens : Warning< + "redundant parentheses surrounding address non-type template argument are " + "incompatible with C++98">, InGroup, DefaultIgnore; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; def err_pointer_to_member_call_drops_quals : Error< @@ -2203,11 +2224,6 @@ def err_template_spec_decl_out_of_scope_global : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 must " "originally be declared in the global scope">; -def ext_template_spec_decl_out_of_scope_global : ExtWarn< - "%select{class template|class template partial|function template|member " - "function|static data member|member class}0 specialization of %1 must " - "originally be declared in the global scope; accepted as a C++11 extension">, - InGroup; def err_template_spec_decl_out_of_scope : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 must " @@ -2217,6 +2233,11 @@ def ext_template_spec_decl_out_of_scope : ExtWarn< "function|static data member|member class}0 specialization of %1 must " "originally be declared in namespace %2; accepted as a C++11 extension">, InGroup; +def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< + "%select{class template|class template partial|function template|member " + "function|static data member|member class}0 specialization of %1 outside " + "namespace %2 is incompatible with C++98">, + InGroup, DefaultIgnore; def err_template_spec_redecl_out_of_scope : Error< "%select{class template|class template partial|function template|member " "function|static data member|member class}0 specialization of %1 not in a " @@ -2384,6 +2405,10 @@ def ext_explicit_instantiation_after_specialization : Extension< "explicit instantiation of %0 that occurs after an explicit " "specialization will be ignored (C++11 extension)">, InGroup; +def warn_cxx98_compat_explicit_instantiation_after_specialization : Warning< + "explicit instantiation of %0 that occurs after an explicit " + "specialization is incompatible with C++98">, + InGroup, DefaultIgnore; def note_previous_template_specialization : Note< "previous template specialization is here">; def err_explicit_instantiation_enum : Error< @@ -2464,6 +2489,9 @@ def warn_typename_missing : ExtWarn< InGroup>; def ext_typename_outside_of_template : ExtWarn< "'typename' occurs outside of a template">, InGroup; +def warn_cxx98_compat_typename_outside_of_template : Warning< + "use of 'typename' outside of a template is incompatible with C++98">, + InGroup, DefaultIgnore; def err_typename_refers_to_using_value_decl : Error< "typename specifier refers to a dependent using declaration for a value " "%0 in %1">; @@ -2482,6 +2510,9 @@ def err_template_kw_missing : Error< "missing 'template' keyword prior to dependent template name '%0%1'">; def ext_template_outside_of_template : ExtWarn< "'template' keyword outside of a template">, InGroup; +def warn_cxx98_compat_template_outside_of_template : Warning< + "use of 'template' keyword outside of a template is incompatible with C++98">, + InGroup, DefaultIgnore; def err_non_type_template_in_nested_name_specifier : Error< "qualified name refers into a specialization of function template '%0'">; @@ -3623,6 +3654,9 @@ def err_bad_const_cast_dest : Error< "which is not a reference, pointer-to-object, or pointer-to-data-member">; def ext_cast_fn_obj : Extension< "cast between pointer-to-function and pointer-to-object is an extension">; +def warn_cxx98_compat_cast_fn_obj : Warning< + "cast between pointer-to-function and pointer-to-object is incompatible with C++98">, + InGroup, DefaultIgnore; def err_bad_reinterpret_cast_small_int : Error< "cast from pointer to smaller type %2 loses information">; def err_bad_cxx_cast_vector_to_scalar_different_size : Error< @@ -3708,6 +3742,10 @@ def ext_array_size_conversion : Extension< "implicit conversion from array size expression of type %0 to " "%select{integral|enumeration}1 type %2 is a C++11 extension">, InGroup; +def warn_cxx98_compat_array_size_conversion : Warning< + "implicit conversion from array size expression of type %0 to " + "%select{integral|enumeration}1 type %2 is incompatible with C++98">, + InGroup, DefaultIgnore; def err_address_space_qualified_new : Error< "'new' cannot allocate objects of type %0 in address space '%1'">; def err_address_space_qualified_delete : Error< @@ -4083,6 +4121,10 @@ def warn_cannot_pass_non_pod_arg_to_vararg : Warning< "cannot pass object of %select{non-POD|non-trivial}0 type %1 through variadic" " %select{function|block|method|constructor}2; call will abort at runtime">, InGroup>, DefaultError; +def warn_cxx98_compat_pass_non_pod_arg_to_vararg : Warning< + "passing object of trivial but non-POD type %0 through variadic" + " %select{function|block|method|constructor}1 is incompatible with C++98">, + InGroup, DefaultIgnore; def err_typecheck_call_invalid_ordered_compare : Error< "ordered compare requires two args of floating point type (%0 and %1)">; @@ -4413,8 +4455,11 @@ def warn_not_compound_assign : Warning< "use of unary operator that may be intended as compound assignment (%0=)">; // C++11 explicit conversion operators -def warn_explicit_conversion_functions : Warning< +def ext_explicit_conversion_functions : ExtWarn< "explicit conversion functions are a C++11 extension">, InGroup; +def warn_cxx98_compat_explicit_conversion_functions : Warning< + "explicit conversion functions are incompatible with C++98">, + InGroup, DefaultIgnore; // C++11 defaulted functions def err_defaulted_default_ctor_params : Error< diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 925f468cfd..7a063036c2 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -1712,15 +1712,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // casting the return value of dlsym() and GetProcAddress(). // FIXME: Conditionally-supported behavior should be configurable in the // TargetInfo or similar. - if (!Self.getLangOptions().CPlusPlus0x) - Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange; + Self.Diag(OpRange.getBegin(), + Self.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) + << OpRange; return TC_Success; } if (DestType->isFunctionPointerType()) { // See above. - if (!Self.getLangOptions().CPlusPlus0x) - Self.Diag(OpRange.getBegin(), diag::ext_cast_fn_obj) << OpRange; + Self.Diag(OpRange.getBegin(), + Self.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_cast_fn_obj : diag::ext_cast_fn_obj) + << OpRange; return TC_Success; } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 38bce96360..528c4ddbc3 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2127,8 +2127,9 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, CXXRecordDecl *ClassDecl) { SourceLocation Loc = TInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!LangOpts.CPlusPlus0x) - return Diag(Loc, diag::err_delegation_0x_only) + return Diag(Loc, diag::err_delegating_ctor) << TInfo->getTypeLoc().getLocalSourceRange(); + Diag(Loc, diag::warn_cxx98_compat_delegating_ctor); // Initialize the object. InitializedEntity DelegationEntity = InitializedEntity::InitializeDelegation( @@ -5342,9 +5343,11 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, R = Context.getFunctionType(ConvType, 0, 0, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. - if (D.getDeclSpec().isExplicitSpecified() && !getLangOptions().CPlusPlus0x) + if (D.getDeclSpec().isExplicitSpecified()) Diag(D.getDeclSpec().getExplicitSpecLoc(), - diag::warn_explicit_conversion_functions) + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_explicit_conversion_functions : + diag::ext_explicit_conversion_functions) << SourceRange(D.getDeclSpec().getExplicitSpecLoc()); } @@ -5791,10 +5794,14 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, case UnqualifiedId::IK_ConstructorName: case UnqualifiedId::IK_ConstructorTemplateId: // C++0x inherited constructors. + Diag(Name.getSourceRange().getBegin(), + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_using_decl_constructor : + diag::err_using_decl_constructor) + << SS.getRange(); + if (getLangOptions().CPlusPlus0x) break; - Diag(Name.getSourceRange().getBegin(), diag::err_using_decl_constructor) - << SS.getRange(); return 0; case UnqualifiedId::IK_DestructorName: @@ -7432,7 +7439,7 @@ Sema::ComputeDefaultedCopyAssignmentExceptionSpecAndConst( &HasConstCopyAssignment); } - // In C++0x, the above citation has "or virtual added" + // In C++11, the above citation has "or virtual" added if (LangOpts.CPlusPlus0x) { for (CXXRecordDecl::base_class_iterator Base = ClassDecl->vbases_begin(), BaseEnd = ClassDecl->vbases_end(); @@ -9996,12 +10003,14 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // C++ [class.friend]p1: A friend of a class is a function or // class that is not a member of the class . . . - // C++0x changes this for both friend types and functions. + // C++11 changes this for both friend types and functions. // Most C++ 98 compilers do seem to give an error here, so // we do, too. - if (!Previous.empty() && DC->Equals(CurContext) - && !getLangOptions().CPlusPlus0x) - Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + if (!Previous.empty() && DC->Equals(CurContext)) + Diag(DS.getFriendSpecLoc(), + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_friend_is_member : + diag::err_friend_is_member); DCScope = getScopeForDeclContext(S, DC); @@ -10045,8 +10054,11 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // C++ [class.friend]p1: A friend of a class is a function or // class that is not a member of the class . . . - if (DC->Equals(CurContext) && !getLangOptions().CPlusPlus0x) - Diag(DS.getFriendSpecLoc(), diag::err_friend_is_member); + if (DC->Equals(CurContext)) + Diag(DS.getFriendSpecLoc(), + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_friend_is_member : + diag::err_friend_is_member); if (D.isFunctionDefinition()) { // C++ [class.friend]p6: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 549939e1c2..d3a8ff95d2 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -562,8 +562,12 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, if (CXXRecordDecl *Record = E->getType()->getAsCXXRecordDecl()) { if (Record->hasTrivialCopyConstructor() && Record->hasTrivialMoveConstructor() && - Record->hasTrivialDestructor()) + Record->hasTrivialDestructor()) { + DiagRuntimeBehavior(E->getLocStart(), 0, + PDiag(diag::warn_cxx98_compat_pass_non_pod_arg_to_vararg) + << E->getType() << CT); TrivialEnough = true; + } } } @@ -2643,9 +2647,10 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok) { QualType Ty; // long long is a C99 feature. - if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x && - Literal.isLongLong) - Diag(Tok.getLocation(), diag::ext_longlong); + if (!getLangOptions().C99 && Literal.isLongLong) + Diag(Tok.getLocation(), + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_longlong); // Get the value in the widest-possible width. llvm::APInt ResultVal(Context.getTargetInfo().getIntMaxTWidth(), 0); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4cd2af1c4e..64a9dd9c76 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -963,17 +963,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, QualType SizeType = ArraySize->getType(); - ExprResult ConvertedSize - = ConvertToIntegralOrEnumerationType(StartLoc, ArraySize, - PDiag(diag::err_array_size_not_integral), - PDiag(diag::err_array_size_incomplete_type) - << ArraySize->getSourceRange(), - PDiag(diag::err_array_size_explicit_conversion), - PDiag(diag::note_array_size_conversion), - PDiag(diag::err_array_size_ambiguous_conversion), - PDiag(diag::note_array_size_conversion), - PDiag(getLangOptions().CPlusPlus0x? 0 - : diag::ext_array_size_conversion)); + ExprResult ConvertedSize = ConvertToIntegralOrEnumerationType( + StartLoc, ArraySize, + PDiag(diag::err_array_size_not_integral), + PDiag(diag::err_array_size_incomplete_type) + << ArraySize->getSourceRange(), + PDiag(diag::err_array_size_explicit_conversion), + PDiag(diag::note_array_size_conversion), + PDiag(diag::err_array_size_ambiguous_conversion), + PDiag(diag::note_array_size_conversion), + PDiag(getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_array_size_conversion : + diag::ext_array_size_conversion)); if (ConvertedSize.isInvalid()) return ExprError(); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 6e8544ef2f..0c4e9e1eb3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1103,10 +1103,10 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, // template-argument, that declaration shall be a definition and shall be // the only declaration of the function template in the translation unit. // (C++98/03 doesn't have this wording; see DR226). - if (!S.getLangOptions().CPlusPlus0x) - S.Diag(ParamLoc, - diag::ext_template_parameter_default_in_function_template) - << DefArgRange; + S.Diag(ParamLoc, S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_parameter_default_in_function_template + : diag::ext_template_parameter_default_in_function_template) + << DefArgRange; return false; case Sema::TPC_ClassTemplateMember: @@ -2268,9 +2268,11 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, ParsedType ObjectType, bool EnteringContext, TemplateTy &Result) { - if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent() && - !getLangOptions().CPlusPlus0x) - Diag(TemplateKWLoc, diag::ext_template_outside_of_template) + if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) + Diag(TemplateKWLoc, + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_outside_of_template : + diag::ext_template_outside_of_template) << FixItHint::CreateRemoval(TemplateKWLoc); DeclContext *LookupCtx = 0; @@ -3261,13 +3263,19 @@ bool UnnamedLocalNoLinkageFinder::VisitAtomicType(const AtomicType* T) { bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { - S.Diag(SR.getBegin(), diag::ext_template_arg_local_type) + S.Diag(SR.getBegin(), + S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_arg_local_type : + diag::ext_template_arg_local_type) << S.Context.getTypeDeclType(Tag) << SR; return true; } if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) { - S.Diag(SR.getBegin(), diag::ext_template_arg_unnamed_type) << SR; + S.Diag(SR.getBegin(), + S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_arg_unnamed_type : + diag::ext_template_arg_unnamed_type) << SR; S.Diag(Tag->getLocation(), diag::note_template_unnamed_type_here); return true; } @@ -3317,9 +3325,14 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param, // compounded from any of these types shall not be used as a // template-argument for a template type-parameter. // - // C++0x allows these, and even in C++03 we allow them as an extension with + // C++11 allows these, and even in C++03 we allow them as an extension with // a warning. - if (!LangOpts.CPlusPlus0x && Arg->hasUnnamedOrLocalType()) { + if (LangOpts.CPlusPlus0x ? + Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_unnamed_type, + SR.getBegin()) != DiagnosticsEngine::Ignored || + Diags.getDiagnosticLevel(diag::warn_cxx98_compat_template_arg_local_type, + SR.getBegin()) != DiagnosticsEngine::Ignored : + Arg->hasUnnamedOrLocalType()) { UnnamedLocalNoLinkageFinder Finder(*this, SR); (void)Finder.Visit(Context.getCanonicalType(Arg)); } @@ -3358,9 +3371,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773 bool ExtraParens = false; while (ParenExpr *Parens = dyn_cast(Arg)) { - if (!Invalid && !ExtraParens && !S.getLangOptions().CPlusPlus0x) { + if (!Invalid && !ExtraParens) { S.Diag(Arg->getSourceRange().getBegin(), - diag::ext_template_arg_extra_parens) + S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_arg_extra_parens : + diag::ext_template_arg_extra_parens) << Arg->getSourceRange(); ExtraParens = true; } @@ -3623,9 +3638,11 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, // See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773 bool ExtraParens = false; while (ParenExpr *Parens = dyn_cast(Arg)) { - if (!Invalid && !ExtraParens && !getLangOptions().CPlusPlus0x) { + if (!Invalid && !ExtraParens) { Diag(Arg->getSourceRange().getBegin(), - diag::ext_template_arg_extra_parens) + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_template_arg_extra_parens : + diag::ext_template_arg_extra_parens) << Arg->getSourceRange(); ExtraParens = true; } @@ -4571,24 +4588,28 @@ static bool CheckTemplateSpecializationScope(Sema &S, // C++0x [temp.expl.spec]p2: // An explicit specialization shall be declared in a namespace enclosing // the specialized template. - if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) && - !(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) { - bool IsCPlusPlus0xExtension - = !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext); - if (isa(SpecializedContext)) - S.Diag(Loc, IsCPlusPlus0xExtension - ? diag::ext_template_spec_decl_out_of_scope_global - : diag::err_template_spec_decl_out_of_scope_global) + if (!DC->InEnclosingNamespaceSetOf(SpecializedContext)) { + bool IsCPlusPlus0xExtension = DC->Encloses(SpecializedContext); + if (isa(SpecializedContext)) { + assert(!IsCPlusPlus0xExtension && + "DC encloses TU but isn't in enclosing namespace set"); + S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global) << EntityKind << Specialized; - else if (isa(SpecializedContext)) - S.Diag(Loc, IsCPlusPlus0xExtension - ? diag::ext_template_spec_decl_out_of_scope - : diag::err_template_spec_decl_out_of_scope) - << EntityKind << Specialized - << cast(SpecializedContext); + } else if (isa(SpecializedContext)) { + int Diag; + if (!IsCPlusPlus0xExtension) + Diag = diag::err_template_spec_decl_out_of_scope; + else if (!S.getLangOptions().CPlusPlus0x) + Diag = diag::ext_template_spec_decl_out_of_scope; + else + Diag = diag::warn_cxx98_compat_template_spec_decl_out_of_scope; + S.Diag(Loc, Diag) + << EntityKind << Specialized << cast(SpecializedContext); + } S.Diag(Specialized->getLocation(), diag::note_specialized_entity); - ComplainedAboutScope = true; + ComplainedAboutScope = + !(IsCPlusPlus0xExtension && S.getLangOptions().CPlusPlus0x); } } @@ -5333,12 +5354,12 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // In C++98/03 mode, we only give an extension warning here, because it // is not harmful to try to explicitly instantiate something that // has been explicitly specialized. - if (!getLangOptions().CPlusPlus0x) { - Diag(NewLoc, diag::ext_explicit_instantiation_after_specialization) - << PrevDecl; - Diag(PrevDecl->getLocation(), - diag::note_previous_template_specialization); - } + Diag(NewLoc, getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_explicit_instantiation_after_specialization : + diag::ext_explicit_instantiation_after_specialization) + << PrevDecl; + Diag(PrevDecl->getLocation(), + diag::note_previous_template_specialization); HasNoEffect = true; return false; @@ -6413,9 +6434,11 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, if (SS.isInvalid()) return true; - if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && - !getLangOptions().CPlusPlus0x) - Diag(TypenameLoc, diag::ext_typename_outside_of_template) + if (TypenameLoc.isValid() && S && !S->getTemplateParamParent()) + Diag(TypenameLoc, + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_typename_outside_of_template : + diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); @@ -6449,10 +6472,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { - if (TypenameLoc.isValid() && S && !S->getTemplateParamParent() && - !getLangOptions().CPlusPlus0x) - Diag(TypenameLoc, diag::ext_typename_outside_of_template) - << FixItHint::CreateRemoval(TypenameLoc); + if (TypenameLoc.isValid() && S && !S->getTemplateParamParent()) + Diag(TypenameLoc, + getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_typename_outside_of_template : + diag::ext_typename_outside_of_template) + << FixItHint::CreateRemoval(TypenameLoc); // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index fe5b719591..f3a705f93e 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -689,9 +689,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.LongLongTy; // long long is a C99 feature. - if (!S.getLangOptions().C99 && - !S.getLangOptions().CPlusPlus0x) - S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99) + S.Diag(DS.getTypeSpecWidthLoc(), + S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_longlong); break; } } else { @@ -703,9 +704,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.UnsignedLongLongTy; // long long is a C99 feature. - if (!S.getLangOptions().C99 && - !S.getLangOptions().CPlusPlus0x) - S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_longlong); + if (!S.getLangOptions().C99) + S.Diag(DS.getTypeSpecWidthLoc(), + S.getLangOptions().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_longlong); break; } } diff --git a/test/SemaCXX/cxx98-compat-pedantic.cpp b/test/SemaCXX/cxx98-compat-pedantic.cpp index b1fd807e75..28fc23a0a7 100644 --- a/test/SemaCXX/cxx98-compat-pedantic.cpp +++ b/test/SemaCXX/cxx98-compat-pedantic.cpp @@ -16,3 +16,16 @@ VA_MACRO(,x) // expected-warning {{empty macro argument list is incompatible wit enum Enum { Enum_value, // expected-warning {{commas at the end of enumerator lists are incompatible with C++98}} }; + +template struct InstantiationAfterSpecialization {}; +template<> struct InstantiationAfterSpecialization {}; // expected-note {{here}} +template struct InstantiationAfterSpecialization; // expected-warning {{explicit instantiation of 'InstantiationAfterSpecialization' that occurs after an explicit specialization is incompatible with C++98}} + +void *dlsym(); +void (*FnPtr)() = (void(*)())dlsym(); // expected-warning {{cast between pointer-to-function and pointer-to-object is incompatible with C++98}} +void *FnVoidPtr = (void*)&dlsym; // expected-warning {{cast between pointer-to-function and pointer-to-object is incompatible with C++98}} + +struct ConvertToInt { + operator int(); +}; +int *ArraySizeConversion = new int[ConvertToInt()]; // expected-warning {{implicit conversion from array size expression of type 'ConvertToInt' to integral type 'int' is incompatible with C++98}} diff --git a/test/SemaCXX/cxx98-compat.cpp b/test/SemaCXX/cxx98-compat.cpp index a2e98e4743..123dd4f637 100644 --- a/test/SemaCXX/cxx98-compat.cpp +++ b/test/SemaCXX/cxx98-compat.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s template // expected-warning {{variadic templates are incompatible with C++98}} class Variadic1 {}; @@ -85,7 +86,7 @@ struct OverrideControl final : OverrideControlBase { // expected-warning {{'fina 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}} +inline namespace InlineNS { // expected-warning {{inline namespaces are incompatible with C++98}} } auto auto_deduction = 0; // expected-warning {{'auto' type specifier is incompatible with C++98}} @@ -100,3 +101,62 @@ void no_except() noexcept; // expected-warning {{noexcept specifications are inc bool no_except_expr = noexcept(1 + 1); // expected-warning {{noexcept expressions are incompatible with C++98}} void *null = nullptr; // expected-warning {{'nullptr' is incompatible with C++98}} static_assert(true, "!"); // expected-warning {{static_assert declarations are incompatible with C++98}} + +struct InhCtorBase { + InhCtorBase(int); +}; +struct InhCtorDerived : InhCtorBase { + using InhCtorBase::InhCtorBase; // expected-warning {{inherited constructors are incompatible with C++98}} +}; + +struct FriendMember { + static void MemberFn(); + friend void FriendMember::MemberFn(); // expected-warning {{friend declaration naming a member of the declaring class is incompatible with C++98}} +}; + +struct DelegCtor { + DelegCtor(int) : DelegCtor() {} // expected-warning {{delegating constructors are incompatible with C++98}} + DelegCtor(); +}; + +template void DefaultFuncTemplateArg(); // expected-warning {{default template arguments for a function template are incompatible with C++98}} + +template int TemplateFn(T) { return 0; } +void LocalTemplateArg() { + struct S {}; + TemplateFn(S()); // expected-warning {{local type 'S' as template argument is incompatible with C++98}} +} +struct {} obj_of_unnamed_type; // expected-note {{here}} +int UnnamedTemplateArg = TemplateFn(obj_of_unnamed_type); // expected-warning {{unnamed type as template argument is incompatible with C++98}} + +namespace RedundantParensInAddressTemplateParam { + int n; + template struct S {}; + S<(&n)> s; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}} + S<(((&n)))> t; // expected-warning {{redundant parentheses surrounding address non-type template argument are incompatible with C++98}} +} + +namespace TemplateSpecOutOfScopeNs { + template struct S {}; // expected-note {{here}} +} +template<> struct TemplateSpecOutOfScopeNs::S {}; // expected-warning {{class template specialization of 'S' outside namespace 'TemplateSpecOutOfScopeNs' is incompatible with C++98}} + +struct Typename { + template struct Inner {}; +}; +typename ::Typename TypenameOutsideTemplate(); // expected-warning {{use of 'typename' outside of a template is incompatible with C++98}} +Typename::template Inner TemplateOutsideTemplate(); // expected-warning {{use of 'template' keyword outside of a template is incompatible with C++98}} + +struct TrivialButNonPOD { + int f(int); +private: + int k; +}; +void Ellipsis(int n, ...); +void TrivialButNonPODThroughEllipsis() { + Ellipsis(1, TrivialButNonPOD()); // expected-warning {{passing object of trivial but non-POD type 'TrivialButNonPOD' through variadic function is incompatible with C++98}} +} + +struct HasExplicitConversion { + explicit operator bool(); // expected-warning {{explicit conversion functions are incompatible with C++98}} +}; -- 2.40.0