diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3963f7581880..98b687b8e821 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1,8604 +1,8606 @@ //==--- DiagnosticSemaKinds.td - libsema diagnostics ----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Semantic Analysis //===----------------------------------------------------------------------===// let Component = "Sema" in { let CategoryName = "Semantic Issue" in { def note_previous_decl : Note<"%0 declared here">; def note_entity_declared_at : Note<"%0 declared here">; def note_callee_decl : Note<"%0 declared here">; def note_defined_here : Note<"%0 defined here">; // For loop analysis def warn_variables_not_in_loop_body : Warning< "variable%select{s| %1|s %1 and %2|s %1, %2, and %3|s %1, %2, %3, and %4}0 " "used in loop condition not modified in loop body">, InGroup, DefaultIgnore; def warn_redundant_loop_iteration : Warning< "variable %0 is %select{decremented|incremented}1 both in the loop header " "and in the loop body">, InGroup, DefaultIgnore; def note_loop_iteration_here : Note<"%select{decremented|incremented}0 here">; def warn_duplicate_enum_values : Warning< "element %0 has been implicitly assigned %1 which another element has " "been assigned">, InGroup>, DefaultIgnore; def note_duplicate_element : Note<"element %0 also has value %1">; // Absolute value functions def warn_unsigned_abs : Warning< "taking the absolute value of unsigned type %0 has no effect">, InGroup; def note_remove_abs : Note< "remove the call to '%0' since unsigned values cannot be negative">; def warn_abs_too_small : Warning< "absolute value function %0 given an argument of type %1 but has parameter " "of type %2 which may cause truncation of value">, InGroup; def warn_wrong_absolute_value_type : Warning< "using %select{integer|floating point|complex}1 absolute value function %0 " "when argument is of %select{integer|floating point|complex}2 type">, InGroup; def note_replace_abs_function : Note<"use function '%0' instead">; def warn_pointer_abs : Warning< "taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">, InGroup; def warn_infinite_recursive_function : Warning< "all paths through this function will call itself">, InGroup, DefaultIgnore; def warn_comma_operator : Warning<"possible misuse of comma operator here">, InGroup>, DefaultIgnore; def note_cast_to_void : Note<"cast expression to void to silence warning">; // Constant expressions def err_expr_not_ice : Error< "expression is not an %select{integer|integral}0 constant expression">; def ext_expr_not_ice : Extension< "expression is not an %select{integer|integral}0 constant expression; " "folding it to a constant is a GNU extension">, InGroup; def err_typecheck_converted_constant_expression : Error< "value of type %0 is not implicitly convertible to %1">; def err_typecheck_converted_constant_expression_disallowed : Error< "conversion from %0 to %1 is not allowed in a converted constant expression">; def err_typecheck_converted_constant_expression_indirect : Error< "conversion from %0 to %1 in converted constant expression would " "bind reference to a temporary">; def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|" "array size|constexpr if condition}0 " "is not a constant expression">; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|" "array size|constexpr if condition}0 " "%select{cannot be narrowed from type %2 to %3|" "evaluates to %2, which cannot be narrowed to type %3}1">, InGroup, DefaultError, SFINAEFailure; def err_ice_not_integral : Error< "integral constant expression must have integral or unscoped enumeration " "type, not %0">; def err_ice_incomplete_type : Error< "integral constant expression has incomplete class type %0">; def err_ice_explicit_conversion : Error< "integral constant expression requires explicit conversion from %0 to %1">; def note_ice_conversion_here : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_ice_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; def err_ice_too_large : Error< "integer constant expression evaluates to value %0 that cannot be " "represented in a %1-bit %select{signed|unsigned}2 integer type">; def err_expr_not_string_literal : Error<"expression is not a string literal">; // Semantic analysis of constant literals. def ext_predef_outside_function : Warning< "predefined identifier is only valid inside function">, InGroup>; def warn_float_overflow : Warning< "magnitude of floating-point constant too large for type %0; maximum is %1">, InGroup; def warn_float_underflow : Warning< "magnitude of floating-point constant too small for type %0; minimum is %1">, InGroup; def warn_double_const_requires_fp64 : Warning< "double precision constant requires cl_khr_fp64, casting to single precision">; def err_half_const_requires_fp16 : Error< "half precision constant requires cl_khr_fp16">; // C99 variable-length arrays def ext_vla : Extension<"variable length arrays are a C99 feature">, InGroup; def warn_vla_used : Warning<"variable length array used">, InGroup, DefaultIgnore; def err_vla_in_sfinae : Error< "variable length array cannot be formed during template argument deduction">; def err_array_star_in_function_definition : Error< "variable length array must be bound in function definition">; def err_vla_decl_in_file_scope : Error< "variable length array declaration not allowed at file scope">; def err_vla_decl_has_static_storage : Error< "variable length array declaration cannot have 'static' storage duration">; def err_vla_decl_has_extern_linkage : Error< "variable length array declaration cannot have 'extern' linkage">; def ext_vla_folded_to_constant : Extension< "variable length array folded to constant array as an extension">, InGroup; // C99 variably modified types def err_variably_modified_template_arg : Error< "variably modified type %0 cannot be used as a template argument">; def err_variably_modified_nontype_template_param : Error< "non-type template parameter of variably modified type %0">; def err_variably_modified_new_type : Error< "'new' cannot allocate object of variably modified type %0">; // C99 Designated Initializers def ext_designated_init : Extension< "designated initializers are a C99 feature">, InGroup; def err_array_designator_negative : Error< "array designator value '%0' is negative">; def err_array_designator_empty_range : Error< "array designator range [%0, %1] is empty">; def err_array_designator_non_array : Error< "array designator cannot initialize non-array type %0">; def err_array_designator_too_large : Error< "array designator index (%0) exceeds array bounds (%1)">; def err_field_designator_non_aggr : Error< "field designator cannot initialize a " "%select{non-struct, non-union|non-class}0 type %1">; def err_field_designator_unknown : Error< "field designator %0 does not refer to any field in type %1">; def err_field_designator_nonfield : Error< "field designator %0 does not refer to a non-static data member">; def note_field_designator_found : Note<"field designator refers here">; def err_designator_for_scalar_init : Error< "designator in initializer for scalar type %0">; def warn_subobject_initializer_overrides : Warning< "subobject initialization overrides initialization of other fields " "within its enclosing subobject">, InGroup; def warn_initializer_overrides : Warning< "initializer overrides prior initialization of this subobject">, InGroup; def note_previous_initializer : Note< "previous initialization %select{|with side effects }0is here" "%select{| (side effects may not occur at run time)}0">; def err_designator_into_flexible_array_member : Error< "designator into flexible array member subobject">; def note_flexible_array_member : Note< "initialized flexible array member %0 is here">; def ext_flexible_array_init : Extension< "flexible array initialization is a GNU extension">, InGroup; // Declarations. def ext_duplicate_declspec : ExtWarn<"duplicate '%0' declaration specifier">, InGroup; def warn_duplicate_declspec : Warning<"duplicate '%0' declaration specifier">, InGroup; def ext_plain_complex : ExtWarn< "plain '_Complex' requires a type specifier; assuming '_Complex double'">; def ext_integer_complex : Extension< "complex integer types are a GNU extension">, InGroup; def err_invalid_sign_spec : Error<"'%0' cannot be signed or unsigned">; def err_invalid_width_spec : Error< "'%select{|short|long|long long}0 %1' is invalid">; def err_invalid_complex_spec : Error<"'_Complex %0' is invalid">; def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; def ext_auto_type_specifier : ExtWarn< "'auto' type specifier is a C++11 extension">, InGroup; def warn_auto_storage_class : Warning< "'auto' storage class specifier is redundant and incompatible with C++11">, InGroup, DefaultIgnore; def warn_deprecated_register : Warning< "'register' storage class specifier is deprecated " "and incompatible with C++1z">, InGroup; def ext_register_storage_class : ExtWarn< "ISO C++1z does not allow 'register' storage class specifier">, DefaultError, InGroup; def err_invalid_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier">; def err_invalid_vector_decl_spec_combination : Error< "cannot combine with previous '%0' declaration specifier. " "'__vector' must be first">; def err_invalid_pixel_decl_spec_combination : Error< "'__pixel' must be preceded by '__vector'. " "'%0' declaration specifier not allowed here">; def err_invalid_vector_bool_decl_spec : Error< "cannot use '%0' with '__vector bool'">; def err_invalid_vector_long_decl_spec : Error< "cannot use 'long' with '__vector'">; def err_invalid_vector_float_decl_spec : Error< "cannot use 'float' with '__vector'">; def err_invalid_vector_double_decl_spec : Error < "use of 'double' with '__vector' requires VSX support to be enabled " "(available on POWER7 or later)">; def err_invalid_vector_long_long_decl_spec : Error < "use of 'long long' with '__vector bool' requires VSX support (available on " "POWER7 or later) or extended Altivec support (available on POWER8 or later) " "to be enabled">; def err_invalid_vector_long_double_decl_spec : Error< "cannot use 'long double' with '__vector'">; def warn_vector_long_decl_spec_combination : Warning< "Use of 'long' with '__vector' is deprecated">, InGroup; def err_use_of_tag_name_without_tag : Error< "must use '%1' tag to refer to type %0%select{| in this scope}2">; def err_redeclaration_different_type : Error< "redeclaration of %0 with a different type%diff{: $ vs $|}1,2">; def err_bad_variable_name : Error< "%0 cannot be the name of a variable or data member">; def err_bad_parameter_name : Error< "%0 cannot be the name of a parameter">; def err_parameter_name_omitted : Error<"parameter name omitted">; def err_anyx86_interrupt_attribute : Error< "%select{x86|x86-64}0 'interrupt' attribute only applies to functions that " "have %select{a 'void' return type|" "only a pointer parameter optionally followed by an integer parameter|" "a pointer as the first parameter|a %2 type as the second parameter}1">; def err_anyx86_interrupt_called : Error< "interrupt service routine cannot be called directly">; def warn_mips_interrupt_attribute : Warning< "MIPS 'interrupt' attribute only applies to functions that have " "%select{no parameters|a 'void' return type}0">, InGroup; def warn_unused_parameter : Warning<"unused parameter %0">, InGroup, DefaultIgnore; def warn_unused_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_unused_local_typedef : Warning< "unused %select{typedef|type alias}0 %1">, InGroup, DefaultIgnore; def warn_unused_property_backing_ivar : Warning<"ivar %0 which backs the property is not " "referenced in this property's accessor">, InGroup, DefaultIgnore; def warn_unused_const_variable : Warning<"unused variable %0">, InGroup, DefaultIgnore; def warn_unused_exception_param : Warning<"unused exception parameter %0">, InGroup, DefaultIgnore; def warn_decl_in_param_list : Warning< "declaration of %0 will not be visible outside of this function">, InGroup; def warn_redefinition_in_param_list : Warning< "redefinition of %0 will not be visible outside of this function">, InGroup; def warn_empty_parens_are_function_decl : Warning< "empty parentheses interpreted as a function declaration">, InGroup; def warn_parens_disambiguated_as_function_declaration : Warning< "parentheses were disambiguated as a function declaration">, InGroup; def note_additional_parens_for_variable_declaration : Note< "add a pair of parentheses to declare a variable">; def note_empty_parens_function_call : Note< "change this ',' to a ';' to call %0">; def note_empty_parens_default_ctor : Note< "remove parentheses to declare a variable">; def note_empty_parens_zero_initialize : Note< "replace parentheses with an initializer to declare a variable">; def warn_unused_function : Warning<"unused function %0">, InGroup, DefaultIgnore; def warn_unused_member_function : Warning<"unused member function %0">, InGroup, DefaultIgnore; def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">, InGroup, DefaultIgnore; def warn_unneeded_internal_decl : Warning< "%select{function|variable}0 %1 is not needed and will not be emitted">, InGroup, DefaultIgnore; def warn_unneeded_static_internal_decl : Warning< "'static' function %0 declared in header file " "should be declared 'static inline'">, InGroup, DefaultIgnore; def warn_unneeded_member_function : Warning< "member function %0 is not needed and will not be emitted">, InGroup, DefaultIgnore; def warn_unused_private_field: Warning<"private field %0 is not used">, InGroup, DefaultIgnore; def warn_parameter_size: Warning< "%0 is a large (%1 bytes) pass-by-value argument; " "pass it by reference instead ?">, InGroup; def warn_return_value_size: Warning< "return value of %0 is a large (%1 bytes) pass-by-value object; " "pass it by reference instead ?">, InGroup; def warn_return_value_udt: Warning< "%0 has C-linkage specified, but returns user-defined type %1 which is " "incompatible with C">, InGroup; def warn_return_value_udt_incomplete: Warning< "%0 has C-linkage specified, but returns incomplete type %1 which could be " "incompatible with C">, InGroup; def warn_implicit_function_decl : Warning< "implicit declaration of function %0">, InGroup, DefaultIgnore; def ext_implicit_function_decl : ExtWarn< "implicit declaration of function %0 is invalid in C99">, InGroup; def note_function_suggestion : Note<"did you mean %0?">; def err_ellipsis_first_param : Error< "ISO C requires a named parameter before '...'">; def err_declarator_need_ident : Error<"declarator requires an identifier">; def err_language_linkage_spec_unknown : Error<"unknown linkage language">; def err_language_linkage_spec_not_ascii : Error< "string literal in language linkage specifier cannot have an " "encoding-prefix">; def warn_use_out_of_scope_declaration : Warning< "use of out-of-scope declaration of %0">; def err_inline_non_function : Error< "'inline' can only appear on functions%select{| and non-local variables}0">; def err_noreturn_non_function : Error< "'_Noreturn' can only appear on functions">; def warn_qual_return_type : Warning< "'%0' type qualifier%s1 on return type %plural{1:has|:have}1 no effect">, InGroup, DefaultIgnore; def warn_deprecated_redundant_constexpr_static_def : Warning< "out-of-line definition of constexpr static data member is redundant " "in C++17 and is deprecated">, InGroup, DefaultIgnore; def warn_decl_shadow : Warning<"declaration shadows a %select{" "local variable|" "variable in %2|" "static data member of %2|" "field of %2}1">, InGroup, DefaultIgnore; def warn_ctor_parm_shadows_field: Warning<"constructor parameter %0 shadows the field %1 of %2">, InGroup, DefaultIgnore; def warn_modifying_shadowing_decl : Warning<"modifying constructor parameter %0 that shadows a " "field of %1">, InGroup, DefaultIgnore; // C++ using declarations def err_using_requires_qualname : Error< "using declaration requires a qualified name">; def err_using_typename_non_type : Error< "'typename' keyword used on a non-type">; def err_using_dependent_value_is_type : Error< "dependent using declaration resolved to type without 'typename'">; def err_using_decl_nested_name_specifier_is_not_class : Error< "using declaration in class refers into '%0', which is not a class">; def err_using_decl_nested_name_specifier_is_current_class : Error< "using declaration refers to its own class">; def err_using_decl_nested_name_specifier_is_not_base_class : Error< "using declaration refers into '%0', which is not a base class of %1">; def err_using_decl_constructor_not_in_direct_base : Error< "%0 is not a direct base of %1, cannot inherit constructors">; def err_using_decl_can_not_refer_to_class_member : Error< "using declaration cannot refer to class member">; def err_ambiguous_inherited_constructor : Error< "constructor of %0 inherited from multiple base class subobjects">; def note_ambiguous_inherited_constructor_using : Note< "inherited from base class %0 here">; def note_using_decl_class_member_workaround : Note< "use %select{an alias declaration|a typedef declaration|a reference|" "a const variable|a constexpr variable}0 instead">; def err_using_decl_can_not_refer_to_namespace : Error< "using declaration cannot refer to a namespace">; def err_using_decl_can_not_refer_to_scoped_enum : Error< "using declaration cannot refer to a scoped enumerator">; def err_using_decl_constructor : Error< "using declaration cannot refer to a constructor">; def warn_cxx98_compat_using_decl_constructor : Warning< "inheriting constructors are incompatible with C++98">, InGroup, DefaultIgnore; def err_using_decl_destructor : Error< "using declaration cannot refer to a destructor">; def err_using_decl_template_id : Error< "using declaration cannot refer to a template specialization">; def note_using_decl_target : Note<"target of using declaration">; def note_using_decl_conflict : Note<"conflicting declaration">; def err_using_decl_redeclaration : Error<"redeclaration of using declaration">; def err_using_decl_conflict : Error< "target of using declaration conflicts with declaration already in scope">; def err_using_decl_conflict_reverse : Error< "declaration conflicts with target of using declaration already in scope">; def note_using_decl : Note<"%select{|previous }0using declaration">; def warn_access_decl_deprecated : Warning< "access declarations are deprecated; use using declarations instead">, InGroup; def err_access_decl : Error< "ISO C++11 does not allow access declarations; " "use using declarations instead">; def warn_exception_spec_deprecated : Warning< "dynamic exception specifications are deprecated">, InGroup, DefaultIgnore; def note_exception_spec_deprecated : Note<"use '%0' instead">; def warn_deprecated_copy_operation : Warning< "definition of implicit copy %select{constructor|assignment operator}1 " "for %0 is deprecated because it has a user-declared " "%select{copy %select{assignment operator|constructor}1|destructor}2">, InGroup, DefaultIgnore; def warn_global_constructor : Warning< "declaration requires a global constructor">, InGroup, DefaultIgnore; def warn_global_destructor : Warning< "declaration requires a global destructor">, InGroup, DefaultIgnore; def warn_exit_time_destructor : Warning< "declaration requires an exit-time destructor">, InGroup, DefaultIgnore; def err_invalid_thread : Error< "'%0' is only allowed on variable declarations">; def err_thread_non_global : Error< "'%0' variables must have global storage">; def err_thread_unsupported : Error< "thread-local storage is not supported for the current target">; def warn_maybe_falloff_nonvoid_function : Warning< "control may reach end of non-void function">, InGroup; def warn_falloff_nonvoid_function : Warning< "control reaches end of non-void function">, InGroup; def err_maybe_falloff_nonvoid_block : Error< "control may reach end of non-void block">; def err_falloff_nonvoid_block : Error< "control reaches end of non-void block">; def warn_suggest_noreturn_function : Warning< "%select{function|method}0 %1 could be declared with attribute 'noreturn'">, InGroup, DefaultIgnore; def warn_suggest_noreturn_block : Warning< "block could be declared with attribute 'noreturn'">, InGroup, DefaultIgnore; // Unreachable code. def warn_unreachable : Warning< "code will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_break : Warning< "'break' will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_return : Warning< "'return' will never be executed">, InGroup, DefaultIgnore; def warn_unreachable_loop_increment : Warning< "loop will run at most once (loop increment never executed)">, InGroup, DefaultIgnore; def note_unreachable_silence : Note< "silence by adding parentheses to mark code as explicitly dead">; /// Built-in functions. def ext_implicit_lib_function_decl : ExtWarn< "implicitly declaring library function '%0' with type %1">, InGroup; def note_include_header_or_declare : Note< "include the header <%0> or explicitly provide a declaration for '%1'">; def note_previous_builtin_declaration : Note<"%0 is a builtin with type %1">; def warn_implicit_decl_requires_sysheader : Warning< "declaration of built-in function '%1' requires inclusion of the header <%0>">, InGroup; def warn_redecl_library_builtin : Warning< "incompatible redeclaration of library function %0">, InGroup>; def err_builtin_definition : Error<"definition of builtin function %0">; def err_arm_invalid_specialreg : Error<"invalid special register for builtin">; def err_invalid_cpu_supports : Error<"invalid cpu feature string for builtin">; def err_builtin_needs_feature : Error<"%0 needs target feature %1">; def err_function_needs_feature : Error<"always_inline function %1 requires target feature '%2', but would " "be inlined into function %0 that is compiled without support for " "'%2'">; def warn_builtin_unknown : Warning<"use of unknown builtin %0">, InGroup, DefaultError; def warn_dyn_class_memaccess : Warning< "%select{destination for|source of|first operand of|second operand of}0 this " "%1 call is a pointer to %select{|class containing a }2dynamic class %3; " "vtable pointer will be %select{overwritten|copied|moved|compared}4">, InGroup>; def note_bad_memaccess_silence : Note< "explicitly cast the pointer to silence this warning">; def warn_sizeof_pointer_expr_memaccess : Warning< "'%0' call operates on objects of type %1 while the size is based on a " "different type %2">, InGroup; def warn_sizeof_pointer_expr_memaccess_note : Note< "did you mean to %select{dereference the argument to 'sizeof' (and multiply " "it by the number of elements)|remove the addressof in the argument to " "'sizeof' (and multiply it by the number of elements)|provide an explicit " "length}0?">; def warn_sizeof_pointer_type_memaccess : Warning< "argument to 'sizeof' in %0 call is the same pointer type %1 as the " "%select{destination|source}2; expected %3 or an explicit length">, InGroup; def warn_strlcpycat_wrong_size : Warning< "size argument in %0 call appears to be size of the source; " "expected the size of the destination">, InGroup>; def note_strlcpycat_wrong_size : Note< "change size argument to be the size of the destination">; def warn_memsize_comparison : Warning< "size argument in %0 call is a comparison">, InGroup>; def note_memsize_comparison_paren : Note< "did you mean to compare the result of %0 instead?">; def note_memsize_comparison_cast_silence : Note< "explicitly cast the argument to size_t to silence this warning">; def warn_strncat_large_size : Warning< "the value of the size argument in 'strncat' is too large, might lead to a " "buffer overflow">, InGroup; def warn_strncat_src_size : Warning<"size argument in 'strncat' call appears " "to be size of the source">, InGroup; def warn_strncat_wrong_size : Warning< "the value of the size argument to 'strncat' is wrong">, InGroup; def note_strncat_wrong_size : Note< "change the argument to be the free space in the destination buffer minus " "the terminating null byte">; def warn_assume_side_effects : Warning< "the argument to %0 has side effects that will be discarded">, InGroup>; def warn_memcpy_chk_overflow : Warning< "%0 will always overflow destination buffer">, InGroup>; /// main() // static main() is not an error in C, just in C++. def warn_static_main : Warning<"'main' should not be declared static">, InGroup
; def err_static_main : Error<"'main' is not allowed to be declared static">; def err_inline_main : Error<"'main' is not allowed to be declared inline">; def ext_variadic_main : ExtWarn< "'main' is not allowed to be declared variadic">, InGroup
; def ext_noreturn_main : ExtWarn< "'main' is not allowed to be declared _Noreturn">, InGroup
; def note_main_remove_noreturn : Note<"remove '_Noreturn'">; def err_constexpr_main : Error< "'main' is not allowed to be declared constexpr">; def err_deleted_main : Error<"'main' is not allowed to be deleted">; def err_mainlike_template_decl : Error<"%0 cannot be a template">; def err_main_returns_nonint : Error<"'main' must return 'int'">; def ext_main_returns_nonint : ExtWarn<"return type of 'main' is not 'int'">, InGroup; def note_main_change_return_type : Note<"change return type to 'int'">; def err_main_surplus_args : Error<"too many parameters (%0) for 'main': " "must be 0, 2, or 3">; def warn_main_one_arg : Warning<"only one parameter on 'main' declaration">, InGroup
; def err_main_arg_wrong : Error<"%select{first|second|third|fourth}0 " "parameter of 'main' (%select{argument count|argument array|environment|" "platform-specific data}0) must be of type %1">; def err_main_global_variable : Error<"main cannot be declared as global variable">; def warn_main_redefined : Warning<"variable named 'main' with external linkage " "has undefined behavior">, InGroup
; def ext_main_used : Extension< "ISO C++ does not allow 'main' to be used by a program">, InGroup
; /// parser diagnostics def ext_no_declarators : ExtWarn<"declaration does not declare anything">, InGroup; def ext_typedef_without_a_name : ExtWarn<"typedef requires a name">, InGroup; def err_typedef_not_identifier : Error<"typedef name must be an identifier">; def err_typedef_changes_linkage : Error<"unsupported: typedef changes linkage" " of anonymous type, but linkage was already computed">; def note_typedef_changes_linkage : Note<"use a tag name here to establish " "linkage prior to definition">; def err_statically_allocated_object : Error< "interface type cannot be statically allocated">; def err_object_cannot_be_passed_returned_by_value : Error< "interface type %1 cannot be %select{returned|passed}0 by value" "; did you forget * in %1?">; def err_parameters_retval_cannot_have_fp16_type : Error< "%select{parameters|function return value}0 cannot have __fp16 type; did you forget * ?">; def err_opencl_half_load_store : Error< "%select{loading directly from|assigning directly to}0 pointer to type %1 is not allowed">; def err_opencl_cast_to_half : Error<"casting to type %0 is not allowed">; def err_opencl_half_declaration : Error< "declaring variable of type %0 is not allowed">; def err_opencl_half_param : Error< "declaring function parameter of type %0 is not allowed; did you forget * ?">; def err_opencl_invalid_return : Error< "declaring function return value of type %0 is not allowed %select{; did you forget * ?|}1">; def warn_enum_value_overflow : Warning<"overflow in enumeration value">; def warn_pragma_options_align_reset_failed : Warning< "#pragma options align=reset failed: %0">, InGroup; def err_pragma_options_align_mac68k_target_unsupported : Error< "mac68k alignment pragma is not supported on this target">; def warn_pragma_pack_invalid_alignment : Warning< "expected #pragma pack parameter to be '1', '2', '4', '8', or '16'">, InGroup; // Follow the Microsoft implementation. def warn_pragma_pack_show : Warning<"value of #pragma pack(show) == %0">; def warn_pragma_pack_pop_identifer_and_alignment : Warning< "specifying both a name and alignment to 'pop' is undefined">; def warn_pragma_pop_failed : Warning<"#pragma %0(pop, ...) failed: %1">, InGroup; def warn_cxx_ms_struct : Warning<"ms_struct may not produce Microsoft-compatible layouts for classes " "with base classes or virtual functions">, DefaultError, InGroup; def err_section_conflict : Error<"%0 causes a section type conflict with %1">; def err_no_base_classes : Error<"invalid use of '__super', %0 has no base classes">; def err_invalid_super_scope : Error<"invalid use of '__super', " "this keyword can only be used inside class or member function scope">; def err_super_in_lambda_unsupported : Error< "use of '__super' inside a lambda is unsupported">; def warn_pragma_unused_undeclared_var : Warning< "undeclared variable %0 used as an argument for '#pragma unused'">, InGroup; def warn_pragma_unused_expected_var_arg : Warning< "only variables can be arguments to '#pragma unused'">, InGroup; def err_pragma_push_visibility_mismatch : Error< "#pragma visibility push with no matching #pragma visibility pop">; def note_surrounding_namespace_ends_here : Note< "surrounding namespace with visibility attribute ends here">; def err_pragma_pop_visibility_mismatch : Error< "#pragma visibility pop with no matching #pragma visibility push">; def note_surrounding_namespace_starts_here : Note< "surrounding namespace with visibility attribute starts here">; def err_pragma_loop_invalid_argument_type : Error< "invalid argument of type %0; expected an integer type">; def err_pragma_loop_invalid_argument_value : Error< "%select{invalid value '%0'; must be positive|value '%0' is too large}1">; def err_pragma_loop_compatibility : Error< "%select{incompatible|duplicate}0 directives '%1' and '%2'">; def err_pragma_loop_precedes_nonloop : Error< "expected a for, while, or do-while loop to follow '%0'">; /// Objective-C parser diagnostics def err_duplicate_class_def : Error< "duplicate interface definition for class %0">; def err_undef_superclass : Error< "cannot find interface declaration for %0, superclass of %1">; def err_forward_superclass : Error< "attempting to use the forward class %0 as superclass of %1">; def err_no_nsconstant_string_class : Error< "cannot find interface declaration for %0">; def err_recursive_superclass : Error< "trying to recursively use %0 as superclass of %1">; def err_conflicting_aliasing_type : Error<"conflicting types for alias %0">; def warn_undef_interface : Warning<"cannot find interface declaration for %0">; def warn_duplicate_protocol_def : Warning<"duplicate protocol definition of %0 is ignored">; def err_protocol_has_circular_dependency : Error< "protocol has circular dependency">; def err_undeclared_protocol : Error<"cannot find protocol declaration for %0">; def warn_undef_protocolref : Warning<"cannot find protocol definition for %0">; def warn_atprotocol_protocol : Warning< "@protocol is using a forward protocol declaration of %0">, InGroup; def warn_readonly_property : Warning< "attribute 'readonly' of property %0 restricts attribute " "'readwrite' of property inherited from %1">, InGroup; def warn_property_attribute : Warning< "'%1' attribute on property %0 does not match the property inherited from %2">, InGroup; def warn_property_types_are_incompatible : Warning< "property type %0 is incompatible with type %1 inherited from %2">, InGroup>; def warn_protocol_property_mismatch : Warning< "property of type %0 was selected for synthesis">, InGroup>; def err_undef_interface : Error<"cannot find interface declaration for %0">; def err_category_forward_interface : Error< "cannot define %select{category|class extension}0 for undefined class %1">; def err_class_extension_after_impl : Error< "cannot declare class extension for %0 after class implementation">; def note_implementation_declared : Note< "class implementation is declared here">; def note_while_in_implementation : Note< "detected while default synthesizing properties in class implementation">; def note_class_declared : Note< "class is declared here">; def note_receiver_class_declared : Note< "receiver is instance of class declared here">; def note_receiver_expr_here : Note< "receiver expression is here">; def note_receiver_is_id : Note< "receiver is treated with 'id' type for purpose of method lookup">; def note_suppressed_class_declare : Note< "class with specified objc_requires_property_definitions attribute is declared here">; def err_objc_root_class_subclass : Error< "objc_root_class attribute may only be specified on a root class declaration">; def warn_objc_root_class_missing : Warning< "class %0 defined without specifying a base class">, InGroup; def err_objc_runtime_visible_category : Error< "cannot implement a category for class %0 that is only visible via the " "Objective-C runtime">; def err_objc_runtime_visible_subclass : Error< "cannot implement subclass %0 of a superclass %1 that is only visible via the " "Objective-C runtime">; def note_objc_needs_superclass : Note< "add a super class to fix this problem">; def warn_dup_category_def : Warning< "duplicate definition of category %1 on interface %0">; def err_conflicting_super_class : Error<"conflicting super class name %0">; def err_dup_implementation_class : Error<"reimplementation of class %0">; def err_dup_implementation_category : Error< "reimplementation of category %1 for class %0">; def err_conflicting_ivar_type : Error< "instance variable %0 has conflicting type%diff{: $ vs $|}1,2">; def err_duplicate_ivar_declaration : Error< "instance variable is already declared">; def warn_on_superclass_use : Warning< "class implementation may not have super class">; def err_conflicting_ivar_bitwidth : Error< "instance variable %0 has conflicting bit-field width">; def err_conflicting_ivar_name : Error< "conflicting instance variable names: %0 vs %1">; def err_inconsistent_ivar_count : Error< "inconsistent number of instance variables specified">; def warn_undef_method_impl : Warning<"method definition for %0 not found">, InGroup>; def warn_conflicting_overriding_ret_types : Warning< "conflicting return type in " "declaration of %0%diff{: $ vs $|}1,2">, InGroup, DefaultIgnore; def warn_conflicting_ret_types : Warning< "conflicting return type in " "implementation of %0%diff{: $ vs $|}1,2">, InGroup; def warn_conflicting_overriding_ret_type_modifiers : Warning< "conflicting distributed object modifiers on return type " "in declaration of %0">, InGroup, DefaultIgnore; def warn_conflicting_ret_type_modifiers : Warning< "conflicting distributed object modifiers on return type " "in implementation of %0">, InGroup; def warn_non_covariant_overriding_ret_types : Warning< "conflicting return type in " "declaration of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_non_covariant_ret_types : Warning< "conflicting return type in " "implementation of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_conflicting_overriding_param_types : Warning< "conflicting parameter types in " "declaration of %0%diff{: $ vs $|}1,2">, InGroup, DefaultIgnore; def warn_conflicting_param_types : Warning< "conflicting parameter types in " "implementation of %0%diff{: $ vs $|}1,2">, InGroup; def warn_conflicting_param_modifiers : Warning< "conflicting distributed object modifiers on parameter type " "in implementation of %0">, InGroup; def warn_conflicting_overriding_param_modifiers : Warning< "conflicting distributed object modifiers on parameter type " "in declaration of %0">, InGroup, DefaultIgnore; def warn_non_contravariant_overriding_param_types : Warning< "conflicting parameter types in " "declaration of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_non_contravariant_param_types : Warning< "conflicting parameter types in " "implementation of %0: %1 vs %2">, InGroup, DefaultIgnore; def warn_conflicting_overriding_variadic :Warning< "conflicting variadic declaration of method and its " "implementation">, InGroup, DefaultIgnore; def warn_conflicting_variadic :Warning< "conflicting variadic declaration of method and its " "implementation">; def warn_category_method_impl_match:Warning< "category is implementing a method which will also be implemented" " by its primary class">, InGroup; def warn_implements_nscopying : Warning< "default assign attribute on property %0 which implements " "NSCopying protocol is not appropriate with -fobjc-gc[-only]">; def warn_multiple_method_decl : Warning<"multiple methods named %0 found">, InGroup; def warn_strict_multiple_method_decl : Warning< "multiple methods named %0 found">, InGroup, DefaultIgnore; def warn_accessor_property_type_mismatch : Warning< "type of property %0 does not match type of accessor %1">; def not_conv_function_declared_at : Note<"type conversion function declared here">; def note_method_declared_at : Note<"method %0 declared here">; def note_property_attribute : Note<"property %0 is declared " "%select{deprecated|unavailable|partial}1 here">; def err_setter_type_void : Error<"type of setter must be void">; def err_duplicate_method_decl : Error<"duplicate declaration of method %0">; def warn_duplicate_method_decl : Warning<"multiple declarations of method %0 found and ignored">, InGroup, DefaultIgnore; def warn_objc_cdirective_format_string : Warning<"using %0 directive in %select{NSString|CFString}1 " "which is being passed as a formatting argument to the formatting " "%select{method|CFfunction}2">, InGroup, DefaultIgnore; def err_objc_var_decl_inclass : Error<"cannot declare variable inside @interface or @protocol">; def error_missing_method_context : Error< "missing context for method declaration">; def err_objc_property_attr_mutually_exclusive : Error< "property attributes '%0' and '%1' are mutually exclusive">; def err_objc_property_requires_object : Error< "property with '%0' attribute must be of object type">; def warn_objc_property_no_assignment_attribute : Warning< "no 'assign', 'retain', or 'copy' attribute is specified - " "'assign' is assumed">, InGroup; def warn_objc_isa_use : Warning< "direct access to Objective-C's isa is deprecated in favor of " "object_getClass()">, InGroup; def warn_objc_isa_assign : Warning< "assignment to Objective-C's isa is deprecated in favor of " "object_setClass()">, InGroup; def warn_objc_pointer_masking : Warning< "bitmasking for introspection of Objective-C object pointers is strongly " "discouraged">, InGroup; def warn_objc_pointer_masking_performSelector : Warning, InGroup; def warn_objc_property_default_assign_on_object : Warning< "default property attribute 'assign' not appropriate for non-GC object">, InGroup; def warn_property_attr_mismatch : Warning< "property attribute in class extension does not match the primary class">, InGroup; def warn_property_implicitly_mismatched : Warning < "primary property declaration is implicitly strong while redeclaration " "in class extension is weak">, InGroup>; def warn_objc_property_copy_missing_on_block : Warning< "'copy' attribute must be specified for the block property " "when -fobjc-gc-only is specified">; def warn_objc_property_retain_of_block : Warning< "retain'ed block property does not copy the block " "- use copy attribute instead">, InGroup; def warn_objc_readonly_property_has_setter : Warning< "setter cannot be specified for a readonly property">, InGroup; def warn_atomic_property_rule : Warning< "writable atomic property %0 cannot pair a synthesized %select{getter|setter}1 " "with a user defined %select{getter|setter}2">, InGroup>; def note_atomic_property_fixup_suggest : Note<"setter and getter must both be " "synthesized, or both be user defined,or the property must be nonatomic">; def err_atomic_property_nontrivial_assign_op : Error< "atomic property of reference type %0 cannot have non-trivial assignment" " operator">; def warn_cocoa_naming_owned_rule : Warning< "property follows Cocoa naming" " convention for returning 'owned' objects">, InGroup>; def err_cocoa_naming_owned_rule : Error< "property follows Cocoa naming" " convention for returning 'owned' objects">; def note_cocoa_naming_declare_family : Note< "explicitly declare getter %objcinstance0 with '%1' to return an 'unowned' " "object">; def warn_auto_synthesizing_protocol_property :Warning< "auto property synthesis will not synthesize property %0" " declared in protocol %1">, InGroup>; def warn_no_autosynthesis_shared_ivar_property : Warning < "auto property synthesis will not synthesize property " "%0 because it cannot share an ivar with another synthesized property">, InGroup; def warn_no_autosynthesis_property : Warning< "auto property synthesis will not synthesize property " "%0 because it is 'readwrite' but it will be synthesized 'readonly' " "via another property">, InGroup; def warn_autosynthesis_property_in_superclass : Warning< "auto property synthesis will not synthesize property " "%0; it will be implemented by its superclass, use @dynamic to " "acknowledge intention">, InGroup; def warn_autosynthesis_property_ivar_match :Warning< "autosynthesized property %0 will use %select{|synthesized}1 instance variable " "%2, not existing instance variable %3">, InGroup>; def warn_missing_explicit_synthesis : Warning < "auto property synthesis is synthesizing property not explicitly synthesized">, InGroup>, DefaultIgnore; def warn_property_getter_owning_mismatch : Warning< "property declared as returning non-retained objects" "; getter returning retained objects">; def warn_property_redecl_getter_mismatch : Warning< "getter name mismatch between property redeclaration (%1) and its original " "declaration (%0)">, InGroup; def error_property_setter_ambiguous_use : Error< "synthesized properties %0 and %1 both claim setter %2 -" " use of this setter will cause unexpected behavior">; def warn_default_atomic_custom_getter_setter : Warning< "atomic by default property %0 has a user defined %select{getter|setter}1 " "(property should be marked 'atomic' if this is intended)">, InGroup, DefaultIgnore; def err_use_continuation_class : Error< "illegal redeclaration of property in class extension %0" " (attribute must be 'readwrite', while its primary must be 'readonly')">; def err_type_mismatch_continuation_class : Error< "type of property %0 in class extension does not match " "property type in primary class">; def err_use_continuation_class_redeclaration_readwrite : Error< "illegal redeclaration of 'readwrite' property in class extension %0" " (perhaps you intended this to be a 'readwrite' redeclaration of a " "'readonly' public property?)">; def err_continuation_class : Error<"class extension has no primary class">; def err_property_type : Error<"property cannot have array or function type %0">; def error_missing_property_context : Error< "missing context for property implementation declaration">; def error_bad_property_decl : Error< "property implementation must have its declaration in interface %0 or one of " "its extensions">; def error_category_property : Error< "property declared in category %0 cannot be implemented in " "class implementation">; def note_property_declare : Note< "property declared here">; def note_protocol_property_declare : Note< "it could also be property of type %0 declared here">; def note_property_synthesize : Note< "property synthesized here">; def error_synthesize_category_decl : Error< "@synthesize not allowed in a category's implementation">; def error_synthesize_on_class_property : Error< "@synthesize not allowed on a class property %0">; def error_reference_property : Error< "property of reference type is not supported">; def error_missing_property_interface : Error< "property implementation in a category with no category declaration">; def error_bad_category_property_decl : Error< "property implementation must have its declaration in the category %0">; def error_bad_property_context : Error< "property implementation must be in a class or category implementation">; def error_missing_property_ivar_decl : Error< "synthesized property %0 must either be named the same as a compatible" " instance variable or must explicitly name an instance variable">; def err_arc_perform_selector_retains : Error< "performSelector names a selector which retains the object">; def warn_arc_perform_selector_leaks : Warning< "performSelector may cause a leak because its selector is unknown">, InGroup>; def warn_dealloc_in_category : Warning< "-dealloc is being overridden in a category">, InGroup; def err_gc_weak_property_strong_type : Error< "weak attribute declared on a __strong type property in GC mode">; def warn_arc_repeated_use_of_weak : Warning < "weak %select{variable|property|implicit property|instance variable}0 %1 is " "accessed multiple times in this %select{function|method|block|lambda}2 " "but may be unpredictably set to nil; assign to a strong variable to keep " "the object alive">, InGroup, DefaultIgnore; def warn_implicitly_retains_self : Warning < "block implicitly retains 'self'; explicitly mention 'self' to indicate " "this is intended behavior">, InGroup>, DefaultIgnore; def warn_arc_possible_repeated_use_of_weak : Warning < "weak %select{variable|property|implicit property|instance variable}0 %1 may " "be accessed multiple times in this %select{function|method|block|lambda}2 " "and may be unpredictably set to nil; assign to a strong variable to keep " "the object alive">, InGroup, DefaultIgnore; def note_arc_weak_also_accessed_here : Note< "also accessed here">; def err_incomplete_synthesized_property : Error< "cannot synthesize property %0 with incomplete type %1">; def error_property_ivar_type : Error< "type of property %0 (%1) does not match type of instance variable %2 (%3)">; def error_property_accessor_type : Error< "type of property %0 (%1) does not match type of accessor %2 (%3)">; def error_ivar_in_superclass_use : Error< "property %0 attempting to use instance variable %1 declared in super class %2">; def error_weak_property : Error< "existing instance variable %1 for __weak property %0 must be __weak">; def error_strong_property : Error< "existing instance variable %1 for strong property %0 may not be __weak">; def error_dynamic_property_ivar_decl : Error< "dynamic property cannot have instance variable specification">; def error_duplicate_ivar_use : Error< "synthesized properties %0 and %1 both claim instance variable %2">; def error_property_implemented : Error<"property %0 is already implemented">; def warn_objc_missing_super_call : Warning< "method possibly missing a [super %0] call">, InGroup; def error_dealloc_bad_result_type : Error< "dealloc return type must be correctly specified as 'void' under ARC, " "instead of %0">; def warn_undeclared_selector : Warning< "undeclared selector %0">, InGroup, DefaultIgnore; def warn_undeclared_selector_with_typo : Warning< "undeclared selector %0; did you mean %1?">, InGroup, DefaultIgnore; def warn_implicit_atomic_property : Warning< "property is assumed atomic by default">, InGroup, DefaultIgnore; def note_auto_readonly_iboutlet_fixup_suggest : Note< "property should be changed to be readwrite">; def warn_auto_readonly_iboutlet_property : Warning< "readonly IBOutlet property %0 when auto-synthesized may " "not work correctly with 'nib' loader">, InGroup>; def warn_auto_implicit_atomic_property : Warning< "property is assumed atomic when auto-synthesizing the property">, InGroup, DefaultIgnore; def warn_unimplemented_selector: Warning< "no method with selector %0 is implemented in this translation unit">, InGroup, DefaultIgnore; def warn_unimplemented_protocol_method : Warning< "method %0 in protocol %1 not implemented">, InGroup; def warning_multiple_selectors: Warning< "several methods with selector %0 of mismatched types are found " "for the @selector expression">, InGroup, DefaultIgnore; def err_objc_kindof_nonobject : Error< "'__kindof' specifier cannot be applied to non-object type %0">; def err_objc_kindof_wrong_position : Error< "'__kindof' type specifier must precede the declarator">; // 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%select{ %1|}0">; def ext_static_assert_no_message : ExtWarn< "static_assert with no message is a C++1z extension">, InGroup; def warn_cxx14_compat_static_assert_no_message : Warning< "static_assert with no message is incompatible with C++ standards before C++1z">, DefaultIgnore, InGroup; def ext_inline_variable : ExtWarn< "inline variables are a C++1z extension">, InGroup; def warn_cxx14_compat_inline_variable : Warning< "inline variables are 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">; def err_inline_namespace_mismatch : Error< "%select{|non-}0inline namespace " "cannot be reopened as %select{non-|}0inline">; def err_unexpected_friend : Error< "friends can only be classes or functions">; def ext_enum_friend : ExtWarn< "befriending enumeration type %0 is a C++11 extension">, InGroup; def warn_cxx98_compat_enum_friend : Warning< "befriending enumeration type %0 is incompatible with C++98">, InGroup, DefaultIgnore; def ext_nonclass_type_friend : ExtWarn< "non-class friend type %0 is a C++11 extension">, InGroup; def warn_cxx98_compat_nonclass_type_friend : Warning< "non-class friend type %0 is incompatible with C++98">, InGroup, DefaultIgnore; 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< "unelaborated friend declaration is a C++11 extension; specify " "'%select{struct|interface|union|class|enum}0' to befriend %1">, InGroup; def warn_cxx98_compat_unelaborated_friend_type : Warning< "befriending %1 without '%select{struct|interface|union|class|enum}0' " "keyword is incompatible with C++98">, InGroup, DefaultIgnore; def err_qualified_friend_not_found : Error< "no function named %0 with type %1 was found in the specified scope">; def err_introducing_special_friend : Error< "must use a qualified name when declaring a %select{constructor|" "destructor|conversion operator}0 as a friend">; def err_tagless_friend_type_template : Error< "friend type templates must use an elaborated type">; def err_no_matching_local_friend : Error< "no matching function found in local scope">; def err_no_matching_local_friend_suggest : Error< "no matching function %0 found in local scope; did you mean %3?">; def err_partial_specialization_friend : Error< "partial specialization cannot be declared as a friend">; def err_qualified_friend_def : Error< "friend function definition cannot be qualified with '%0'">; def err_friend_def_in_local_class : Error< "friend function cannot be defined in a local class">; def err_friend_not_first_in_declaration : Error< "'friend' must appear first in a non-function declaration">; def err_using_decl_friend : Error< "cannot befriend target of using declaration">; def warn_template_qualified_friend_unsupported : Warning< "dependent nested name specifier '%0' for friend class declaration is " "not supported; turning off access control for %1">, InGroup; def warn_template_qualified_friend_ignored : Warning< "dependent nested name specifier '%0' for friend template declaration is " "not supported; ignoring this friend declaration">, InGroup; def ext_friend_tag_redecl_outside_namespace : ExtWarn< "unqualified friend declaration referring to type outside of the nearest " "enclosing namespace is a Microsoft extension; add a nested name specifier">, InGroup; def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">; def err_invalid_member_in_interface : Error< "%select{data member |non-public member function |static member function |" "user-declared constructor|user-declared destructor|operator |" "nested class }0%1 is not permitted within an interface type">; def err_invalid_base_in_interface : Error< "interface type cannot inherit from " "%select{'struct|non-public 'interface|'class}0 %1'">; def err_abstract_type_in_decl : Error< "%select{return|parameter|variable|field|instance variable|" "synthesized instance variable}0 type %1 is an abstract class">; def err_allocation_of_abstract_type : Error< "allocating an object of abstract class type %0">; def err_throw_abstract_type : Error< "cannot throw an object of abstract type %0">; def err_array_of_abstract_type : Error<"array of abstract class type %0">; def err_capture_of_abstract_type : Error< "by-copy capture of value of abstract type %0">; def err_capture_of_incomplete_type : Error< "by-copy capture of variable %0 with incomplete type %1">; def err_capture_default_non_local : Error< "non-local lambda expression cannot have a capture-default">; def err_multiple_final_overriders : Error< "virtual function %q0 has more than one final overrider in %1">; def note_final_overrider : Note<"final overrider of %q0 in %1">; def err_type_defined_in_type_specifier : Error< "%0 cannot be defined in a type specifier">; def err_type_defined_in_result_type : Error< "%0 cannot be defined in the result type of a function">; def err_type_defined_in_param_type : Error< "%0 cannot be defined in a parameter type">; def err_type_defined_in_alias_template : Error< "%0 cannot be defined in a type alias template">; def err_type_defined_in_condition : Error< "%0 cannot be defined in a condition">; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; def note_pure_qualified_call_kext : Note< "qualified call to %0::%1 is treated as a virtual call to %1 due to -fapple-kext">; def err_deleted_decl_not_first : Error< "deleted definition must be first declaration">; def err_deleted_override : Error< "deleted function %0 cannot override a non-deleted function">; def err_non_deleted_override : Error< "non-deleted function %0 cannot override a deleted function">; def warn_weak_vtable : Warning< "%0 has no out-of-line virtual method definitions; its vtable will be " "emitted in every translation unit">, InGroup>, DefaultIgnore; def warn_weak_template_vtable : Warning< "explicit template instantiation %0 will emit a vtable in every " "translation unit">, InGroup>, DefaultIgnore; def ext_using_undefined_std : ExtWarn< "using directive refers to implicitly-defined namespace 'std'">; // C++ exception specifications def err_exception_spec_in_typedef : Error< "exception specifications are not allowed in %select{typedefs|type aliases}0">; def err_distant_exception_spec : Error< "exception specifications are not allowed beyond a single level " "of indirection">; def err_incomplete_in_exception_spec : Error< "%select{|pointer to |reference to }0incomplete type %1 is not allowed " "in exception specification">; def ext_incomplete_in_exception_spec : ExtWarn, InGroup; def err_rref_in_exception_spec : Error< "rvalue reference type %0 is not allowed in exception specification">; def err_mismatched_exception_spec : Error< "exception specification in declaration does not match previous declaration">; def ext_mismatched_exception_spec : ExtWarn, InGroup; def err_override_exception_spec : Error< "exception specification of overriding function is more lax than " "base version">; def ext_override_exception_spec : ExtWarn, InGroup; def err_incompatible_exception_specs : Error< "target exception specification is not superset of source">; def err_deep_exception_specs_differ : Error< "exception specifications of %select{return|argument}0 types differ">; def err_missing_exception_specification : Error< "%0 is missing exception specification '%1'">; def ext_missing_exception_specification : ExtWarn< err_missing_exception_specification.Text>, InGroup>; def ext_ms_missing_exception_specification : ExtWarn< err_missing_exception_specification.Text>, InGroup; def err_noexcept_needs_constant_expression : Error< "argument to noexcept specifier must be a constant expression">; def err_exception_spec_not_parsed : Error< "exception specification is not available until end of class definition">; // C++ access checking def err_class_redeclared_with_different_access : Error< "%0 redeclared with '%1' access">; def err_access : Error< "%1 is a %select{private|protected}0 member of %3">, AccessControl; def ext_ms_using_declaration_inaccessible : ExtWarn< "using declaration referring to inaccessible member '%0' (which refers " "to accessible member '%1') is a Microsoft compatibility extension">, AccessControl, InGroup; def err_access_ctor : Error< "calling a %select{private|protected}0 constructor of class %2">, AccessControl; def ext_rvalue_to_reference_access_ctor : Extension< "C++98 requires an accessible copy constructor for class %2 when binding " "a reference to a temporary; was %select{private|protected}0">, AccessControl, InGroup; def err_access_base_ctor : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "%select{base class|inherited virtual base class}0 %1 has %select{private|" "protected}3 %select{default |copy |move |*ERROR* |*ERROR* " "|*ERROR*|}2constructor">, AccessControl; def err_access_field_ctor : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "field of type %0 has %select{private|protected}2 " "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}1constructor">, AccessControl; def err_access_friend_function : Error< "friend function %1 is a %select{private|protected}0 member of %3">, AccessControl; def err_access_dtor : Error< "calling a %select{private|protected}1 destructor of class %0">, AccessControl; def err_access_dtor_base : Error<"base class %0 has %select{private|protected}1 destructor">, AccessControl; def err_access_dtor_vbase : Error<"inherited virtual base class %1 has " "%select{private|protected}2 destructor">, AccessControl; def err_access_dtor_temp : Error<"temporary of type %0 has %select{private|protected}1 destructor">, AccessControl; def err_access_dtor_exception : Error<"exception object of type %0 has %select{private|protected}1 " "destructor">, AccessControl; def err_access_dtor_field : Error<"field of type %1 has %select{private|protected}2 destructor">, AccessControl; def err_access_dtor_var : Error<"variable of type %1 has %select{private|protected}2 destructor">, AccessControl; def err_access_dtor_ivar : Error<"instance variable of type %0 has %select{private|protected}1 " "destructor">, AccessControl; def note_previous_access_declaration : Note< "previously declared '%1' here">; def note_access_natural : Note< "%select{|implicitly }1declared %select{private|protected}0 here">; def note_access_constrained_by_path : Note< "constrained by %select{|implicitly }1%select{private|protected}0" " inheritance here">; def note_access_protected_restricted_noobject : Note< "must name member using the type of the current context %0">; def note_access_protected_restricted_ctordtor : Note< "protected %select{constructor|destructor}0 can only be used to " "%select{construct|destroy}0 a base class subobject">; def note_access_protected_restricted_object : Note< "can only access this member on an object of type %0">; def warn_cxx98_compat_sfinae_access_control : Warning< "substitution failure due to access control is incompatible with C++98">, InGroup, DefaultIgnore, NoSFINAE; // C++ name lookup def err_incomplete_nested_name_spec : Error< "incomplete type %0 named in nested name specifier">; def err_dependent_nested_name_spec : Error< "nested name specifier for a declaration cannot depend on a template " "parameter">; def err_nested_name_member_ref_lookup_ambiguous : Error< "lookup of %0 in member access expression is ambiguous">; def ext_nested_name_member_ref_lookup_ambiguous : ExtWarn< "lookup of %0 in member access expression is ambiguous; using member of %1">, InGroup; def note_ambig_member_ref_object_type : Note< "lookup in the object type %0 refers here">; def note_ambig_member_ref_scope : Note< "lookup from the current scope refers here">; def err_qualified_member_nonclass : Error< "qualified member access refers to a member in %0">; def err_incomplete_member_access : Error< "member access into incomplete type %0">; def err_incomplete_type : Error< "incomplete type %0 where a complete type is required">; def warn_cxx98_compat_enum_nested_name_spec : Warning< "enumeration type in nested name specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_nested_name_spec_is_not_class : Error< "%0 cannot appear before '::' because it is not a class" "%select{ or namespace|, namespace, or enumeration}1; did you mean ':'?">; def ext_nested_name_spec_is_enum : ExtWarn< "use of enumeration in a nested name specifier is a C++11 extension">, InGroup; // C++ class members def err_storageclass_invalid_for_member : Error< "storage class specified for a member declaration">; def err_mutable_function : Error<"'mutable' cannot be applied to functions">; def err_mutable_reference : Error<"'mutable' cannot be applied to references">; def ext_mutable_reference : ExtWarn< "'mutable' on a reference type is a Microsoft extension">, InGroup; def err_mutable_const : Error<"'mutable' and 'const' cannot be mixed">; def err_mutable_nonmember : Error< "'mutable' can only be applied to member variables">; def err_virtual_in_union : Error< "unions cannot have virtual functions">; def err_virtual_non_function : Error< "'virtual' can only appear on non-static member functions">; def err_virtual_out_of_class : Error< "'virtual' can only be specified inside the class definition">; def err_virtual_member_function_template : Error< "'virtual' cannot be specified on member function templates">; def err_static_overrides_virtual : Error< "'static' member function %0 overrides a virtual function in a base class">; def err_explicit_non_function : Error< "'explicit' can only appear on non-static member functions">; def err_explicit_out_of_class : Error< "'explicit' can only be specified inside the class definition">; def err_explicit_non_ctor_or_conv_function : Error< "'explicit' can only be applied to a constructor or conversion function">; def err_static_not_bitfield : Error<"static member %0 cannot be a bit-field">; def err_static_out_of_line : Error< "'static' can only be specified inside the class definition">; def err_storage_class_for_static_member : Error< "static data member definition cannot specify a storage class">; def err_typedef_not_bitfield : Error<"typedef member %0 cannot be a bit-field">; def err_not_integral_type_bitfield : Error< "bit-field %0 has non-integral type %1">; def err_not_integral_type_anon_bitfield : Error< "anonymous bit-field has non-integral type %0">; def err_member_function_initialization : Error< "initializer on function does not look like a pure-specifier">; def err_non_virtual_pure : Error< "%0 is not virtual and cannot be declared pure">; def ext_pure_function_definition : ExtWarn< "function definition with pure-specifier is a Microsoft extension">, InGroup; def err_implicit_object_parameter_init : Error< "cannot initialize object parameter of type %0 with an expression " "of type %1">; def err_qualified_member_of_unrelated : Error< "%q0 is not a member of class %1">; def warn_call_to_pure_virtual_member_function_from_ctor_dtor : Warning< "call to pure virtual member function %0 has undefined behavior; " "overrides of %0 in subclasses are not available in the " "%select{constructor|destructor}1 of %2">; def note_member_declared_at : Note<"member is declared here">; def note_ivar_decl : Note<"instance variable is declared here">; def note_bitfield_decl : Note<"bit-field is declared here">; def note_implicit_param_decl : Note<"%0 is an implicit parameter">; def note_member_synthesized_at : Note< "implicit %select{default constructor|copy constructor|move constructor|copy " "assignment operator|move assignment operator|destructor}0 for %1 first " "required here">; def note_inhctor_synthesized_at : Note< "inherited constructor for %0 first required here">; def err_missing_default_ctor : Error< "%select{constructor for %1 must explicitly initialize the|" "implicit default constructor for %1 must explicitly initialize the|" "cannot use constructor inherited from base class %4;}0 " "%select{base class|member}2 %3 %select{which|which|of %1}0 " "does not have a default constructor">; def note_due_to_dllexported_class : Note< "due to '%0' being dllexported%select{|; try compiling in C++11 mode}1">; def err_illegal_union_or_anon_struct_member : Error< "%select{anonymous struct|union}0 member %1 has a non-trivial " "%select{constructor|copy constructor|move constructor|copy assignment " "operator|move assignment operator|destructor}2">; def warn_cxx98_compat_nontrivial_union_or_anon_struct_member : Warning< "%select{anonymous struct|union}0 member %1 with a non-trivial " "%select{constructor|copy constructor|move constructor|copy assignment " "operator|move assignment operator|destructor}2 is incompatible with C++98">, InGroup, DefaultIgnore; def note_nontrivial_virtual_dtor : Note< "destructor for %0 is not trivial because it is virtual">; def note_nontrivial_has_virtual : Note< "because type %0 has a virtual %select{member function|base class}1">; def note_nontrivial_no_def_ctor : Note< "because %select{base class of |field of |}0type %1 has no " "default constructor">; def note_user_declared_ctor : Note< "implicit default constructor suppressed by user-declared constructor">; def note_nontrivial_no_copy : Note< "because no %select{<>|constructor|constructor|assignment operator|" "assignment operator|<>}2 can be used to " "%select{<>|copy|move|copy|move|<>}2 " "%select{base class|field|an object}0 of type %3">; def note_nontrivial_user_provided : Note< "because %select{base class of |field of |}0type %1 has a user-provided " "%select{default constructor|copy constructor|move constructor|" "copy assignment operator|move assignment operator|destructor}2">; def note_nontrivial_in_class_init : Note< "because field %0 has an initializer">; def note_nontrivial_param_type : Note< "because its parameter is %diff{of type $, not $|of the wrong type}2,3">; def note_nontrivial_default_arg : Note<"because it has a default argument">; def note_nontrivial_variadic : Note<"because it is a variadic function">; def note_nontrivial_subobject : Note< "because the function selected to %select{construct|copy|move|copy|move|" "destroy}2 %select{base class|field}0 of type %1 is not trivial">; def note_nontrivial_objc_ownership : Note< "because type %0 has a member with %select{no|no|__strong|__weak|" "__autoreleasing}1 ownership">; def err_static_data_member_not_allowed_in_anon_struct : Error< "static data member %0 not allowed in anonymous struct">; def ext_static_data_member_in_union : ExtWarn< "static data member %0 in union is a C++11 extension">, InGroup; def warn_cxx98_compat_static_data_member_in_union : Warning< "static data member %0 in union is incompatible with C++98">, InGroup, DefaultIgnore; def ext_union_member_of_reference_type : ExtWarn< "union member %0 has reference type %1, which is a Microsoft extension">, InGroup; def err_union_member_of_reference_type : Error< "union member %0 has reference type %1">; def ext_anonymous_struct_union_qualified : Extension< "anonymous %select{struct|union}0 cannot be '%1'">; def err_different_return_type_for_overriding_virtual_function : Error< "virtual function %0 has a different return type " "%diff{($) than the function it overrides (which has return type $)|" "than the function it overrides}1,2">; def note_overridden_virtual_function : Note< "overridden virtual function is here">; def err_conflicting_overriding_cc_attributes : Error< "virtual function %0 has different calling convention attributes " "%diff{($) than the function it overrides (which has calling convention $)|" "than the function it overrides}1,2">; def err_covariant_return_inaccessible_base : Error< "invalid covariant return for virtual function: %1 is a " "%select{private|protected}2 base class of %0">, AccessControl; def err_covariant_return_ambiguous_derived_to_base_conv : Error< "return type of virtual function %3 is not covariant with the return type of " "the function it overrides (ambiguous conversion from derived class " "%0 to base class %1:%2)">; def err_covariant_return_not_derived : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 is not derived from %2)">; def err_covariant_return_incomplete : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 is incomplete)">; def err_covariant_return_type_different_qualifications : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (%1 has different qualifiers than %2)">; def err_covariant_return_type_class_type_more_qualified : Error< "return type of virtual function %0 is not covariant with the return type of " "the function it overrides (class type %1 is more qualified than class " "type %2">; // C++ constructors def err_constructor_cannot_be : Error<"constructor cannot be declared '%0'">; def err_invalid_qualified_constructor : Error< "'%0' qualifier is not allowed on a constructor">; def err_ref_qualifier_constructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a constructor">; def err_constructor_return_type : Error< "constructor cannot have a return type">; def err_constructor_redeclared : Error<"constructor cannot be redeclared">; def err_constructor_byvalue_arg : Error< "copy constructor must pass its first argument by reference">; def warn_no_constructor_for_refconst : Warning< "%select{struct|interface|union|class|enum}0 %1 does not declare any " "constructor to initialize its non-modifiable members">; def note_refconst_member_not_initialized : Note< "%select{const|reference}0 member %1 will never be initialized">; def ext_ms_explicit_constructor_call : ExtWarn< "explicit constructor calls are a Microsoft extension">, InGroup; // C++ destructors def err_destructor_not_member : Error< "destructor must be a non-static member function">; def err_destructor_cannot_be : Error<"destructor cannot be declared '%0'">; def err_invalid_qualified_destructor : Error< "'%0' qualifier is not allowed on a destructor">; def err_ref_qualifier_destructor : Error< "ref-qualifier '%select{&&|&}0' is not allowed on a destructor">; def err_destructor_return_type : Error<"destructor cannot have a return type">; def err_destructor_redeclared : Error<"destructor cannot be redeclared">; def err_destructor_with_params : Error<"destructor cannot have any parameters">; def err_destructor_variadic : Error<"destructor cannot be variadic">; def err_destructor_typedef_name : Error< "destructor cannot be declared using a %select{typedef|type alias}1 %0 of the class name">; def err_destructor_name : Error< "expected the class name after '~' to name the enclosing class">; def err_destructor_class_name : Error< "expected the class name after '~' to name a destructor">; def err_ident_in_dtor_not_a_type : Error< "identifier %0 in object destruction expression does not name a type">; def err_destructor_expr_type_mismatch : Error< "destructor type %0 in object destruction expression does not match the " "type %1 of the object being destroyed">; def note_destructor_type_here : Note< "type %0 is declared here">; def err_destructor_template : Error< "destructor cannot be declared as a template">; // C++ initialization def err_init_conversion_failed : Error< "cannot initialize %select{a variable|a parameter|return object|an " "exception object|a member subobject|an array element|a new value|a value|a " "base class|a constructor delegation|a vector element|a block element|a " "complex element|a lambda capture|a compound literal initializer|a " "related result|a parameter of CF audited function}0 " "%diff{of type $ with an %select{rvalue|lvalue}2 of type $|" "with an %select{rvalue|lvalue}2 of incompatible type}1,3" "%select{|: different classes%diff{ ($ vs $)|}5,6" "|: different number of parameters (%5 vs %6)" "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" "|: different return type%diff{ ($ vs $)|}5,6" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}6)}4">; def err_lvalue_to_rvalue_ref : Error<"rvalue reference %diff{to type $ cannot " "bind to lvalue of type $|cannot bind to incompatible lvalue}0,1">; def err_lvalue_reference_bind_to_initlist : Error< "%select{non-const|volatile}0 lvalue reference to type %1 cannot bind to an " "initializer list temporary">; def err_lvalue_reference_bind_to_temporary : Error< "%select{non-const|volatile}0 lvalue reference %diff{to type $ cannot bind " "to a temporary of type $|cannot bind to incompatible temporary}1,2">; def err_lvalue_reference_bind_to_unrelated : Error< "%select{non-const|volatile}0 lvalue reference " "%diff{to type $ cannot bind to a value of unrelated type $|" "cannot bind to a value of unrelated type}1,2">; def err_reference_bind_drops_quals : Error< "binding value %diff{of type $ to reference to type $|to reference}0,1 " "drops %select{<>|'const'|'restrict'|'const' and 'restrict'|" "'volatile'|'const' and 'volatile'|'restrict' and 'volatile'|" "'const', 'restrict', and 'volatile'}2 qualifier%plural{1:|2:|4:|:s}2">; def err_reference_bind_failed : Error< "reference %diff{to type $ could not bind to an %select{rvalue|lvalue}1 of " "type $|could not bind to %select{rvalue|lvalue}1 of incompatible type}0,2">; def err_reference_bind_init_list : Error< "reference to type %0 cannot bind to an initializer list">; def warn_temporary_array_to_pointer_decay : Warning< "pointer is initialized by a temporary array, which will be destroyed at the " "end of the full-expression">, InGroup>; def err_init_list_bad_dest_type : Error< "%select{|non-aggregate }0type %1 cannot be initialized with an initializer " "list">; def err_member_function_call_bad_cvr : Error<"member function %0 not viable: " "'this' argument has type %1, but function is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}2">; def err_reference_bind_to_bitfield : Error< "%select{non-const|volatile}0 reference cannot bind to " "bit-field%select{| %1}2">; def err_reference_bind_to_vector_element : Error< "%select{non-const|volatile}0 reference cannot bind to vector element">; def err_reference_var_requires_init : Error< "declaration of reference variable %0 requires an initializer">; def err_reference_without_init : Error< "reference to type %0 requires an initializer">; def note_value_initialization_here : Note< "in value-initialization of type %0 here">; def err_reference_has_multiple_inits : Error< "reference cannot be initialized with multiple values">; def err_init_non_aggr_init_list : Error< "initialization of non-aggregate type %0 with an initializer list">; def err_init_reference_member_uninitialized : Error< "reference member of type %0 uninitialized">; def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field %0 is uninitialized when used here">, InGroup; def warn_base_class_is_uninit : Warning< "base class %0 is uninitialized when used here to access %q1">, InGroup; def warn_reference_field_is_uninit : Warning< "reference %0 is not yet bound to a value when used here">, InGroup; def note_uninit_in_this_constructor : Note< "during field initialization in %select{this|the implicit default}0 " "constructor">; def warn_static_self_reference_in_init : Warning< "static variable %0 is suspiciously used within its own initialization">, InGroup; def warn_uninit_self_reference_in_init : Warning< "variable %0 is uninitialized when used within its own initialization">, InGroup; def warn_uninit_self_reference_in_reference_init : Warning< "reference %0 is not yet bound to a value when used within its own" " initialization">, InGroup; def warn_uninit_var : Warning< "variable %0 is uninitialized when %select{used here|captured by block}1">, InGroup, DefaultIgnore; def warn_sometimes_uninit_var : Warning< "variable %0 is %select{used|captured}1 uninitialized whenever " "%select{'%3' condition is %select{true|false}4|" "'%3' loop %select{is entered|exits because its condition is false}4|" "'%3' loop %select{condition is true|exits because its condition is false}4|" "switch %3 is taken|" "its declaration is reached|" "%3 is called}2">, InGroup, DefaultIgnore; def warn_maybe_uninit_var : Warning< "variable %0 may be uninitialized when " "%select{used here|captured by block}1">, InGroup, DefaultIgnore; def note_var_declared_here : Note<"variable %0 is declared here">; def note_uninit_var_use : Note< "%select{uninitialized use occurs|variable is captured by block}0 here">; def warn_uninit_byref_blockvar_captured_by_block : Warning< "block pointer variable %0 is uninitialized when captured by block">, InGroup, DefaultIgnore; def note_block_var_fixit_add_initialization : Note< "did you mean to use __block %0?">; def note_in_omitted_aggregate_initializer : Note< "in implicit initialization of %select{array element %1|field %1}0 " "with omitted initializer">; def note_in_reference_temporary_list_initializer : Note< "in initialization of temporary of type %0 created to " "list-initialize this reference">; def note_var_fixit_add_initialization : Note< "initialize the variable %0 to silence this warning">; def note_uninit_fixit_remove_cond : Note< "remove the %select{'%1' if its condition|condition if it}0 " "is always %select{false|true}2">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; def warn_unsequenced_mod_mod : Warning< "multiple unsequenced modifications to %0">, InGroup; def warn_unsequenced_mod_use : Warning< "unsequenced modification and access to %0">, InGroup; def err_temp_copy_no_viable : Error< "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1">; def ext_rvalue_to_reference_temp_copy_no_viable : Extension< "no viable constructor %select{copying variable|copying parameter|" "returning object|throwing object|copying member subobject|copying array " "element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1; C++98 requires a copy " "constructor when binding a reference to a temporary">, InGroup; def err_temp_copy_ambiguous : Error< "ambiguous constructor call when %select{copying variable|copying " "parameter|returning object|throwing object|copying member subobject|copying " "array element|allocating object|copying temporary|initializing base subobject|" "initializing vector element|capturing value}0 of type %1">; def err_temp_copy_deleted : Error< "%select{copying variable|copying parameter|returning object|throwing " "object|copying member subobject|copying array element|allocating object|" "copying temporary|initializing base subobject|initializing vector element|" "capturing value}0 of type %1 invokes deleted constructor">; def err_temp_copy_incomplete : Error< "copying a temporary object of incomplete type %0">; def warn_cxx98_compat_temp_copy : Warning< "%select{copying variable|copying parameter|returning object|throwing " "object|copying member subobject|copying array element|allocating object|" "copying temporary|initializing base subobject|initializing vector element}1 " "of type %2 when binding a reference to a temporary would %select{invoke " "an inaccessible constructor|find no viable constructor|find ambiguous " "constructors|invoke a deleted constructor}0 in C++98">, InGroup, DefaultIgnore; def err_selected_explicit_constructor : Error< "chosen constructor is explicit in copy-initialization">; def note_constructor_declared_here : Note< "constructor declared here">; // C++11 decltype def err_decltype_in_declarator : Error< "'decltype' cannot be used to name a declaration">; // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; def err_auto_variable_cannot_appear_in_own_initializer : Error< "variable %0 declared with %select{'auto'|'decltype(auto)'|'__auto_type'}1 " "type cannot appear in its own initializer">; def err_illegal_decl_array_of_auto : Error< "'%0' declared as array of %1">; def err_new_array_of_auto : Error< "cannot allocate array of 'auto'">; def err_auto_not_allowed : Error< "%select{'auto'|'decltype(auto)'|'__auto_type'}0 not allowed " "%select{in function prototype" "|in non-static struct member|in struct member" "|in non-static union member|in union member" "|in non-static class member|in interface member" "|in exception declaration|in template parameter|in block literal" "|in template argument|in typedef|in type alias|in function return type" "|in conversion function type|here|in lambda parameter" "|in type allocated by 'new'|in K&R-style function parameter}1">; def err_auto_not_allowed_var_inst : Error< "'auto' variable template instantiation is not allowed">; def err_auto_var_requires_init : Error< "declaration of variable %0 with type %1 requires an initializer">; def err_auto_new_requires_ctor_arg : Error< "new expression for type %0 requires a constructor argument">; def err_auto_new_list_init : Error< "new expression for type %0 cannot use list-initialization">; def err_auto_var_init_no_expression : Error< "initializer for variable %0 with type %1 is empty">; def err_auto_var_init_multiple_expressions : Error< "initializer for variable %0 with type %1 contains multiple expressions">; def err_auto_var_init_paren_braces : Error< "cannot deduce type for variable %1 with type %2 from " "%select{parenthesized|nested}0 initializer list">; def err_auto_new_ctor_multiple_expressions : Error< "new expression for type %0 contains multiple constructor arguments">; def err_auto_missing_trailing_return : Error< "'auto' return without trailing return type; deduced return types are a " "C++14 extension">; def err_deduced_return_type : Error< "deduced return types are a C++14 extension">; def err_trailing_return_without_auto : Error< "function with trailing return type must specify return type 'auto', not %0">; def err_trailing_return_in_parens : Error< "trailing return type may not be nested within parentheses">; def err_auto_var_deduction_failure : Error< "variable %0 with type %1 has incompatible initializer of type %2">; def err_auto_var_deduction_failure_from_init_list : Error< "cannot deduce actual type for variable %0 with type %1 from initializer list">; def err_auto_new_deduction_failure : Error< "new expression for type %0 has incompatible constructor argument of type %1">; def err_auto_different_deductions : Error< "'%select{auto|decltype(auto)|__auto_type}0' deduced as %1 in declaration " "of %2 and deduced as %3 in declaration of %4">; def err_implied_std_initializer_list_not_found : Error< "cannot deduce type of initializer list because std::initializer_list was " "not found; include ">; def err_malformed_std_initializer_list : Error< "std::initializer_list must be a class template with a single type parameter">; def warn_dangling_std_initializer_list : Warning< "array backing the initializer list will be destroyed at the end of " "%select{the full-expression|the constructor}0">, InGroup>; def err_auto_init_list_from_c : Error< "cannot use __auto_type with initializer list in C">; def err_auto_bitfield : Error< "cannot pass bit-field as __auto_type initializer in C">; // C++1y decltype(auto) type def err_decltype_auto_cannot_be_combined : Error< "'decltype(auto)' cannot be combined with other type specifiers">; def err_decltype_auto_function_declarator_not_declaration : Error< "'decltype(auto)' can only be used as a return type " "in a function declaration">; def err_decltype_auto_compound_type : Error< "cannot form %select{pointer to|reference to|array of}0 'decltype(auto)'">; def err_decltype_auto_initializer_list : Error< "cannot deduce 'decltype(auto)' from initializer list">; // C++1y deduced return types def err_auto_fn_deduction_failure : Error< "cannot deduce return type %0 from returned value of type %1">; def err_auto_fn_different_deductions : Error< "'%select{auto|decltype(auto)}0' in return type deduced as %1 here but " "deduced as %2 in earlier return statement">; def err_auto_fn_used_before_defined : Error< "function %0 with deduced return type cannot be used before it is defined">; def err_auto_fn_no_return_but_not_auto : Error< "cannot deduce return type %0 for function with no return statements">; def err_auto_fn_return_void_but_not_auto : Error< "cannot deduce return type %0 from omitted return expression">; def err_auto_fn_return_init_list : Error< "cannot deduce return type from initializer list">; def err_auto_fn_virtual : Error< "function with deduced return type cannot be virtual">; // C++11 override control def override_keyword_only_allowed_on_virtual_member_functions : Error< "only virtual member functions can be marked '%0'">; def override_keyword_hides_virtual_member_function : Error< "non-virtual member function marked '%0' hides virtual member " "%select{function|functions}1">; def err_function_marked_override_not_overriding : Error< "%0 marked 'override' but does not override any member functions">; def warn_function_marked_not_override_overriding : Warning < "%0 overrides a member function but is not marked 'override'">, InGroup; def err_class_marked_final_used_as_base : Error< "base %0 is marked '%select{final|sealed}1'">; def warn_abstract_final_class : Warning< "abstract class is marked '%select{final|sealed}0'">, InGroup; // C++11 attributes def err_repeat_attribute : Error<"%0 attribute cannot be repeated">; // C++11 final def err_final_function_overridden : Error< "declaration of %0 overrides a '%select{final|sealed}1' function">; // C++11 scoped enumerations def err_enum_invalid_underlying : Error< "non-integral type %0 is an invalid underlying type">; def err_enumerator_too_large : Error< "enumerator value is not representable in the underlying type %0">; def ext_enumerator_too_large : ExtWarn< "enumerator value is not representable in the underlying type %0">, InGroup; def err_enumerator_wrapped : Error< "enumerator value %0 is not representable in the underlying type %1">; def err_enum_redeclare_type_mismatch : Error< "enumeration redeclared with different underlying type %0 (was %1)">; def err_enum_redeclare_fixed_mismatch : Error< "enumeration previously declared with %select{non|}0fixed underlying type">; def err_enum_redeclare_scoped_mismatch : Error< "enumeration previously declared as %select{un|}0scoped">; def err_enum_class_reference : Error< "reference to %select{|scoped }0enumeration must use 'enum' " "not 'enum class'">; def err_only_enums_have_underlying_types : Error< "only enumeration types have underlying types">; def err_underlying_type_of_incomplete_enum : Error< "cannot determine underlying type of incomplete enumeration type %0">; // C++11 delegating constructors 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< "constructor for %0 creates a delegation cycle">, DefaultError, InGroup; def note_it_delegates_to : Note<"it delegates to">; def note_which_delegates_to : Note<"which delegates to">; // C++11 range-based for loop def err_for_range_decl_must_be_var : Error< "for range declaration must declare a variable">; def err_for_range_storage_class : Error< "loop variable %0 may not be declared %select{'extern'|'static'|" "'__private_extern__'|'auto'|'register'|'constexpr'}1">; def err_type_defined_in_for_range : Error< "types may not be defined in a for range declaration">; def err_for_range_deduction_failure : Error< "cannot use type %0 as a range">; def err_for_range_incomplete_type : Error< "cannot use incomplete type %0 as a range">; def err_for_range_iter_deduction_failure : Error< "cannot use type %0 as an iterator">; def err_for_range_member_begin_end_mismatch : Error< "range type %0 has '%select{begin|end}1' member but no '%select{end|begin}1' member">; def ext_for_range_begin_end_types_differ : ExtWarn< "'begin' and 'end' returning different types (%0 and %1) is a C++1z extension">, InGroup; def warn_for_range_begin_end_types_differ : Warning< "'begin' and 'end' returning different types (%0 and %1) is incompatible " "with C++ standards before C++1z">, InGroup, DefaultIgnore; def note_in_for_range: Note< "when looking up '%select{begin|end}0' function for range expression " "of type %1">; def err_for_range_invalid: Error< "invalid range expression of type %0; no viable '%select{begin|end}1' " "function available">; def err_range_on_array_parameter : Error< "cannot build range expression with array function parameter %0 since " "parameter with array type %1 is treated as pointer type %2">; def err_for_range_dereference : Error< "invalid range expression of type %0; did you mean to dereference it " "with '*'?">; def note_for_range_invalid_iterator : Note < "in implicit call to 'operator%select{!=|*|++}0' for iterator of type %1">; def note_for_range_begin_end : Note< "selected '%select{begin|end}0' %select{function|template }1%2 with iterator type %3">; def warn_for_range_const_reference_copy : Warning< "loop variable %0 " "%diff{has type $ but is initialized with type $" "| is initialized with a value of a different type}1,2 resulting in a copy">, InGroup, DefaultIgnore; def note_use_type_or_non_reference : Note< "use non-reference type %0 to keep the copy or type %1 to prevent copying">; def warn_for_range_variable_always_copy : Warning< "loop variable %0 is always a copy because the range of type %1 does not " "return a reference">, InGroup, DefaultIgnore; def note_use_non_reference_type : Note<"use non-reference type %0">; def warn_for_range_copy : Warning< "loop variable %0 of type %1 creates a copy from type %2">, InGroup, DefaultIgnore; def note_use_reference_type : Note<"use reference type %0 to prevent copying">; // C++11 constexpr def warn_cxx98_compat_constexpr : Warning< "'constexpr' specifier is incompatible with C++98">, InGroup, DefaultIgnore; // FIXME: Maybe this should also go in -Wc++14-compat? def warn_cxx14_compat_constexpr_not_const : Warning< "'constexpr' non-static member function will not be implicitly 'const' " "in C++14; add 'const' to avoid a change in behavior">, InGroup>; def err_invalid_constexpr : Error< "%select{function parameter|typedef|non-static data member}0 " "cannot be constexpr">; def err_invalid_constexpr_member : Error<"non-static data member cannot be " "constexpr%select{; did you intend to make it %select{const|static}0?|}1">; def err_constexpr_tag : Error< "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">; def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">; def err_constexpr_no_declarators : Error< "constexpr can only be used in variable and function declarations">; def err_invalid_constexpr_var_decl : Error< "constexpr variable declaration must be a definition">; def err_constexpr_static_mem_var_requires_init : Error< "declaration of constexpr static data member %0 requires an initializer">; def err_constexpr_var_non_literal : Error< "constexpr variable cannot have non-literal type %0">; def err_constexpr_var_requires_const_init : Error< "constexpr variable %0 must be initialized by a constant expression">; def err_constexpr_redecl_mismatch : Error< "%select{non-constexpr declaration of %0 follows constexpr declaration" "|constexpr declaration of %0 follows non-constexpr declaration}1">; def err_constexpr_virtual : Error<"virtual function cannot be constexpr">; def err_constexpr_virtual_base : Error< "constexpr %select{member function|constructor}0 not allowed in " "%select{struct|interface|class}1 with virtual base " "%plural{1:class|:classes}2">; def note_non_literal_incomplete : Note< "incomplete type %0 is not a literal type">; def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 " "with virtual base %plural{1:class|:classes}1 is not a literal type">; def note_constexpr_virtual_base_here : Note<"virtual base class declared here">; def err_constexpr_non_literal_return : Error< "constexpr function's return type %0 is not a literal type">; def err_constexpr_non_literal_param : Error< "constexpr %select{function|constructor}1's %ordinal0 parameter type %2 is " "not a literal type">; def err_constexpr_body_invalid_stmt : Error< "statement not allowed in constexpr %select{function|constructor}0">; def ext_constexpr_body_invalid_stmt : ExtWarn< "use of this statement in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning< "use of this statement in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def ext_constexpr_type_definition : ExtWarn< "type definition in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_type_definition : Warning< "type definition in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_constexpr_vla : Error< "variably-modified type %0 cannot be used in a constexpr " "%select{function|constructor}1">; def ext_constexpr_local_var : ExtWarn< "variable declaration in a constexpr %select{function|constructor}0 " "is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_local_var : Warning< "variable declaration in a constexpr %select{function|constructor}0 " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_constexpr_local_var_static : Error< "%select{static|thread_local}1 variable not permitted in a constexpr " "%select{function|constructor}0">; def err_constexpr_local_var_non_literal_type : Error< "variable of non-literal type %1 cannot be defined in a constexpr " "%select{function|constructor}0">; def err_constexpr_local_var_no_init : Error< "variables defined in a constexpr %select{function|constructor}0 must be " "initialized">; def ext_constexpr_function_never_constant_expr : ExtWarn< "constexpr %select{function|constructor}0 never produces a " "constant expression">, InGroup>, DefaultError; def err_enable_if_never_constant_expr : Error< "'enable_if' attribute expression never produces a constant expression">; def err_constexpr_body_no_return : Error< "no return statement in constexpr function">; def err_constexpr_return_missing_expr : Error< "non-void constexpr function %0 should return a value">; def warn_cxx11_compat_constexpr_body_no_return : Warning< "constexpr function with no return statements is incompatible with C++ " "standards before C++14">, InGroup, DefaultIgnore; def ext_constexpr_body_multiple_return : ExtWarn< "multiple return statements in constexpr function is a C++14 extension">, InGroup; def warn_cxx11_compat_constexpr_body_multiple_return : Warning< "multiple return statements in constexpr function " "is incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def note_constexpr_body_previous_return : Note< "previous return statement is here">; def err_constexpr_function_try_block : Error< "function try block not allowed in constexpr %select{function|constructor}0">; def err_constexpr_union_ctor_no_init : Error< "constexpr union constructor does not initialize any member">; def err_constexpr_ctor_missing_init : Error< "constexpr constructor must initialize all members">; def note_constexpr_ctor_missing_init : Note< "member not initialized by constructor">; def note_non_literal_no_constexpr_ctors : Note< "%0 is not literal because it is not an aggregate and has no constexpr " "constructors other than copy or move constructors">; def note_non_literal_base_class : Note< "%0 is not literal because it has base class %1 of non-literal type">; def note_non_literal_field : Note< "%0 is not literal because it has data member %1 of " "%select{non-literal|volatile}3 type %2">; def note_non_literal_user_provided_dtor : Note< "%0 is not literal because it has a user-provided destructor">; def note_non_literal_nontrivial_dtor : Note< "%0 is not literal because it has a non-trivial destructor">; def warn_private_extern : Warning< "use of __private_extern__ on a declaration may not produce external symbol " "private to the linkage unit and is deprecated">, InGroup; def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; // C++ Concepts TS def err_concept_wrong_decl_kind : Error< "'concept' can only appear on the definition of a function template or variable template">; def err_concept_decls_may_only_appear_in_namespace_scope : Error< "concept declarations may only appear in namespace scope">; def err_function_concept_not_defined : Error< "function concept declaration must be a definition">; def err_var_concept_not_initialized : Error< "variable concept declaration must be initialized">; def err_function_concept_exception_spec : Error< "function concept cannot have exception specification">; def err_concept_decl_invalid_specifiers : Error< "%select{variable|function}0 concept cannot be declared " "'%select{thread_local|inline|friend|constexpr}1'">; def err_function_concept_with_params : Error< "function concept cannot have any parameters">; def err_function_concept_bool_ret : Error< "declared return type of function concept must be 'bool'">; def err_variable_concept_bool_decl : Error< "declared type of variable concept must be 'bool'">; def err_concept_specified_specialization : Error< "'concept' cannot be applied on an " "%select{explicit instantiation|explicit specialization|partial specialization}0">; def err_concept_specialized : Error< "%select{function|variable}0 concept cannot be " "%select{explicitly instantiated|explicitly specialized|partially specialized}1">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< "'%0' type specifier is incompatible with C++98">, InGroup, DefaultIgnore; // __make_integer_seq def err_integer_sequence_negative_length : Error< "integer sequences must have non-negative sequence length">; def err_integer_sequence_integral_element_type : Error< "integer sequences must have integral element type">; // __type_pack_element def err_type_pack_element_out_of_bounds : Error< "a parameter pack may not be accessed at an out of bounds index">; // Objective-C++ def err_objc_decls_may_only_appear_in_global_scope : Error< "Objective-C declarations may only appear in global scope">; def warn_auto_var_is_id : Warning< "'auto' deduced as 'id' in declaration of %0">, InGroup>; // Attributes def err_nsobject_attribute : Error< "'NSObject' attribute is for pointer types only">; def err_attributes_are_not_compatible : Error< "%0 and %1 attributes are not compatible">; def err_attribute_wrong_number_arguments : Error< "%0 attribute %plural{0:takes no arguments|1:takes one argument|" ":requires exactly %1 arguments}1">; def err_attribute_too_many_arguments : Error< "%0 attribute takes no more than %1 argument%s1">; def err_attribute_too_few_arguments : Error< "%0 attribute takes at least %1 argument%s1">; def err_attribute_invalid_vector_type : Error<"invalid vector element type %0">; def err_attribute_bad_neon_vector_size : Error< "Neon vector size must be 64 or 128 bits">; def err_attribute_requires_positive_integer : Error< "%0 attribute requires a positive integral compile time constant expression">; def err_attribute_requires_opencl_version : Error< "%0 attribute requires OpenCL version %1%select{| or above}2">; def warn_unsupported_target_attribute : Warning<"Ignoring unsupported '%0' in the target attribute string">, InGroup; def err_attribute_unsupported : Error<"%0 attribute is not supported for this target">; // The err_*_attribute_argument_not_int are seperate because they're used by // VerifyIntegerConstantExpression. def err_aligned_attribute_argument_not_int : Error< "'aligned' attribute requires integer constant">; def err_align_value_attribute_argument_not_int : Error< "'align_value' attribute requires integer constant">; def err_alignas_attribute_wrong_decl_type : Error< "%0 attribute cannot be applied to a %select{function parameter|" "variable with 'register' storage class|'catch' variable|bit-field}1">; def err_alignas_missing_on_definition : Error< "%0 must be specified on definition if it is specified on any declaration">; def note_alignas_on_declaration : Note<"declared with %0 attribute here">; def err_alignas_mismatch : Error< "redeclaration has different alignment requirement (%1 vs %0)">; def err_alignas_underaligned : Error< "requested alignment is less than minimum alignment of %1 for type %0">; def err_attribute_argument_n_type : Error< "%0 attribute requires parameter %1 to be %select{int or bool|an integer " "constant|a string|an identifier}2">; def err_attribute_argument_type : Error< "%0 attribute requires %select{int or bool|an integer " "constant|a string|an identifier}1">; def err_attribute_argument_outof_range : Error< "%0 attribute requires integer constant between %1 and %2 inclusive">; def err_init_priority_object_attr : Error< "can only use 'init_priority' attribute on file-scope definitions " "of objects of class type">; def err_attribute_argument_vec_type_hint : Error< "invalid attribute argument %0 - expecting a vector or vectorizable scalar type">; def err_attribute_argument_out_of_bounds : Error< "%0 attribute parameter %1 is out of bounds">; def err_attribute_only_once_per_parameter : Error< "%0 attribute can only be applied once per parameter">; def err_attribute_uuid_malformed_guid : Error< "uuid attribute contains a malformed GUID">; def warn_attribute_pointers_only : Warning< "%0 attribute only applies to%select{| constant}1 pointer arguments">, InGroup; def err_attribute_pointers_only : Error; def warn_attribute_return_pointers_only : Warning< "%0 attribute only applies to return values that are pointers">, InGroup; def warn_attribute_return_pointers_refs_only : Warning< "%0 attribute only applies to return values that are pointers or references">, InGroup; def warn_attribute_pointer_or_reference_only : Warning< "%0 attribute only applies to a pointer or reference (%1 is invalid)">, InGroup; def err_attribute_no_member_pointers : Error< "%0 attribute cannot be used with pointers to members">; def err_attribute_invalid_implicit_this_argument : Error< "%0 attribute is invalid for the implicit this argument">; def err_ownership_type : Error< "%0 attribute only applies to %select{pointer|integer}1 arguments">; def err_ownership_returns_index_mismatch : Error< "'ownership_returns' attribute index does not match; here it is %0">; def note_ownership_returns_index_mismatch : Note< "declared with index %0 here">; def err_format_strftime_third_parameter : Error< "strftime format attribute requires 3rd parameter to be 0">; def err_format_attribute_requires_variadic : Error< "format attribute requires variadic function">; def err_format_attribute_not : Error<"format argument not %0">; def err_format_attribute_result_not : Error<"function does not return %0">; def err_format_attribute_implicit_this_format_string : Error< "format attribute cannot specify the implicit this argument as the format " "string">; def err_init_method_bad_return_type : Error< "init methods must return an object pointer type, not %0">; def err_attribute_invalid_size : Error< "vector size not an integral multiple of component size">; def err_attribute_zero_size : Error<"zero vector size">; def err_attribute_size_too_large : Error<"vector size too large">; def err_typecheck_vector_not_convertable : Error< "cannot convert between vector values of different size (%0 and %1)">; def err_typecheck_vector_not_convertable_non_scalar : Error< "cannot convert between vector and non-scalar values (%0 and %1)">; def err_typecheck_vector_lengths_not_equal : Error< "vector operands do not have the same number of elements (%0 and %1)">; def err_ext_vector_component_exceeds_length : Error< "vector component access exceeds type %0">; def err_ext_vector_component_name_illegal : Error< "illegal vector component name '%0'">; def err_attribute_address_space_negative : Error< "address space is negative">; def err_attribute_address_space_too_high : Error< "address space is larger than the maximum supported (%0)">; def err_attribute_address_multiple_qualifiers : Error< "multiple address spaces specified for type">; def err_attribute_address_function_type : Error< "function type may not be qualified with an address space">; def err_as_qualified_auto_decl : Error< "automatic variable qualified with an address space">; def err_arg_with_address_space : Error< "parameter may not be qualified with an address space">; def err_field_with_address_space : Error< "field may not be qualified with an address space">; def err_attr_objc_ownership_redundant : Error< "the type %0 is already explicitly ownership-qualified">; def err_invalid_nsnumber_type : Error< "%0 is not a valid literal type for NSNumber">; def err_objc_illegal_boxed_expression_type : Error< "illegal type %0 used in a boxed expression">; def err_objc_non_trivially_copyable_boxed_expression_type : Error< "non-trivially copyable type %0 cannot be used in a boxed expression">; def err_objc_incomplete_boxed_expression_type : Error< "incomplete type %0 used in a boxed expression">; def err_undeclared_objc_literal_class : Error< "definition of class %0 must be available to use Objective-C " "%select{array literals|dictionary literals|numeric literals|boxed expressions|" "string literals}1">; def err_undeclared_boxing_method : Error< "declaration of %0 is missing in %1 class">; def err_objc_literal_method_sig : Error< "literal construction method %0 has incompatible signature">; def note_objc_literal_method_param : Note< "%select{first|second|third}0 parameter has unexpected type %1 " "(should be %2)">; def note_objc_literal_method_return : Note< "method returns unexpected type %0 (should be an object type)">; def err_invalid_collection_element : Error< "collection element of type %0 is not an Objective-C object">; def err_box_literal_collection : Error< "%select{string|character|boolean|numeric}0 literal must be prefixed by '@' " "in a collection">; def warn_objc_literal_comparison : Warning< "direct comparison of %select{an array literal|a dictionary literal|" "a numeric literal|a boxed expression|}0 has undefined behavior">, InGroup; def err_missing_atsign_prefix : Error< "string literal must be prefixed by '@' ">; def warn_objc_string_literal_comparison : Warning< "direct comparison of a string literal has undefined behavior">, InGroup; def warn_concatenated_nsarray_literal : Warning< "concatenated NSString literal for an NSArray expression - " "possibly missing a comma">, InGroup; def note_objc_literal_comparison_isequal : Note< "use 'isEqual:' instead">; def warn_objc_collection_literal_element : Warning< "object of type %0 is not compatible with " "%select{array element type|dictionary key type|dictionary value type}1 %2">, InGroup; def err_swift_param_attr_not_swiftcall : Error< "'%0' parameter can only be used with swiftcall calling convention">; def err_swift_indirect_result_not_first : Error< "'swift_indirect_result' parameters must be first parameters of function">; def err_swift_context_not_before_swift_error_result : Error< "'swift_context' parameter can only be followed by 'swift_error_result' " "parameter">; def err_swift_error_result_not_last : Error< "'swift_error_result' parameter must be last parameter of function">; def err_swift_error_result_not_after_swift_context : Error< "'swift_error_result' parameter must follow 'swift_context' parameter">; def err_swift_abi_parameter_wrong_type : Error< "'%0' parameter must have pointer%select{| to unqualified pointer}1 type; " "type here is %2">; def err_attribute_argument_is_zero : Error< "%0 attribute must be greater than 0">; def warn_attribute_argument_n_negative : Warning< "%0 attribute parameter %1 is negative and will be ignored">, InGroup; def err_property_function_in_objc_container : Error< "use of Objective-C property in function nested in Objective-C " "container not supported, move function outside its container">; let CategoryName = "Cocoa API Issue" in { def warn_objc_redundant_literal_use : Warning< "using %0 with a literal is redundant">, InGroup; } def err_attr_tlsmodel_arg : Error<"tls_model must be \"global-dynamic\", " "\"local-dynamic\", \"initial-exec\" or \"local-exec\"">; def err_tls_var_aligned_over_maximum : Error< "alignment (%0) of thread-local variable %1 is greater than the maximum supported " "alignment (%2) for a thread-local variable on this target">; def err_only_annotate_after_access_spec : Error< "access specifier can only have annotation attributes">; def err_attribute_section_invalid_for_target : Error< "argument to 'section' attribute is not valid for this target: %0">; def warn_mismatched_section : Warning< "section does not match previous declaration">, InGroup
; def err_anonymous_property: Error< "anonymous property is not supported">; def err_property_is_variably_modified : Error< "property %0 has a variably modified type">; def err_no_accessor_for_property : Error< "no %select{getter|setter}0 defined for property %1">; def error_cannot_find_suitable_accessor : Error< "cannot find suitable %select{getter|setter}0 for property %1">; def err_alignment_not_power_of_two : Error< "requested alignment is not a power of 2">; def err_alignment_dependent_typedef_name : Error< "requested alignment is dependent but declaration is not dependent">; def err_attribute_aligned_too_great : Error< "requested alignment must be %0 bytes or smaller">; def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning< "%q0 redeclared without %1 attribute: previous %1 ignored">, InGroup; def warn_redeclaration_without_import_attribute : Warning< "%q0 redeclared without 'dllimport' attribute: 'dllexport' attribute added">, InGroup; def warn_dllimport_dropped_from_inline_function : Warning< "%q0 redeclared inline; %1 attribute ignored">, InGroup; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup; def warn_attribute_ignored_on_inline : Warning<"%0 attribute ignored on inline function">, InGroup; def warn_attribute_after_definition_ignored : Warning< "attribute %0 after definition is ignored">, InGroup; def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup; def warn_cxx11_gnu_attribute_on_type : Warning< "attribute %0 ignored, because it cannot be applied to a type">, InGroup; def warn_unhandled_ms_attribute_ignored : Warning< "__declspec attribute %0 is not supported">, InGroup; def err_decl_attribute_invalid_on_stmt : Error< "%0 attribute cannot be applied to a statement">; def err_stmt_attribute_invalid_on_decl : Error< "%0 attribute cannot be applied to a declaration">; def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after " "\"%select{class|struct|interface|union|enum}1\" to apply attribute to " "type declaration">, InGroup; def warn_attribute_precede_definition : Warning< "attribute declaration must precede definition">, InGroup; def warn_attribute_void_function_method : Warning< "attribute %0 cannot be applied to " "%select{functions|Objective-C method}1 without return value">, InGroup; def warn_attribute_weak_on_field : Warning< "__weak attribute cannot be specified on a field declaration">, InGroup; def warn_gc_attribute_weak_on_local : Warning< "Objective-C GC does not allow weak variables on the stack">, InGroup; def warn_nsobject_attribute : Warning< "'NSObject' attribute may be put on a typedef only; attribute is ignored">, InGroup; def warn_independentclass_attribute : Warning< "'objc_independent_class' attribute may be put on a typedef only; " "attribute is ignored">, InGroup; def warn_ptr_independentclass_attribute : Warning< "'objc_independent_class' attribute may be put on Objective-C object " "pointer type only; attribute is ignored">, InGroup; def warn_attribute_weak_on_local : Warning< "__weak attribute cannot be specified on an automatic variable when ARC " "is not enabled">, InGroup; def warn_weak_identifier_undeclared : Warning< "weak identifier %0 never declared">; def err_attribute_weak_static : Error< "weak declaration cannot have internal linkage">; def err_attribute_selectany_non_extern_data : Error< "'selectany' can only be applied to data items with external linkage">; def err_declspec_thread_on_thread_variable : Error< "'__declspec(thread)' applied to variable that already has a " "thread-local storage specifier">; def err_attribute_dll_not_extern : Error< "%q0 must have external linkage when declared %q1">; def err_attribute_dll_thread_local : Error< "%q0 cannot be thread local when declared %q1">; def err_attribute_dll_lambda : Error< "lambda cannot be declared %0">; def warn_attribute_invalid_on_definition : Warning< "'%0' attribute cannot be specified on a definition">, InGroup; def err_attribute_dll_redeclaration : Error< "redeclaration of %q0 cannot add %q1 attribute">; def warn_attribute_dll_redeclaration : Warning< "redeclaration of %q0 should not add %q1 attribute">, InGroup>; def err_attribute_dllimport_function_definition : Error< "dllimport cannot be applied to non-inline function definition">; def err_attribute_dll_deleted : Error< "attribute %q0 cannot be applied to a deleted function">; def err_attribute_dllimport_data_definition : Error< "definition of dllimport data">; def err_attribute_dllimport_static_field_definition : Error< "definition of dllimport static field not allowed">; def warn_attribute_dllimport_static_field_definition : Warning< "definition of dllimport static field">, InGroup>; def warn_attribute_dllexport_explicit_instantiation_decl : Warning< "explicit instantiation declaration should not be 'dllexport'">, InGroup>; def warn_invalid_initializer_from_system_header : Warning< "invalid constructor form class in system header, should not be explicit">, InGroup>; def note_used_in_initialization_here : Note<"used in initialization here">; def err_attribute_dll_member_of_dll_class : Error< "attribute %q0 cannot be applied to member of %q1 class">; def warn_attribute_dll_instantiated_base_class : Warning< "propagating dll attribute to %select{already instantiated|explicitly specialized}0 " "base class template without dll attribute is not supported">, InGroup>, DefaultIgnore; def err_attribute_dll_ambiguous_default_ctor : Error< "'__declspec(dllexport)' cannot be applied to more than one default constructor in %0">; def err_attribute_weakref_not_static : Error< "weakref declaration must have internal linkage">; def err_attribute_weakref_not_global_context : Error< "weakref declaration of %0 must be in a global context">; def err_attribute_weakref_without_alias : Error< "weakref declaration of %0 must also have an alias attribute">; def err_alias_not_supported_on_darwin : Error < "only weak aliases are supported on darwin">; def err_alias_to_undefined : Error< "%select{alias|ifunc}0 must point to a defined %select{variable or |}1function">; def warn_alias_to_weak_alias : Warning< "%select{alias|ifunc}2 will always resolve to %0 even if weak definition of %1 is overridden">, InGroup; def warn_alias_with_section : Warning< "%select{alias|ifunc}1 will not be in section '%0' but in the same section as the %select{aliasee|resolver}2">, InGroup; def err_duplicate_mangled_name : Error< "definition with same mangled name as another definition">; def err_cyclic_alias : Error< "%select{alias|ifunc}0 definition is part of a cycle">; def err_ifunc_resolver_return : Error< "ifunc resolver function must return a pointer">; def err_ifunc_resolver_params : Error< "ifunc resolver function must have no parameters">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{functions|unions|" "variables and functions|" "functions, variables, and Objective-C interfaces|" "functions and methods|parameters|" "functions, methods and blocks|functions, methods, and classes|" "functions, methods, and parameters|classes|enums|variables|methods|" "fields and global variables|structs|parameters and typedefs|variables and typedefs|" "thread-local variables|variables and fields|variables, data members and tag types|" "types and namespaces|Objective-C interfaces|methods and properties|" "struct or union|struct, union or class|types|" "Objective-C instance methods|init methods of interface or class extension declarations|" "variables, functions and classes|" "functions, variables, classes, and Objective-C interfaces|" "Objective-C protocols|" "functions and global variables|structs, unions, and typedefs|structs and typedefs|" "interface or protocol declarations|kernel functions|non-K&R-style functions|" "variables, enums, fields and typedefs|functions, methods, enums, and classes|" "structs, classes, variables, functions, and inline namespaces|" "variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, InGroup; def warn_incomplete_encoded_type : Warning< "encoding of %0 type is incomplete because %1 component has unknown encoding">, InGroup>; def warn_gnu_inline_attribute_requires_inline : Warning< "'gnu_inline' attribute requires function to be marked 'inline'," " attribute ignored">, InGroup; def err_attribute_vecreturn_only_vector_member : Error< "the vecreturn attribute can only be used on a class or structure with one member, which must be a vector">; def err_attribute_vecreturn_only_pod_record : Error< "the vecreturn attribute can only be used on a POD (plain old data) class or structure (i.e. no virtual functions)">; def err_cconv_change : Error< "function declared '%0' here was previously declared " "%select{'%2'|without calling convention}1">; def warn_cconv_ignored : Warning< "calling convention %0 ignored for this target">, InGroup; def err_cconv_knr : Error< "function with no prototype cannot use the %0 calling convention">; def warn_cconv_knr : Warning< err_cconv_knr.Text>, InGroup>; def err_cconv_varargs : Error< "variadic function cannot use %0 calling convention">; def warn_cconv_varargs : Warning< "%0 calling convention ignored on variadic function">, InGroup; def warn_cconv_structors : Warning< "%0 calling convention ignored on constructor/destructor">, InGroup; def err_regparm_mismatch : Error<"function declared with regparm(%0) " "attribute was previously declared " "%plural{0:without the regparm|:with the regparm(%1)}1 attribute">; def err_returns_retained_mismatch : Error< "function declared with the ns_returns_retained attribute " "was previously declared without the ns_returns_retained attribute">; def err_objc_precise_lifetime_bad_type : Error< "objc_precise_lifetime only applies to retainable types; type here is %0">; def warn_objc_precise_lifetime_meaningless : Error< "objc_precise_lifetime is not meaningful for " "%select{__unsafe_unretained|__autoreleasing}0 objects">; def err_invalid_pcs : Error<"invalid PCS type">; def warn_attribute_not_on_decl : Warning< "%0 attribute ignored when parsing type">, InGroup; def err_base_specifier_attribute : Error< "%0 attribute cannot be applied to a base specifier">; def err_invalid_attribute_on_virtual_function : Error< "%0 attribute cannot be applied to virtual functions">; // Availability attribute def warn_availability_unknown_platform : Warning< "unknown platform %0 in availability macro">, InGroup; def warn_availability_version_ordering : Warning< "feature cannot be %select{introduced|deprecated|obsoleted}0 in %1 version " "%2 before it was %select{introduced|deprecated|obsoleted}3 in version %4; " "attribute ignored">, InGroup; def warn_mismatched_availability: Warning< "availability does not match previous declaration">, InGroup; def warn_mismatched_availability_override : Warning< "%select{|overriding }4method %select{introduced after|" "deprecated before|obsoleted before}0 " "%select{the protocol method it implements|overridden method}4 " "on %1 (%2 vs. %3)">, InGroup; def warn_mismatched_availability_override_unavail : Warning< "%select{|overriding }1method cannot be unavailable on %0 when " "%select{the protocol method it implements|its overridden method}1 is " "available">, InGroup; def note_overridden_method : Note< "overridden method is here">; def note_protocol_method : Note< "protocol method is here">; def warn_available_using_star_case : Warning< "using '*' case here, platform %0 is not accounted for">, InGroup; // Thread Safety Attributes def warn_invalid_capability_name : Warning< "invalid capability name '%0'; capability name must be 'mutex' or 'role'">, InGroup, DefaultIgnore; def warn_thread_attribute_ignored : Warning< "ignoring %0 attribute because its argument is invalid">, InGroup, DefaultIgnore; def warn_thread_attribute_argument_not_lockable : Warning< "%0 attribute requires arguments whose type is annotated " "with 'capability' attribute; type here is %1">, InGroup, DefaultIgnore; def warn_thread_attribute_decl_not_lockable : Warning< "%0 attribute can only be applied in a context annotated " "with 'capability(\"mutex\")' attribute">, InGroup, DefaultIgnore; def warn_thread_attribute_decl_not_pointer : Warning< "%0 only applies to pointer types; type here is %1">, InGroup, DefaultIgnore; def err_attribute_argument_out_of_range : Error< "%0 attribute parameter %1 is out of bounds: " "%plural{0:no parameters to index into|" "1:can only be 1, since there is one parameter|" ":must be between 1 and %2}2">; // Thread Safety Analysis def warn_unlock_but_no_lock : Warning<"releasing %0 '%1' that was not held">, InGroup, DefaultIgnore; def warn_unlock_kind_mismatch : Warning< "releasing %0 '%1' using %select{shared|exclusive}2 access, expected " "%select{shared|exclusive}3 access">, InGroup, DefaultIgnore; def warn_double_lock : Warning<"acquiring %0 '%1' that is already held">, InGroup, DefaultIgnore; def warn_no_unlock : Warning< "%0 '%1' is still held at the end of function">, InGroup, DefaultIgnore; def warn_expecting_locked : Warning< "expecting %0 '%1' to be held at the end of function">, InGroup, DefaultIgnore; // FIXME: improve the error message about locks not in scope def warn_lock_some_predecessors : Warning< "%0 '%1' is not held on every path through here">, InGroup, DefaultIgnore; def warn_expecting_lock_held_on_loop : Warning< "expecting %0 '%1' to be held at start of each loop">, InGroup, DefaultIgnore; def note_locked_here : Note<"%0 acquired here">; def warn_lock_exclusive_and_shared : Warning< "%0 '%1' is acquired exclusively and shared in the same scope">, InGroup, DefaultIgnore; def note_lock_exclusive_and_shared : Note< "the other acquisition of %0 '%1' is here">; def warn_variable_requires_any_lock : Warning< "%select{reading|writing}1 variable '%0' requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup, DefaultIgnore; def warn_var_deref_requires_any_lock : Warning< "%select{reading|writing}1 the value pointed to by '%0' requires holding " "%select{any mutex|any mutex exclusively}1">, InGroup, DefaultIgnore; def warn_fun_excludes_mutex : Warning< "cannot call function '%1' while %0 '%2' is held">, InGroup, DefaultIgnore; def warn_cannot_resolve_lock : Warning< "cannot resolve lock expression">, InGroup, DefaultIgnore; def warn_acquired_before : Warning< "%0 '%1' must be acquired before '%2'">, InGroup, DefaultIgnore; def warn_acquired_before_after_cycle : Warning< "Cycle in acquired_before/after dependencies, starting with '%0'">, InGroup, DefaultIgnore; // Thread safety warnings negative capabilities def warn_acquire_requires_negative_cap : Warning< "acquiring %0 '%1' requires negative capability '%2'">, InGroup, DefaultIgnore; // Thread safety warnings on pass by reference def warn_guarded_pass_by_reference : Warning< "passing variable '%1' by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_pt_guarded_pass_by_reference : Warning< "passing the value that '%1' points to by reference requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; // Imprecise thread safety warnings def warn_variable_requires_lock : Warning< "%select{reading|writing}3 variable '%1' requires holding %0 " "%select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_var_deref_requires_lock : Warning< "%select{reading|writing}3 the value pointed to by '%1' requires " "holding %0 %select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; def warn_fun_requires_lock : Warning< "calling function '%1' requires holding %0 %select{'%2'|'%2' exclusively}3">, InGroup, DefaultIgnore; // Precise thread safety warnings def warn_variable_requires_lock_precise : Warning, InGroup, DefaultIgnore; def warn_var_deref_requires_lock_precise : Warning, InGroup, DefaultIgnore; def warn_fun_requires_lock_precise : Warning, InGroup, DefaultIgnore; def note_found_mutex_near_match : Note<"found near match '%0'">; // Verbose thread safety warnings def warn_thread_safety_verbose : Warning<"Thread safety verbose warning.">, InGroup, DefaultIgnore; def note_thread_warning_in_fun : Note<"Thread warning in function '%0'">; def note_guarded_by_declared_here : Note<"Guarded_by declared here.">; // Dummy warning that will trigger "beta" warnings from the analysis if enabled. def warn_thread_safety_beta : Warning<"Thread safety beta warning.">, InGroup, DefaultIgnore; // Consumed warnings def warn_use_in_invalid_state : Warning< "invalid invocation of method '%0' on object '%1' while it is in the '%2' " "state">, InGroup, DefaultIgnore; def warn_use_of_temp_in_invalid_state : Warning< "invalid invocation of method '%0' on a temporary object while it is in the " "'%1' state">, InGroup, DefaultIgnore; def warn_attr_on_unconsumable_class : Warning< "consumed analysis attribute is attached to member of class '%0' which isn't " "marked as consumable">, InGroup, DefaultIgnore; def warn_return_typestate_for_unconsumable_type : Warning< "return state set for an unconsumable type '%0'">, InGroup, DefaultIgnore; def warn_return_typestate_mismatch : Warning< "return value not in expected state; expected '%0', observed '%1'">, InGroup, DefaultIgnore; def warn_loop_state_mismatch : Warning< "state of variable '%0' must match at the entry and exit of loop">, InGroup, DefaultIgnore; def warn_param_return_typestate_mismatch : Warning< "parameter '%0' not in expected state when the function returns: expected " "'%1', observed '%2'">, InGroup, DefaultIgnore; def warn_param_typestate_mismatch : Warning< "argument not in expected state; expected '%0', observed '%1'">, InGroup, DefaultIgnore; // no_sanitize attribute def warn_unknown_sanitizer_ignored : Warning< "unknown sanitizer '%0' ignored">, InGroup; def warn_impcast_vector_scalar : Warning< "implicit conversion turns vector to scalar: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_complex_scalar : Warning< "implicit conversion discards imaginary component: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_float_precision : Warning< "implicit conversion loses floating-point precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_double_promotion : Warning< "implicit conversion increases floating-point precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_sign : Warning< "implicit conversion changes signedness: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_sign_conditional : Warning< "operand of ? changes signedness: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_precision : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_64_32 : Warning< "implicit conversion loses integer precision: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_integer_precision_constant : Warning< "implicit conversion from %2 to %3 changes value from %0 to %1">, InGroup; def warn_impcast_bitfield_precision_constant : Warning< "implicit truncation from %2 to bitfield changes value from %0 to %1">, InGroup; def warn_impcast_literal_float_to_integer : Warning< "implicit conversion from %0 to %1 changes value from %2 to %3">, InGroup; def warn_impcast_float_integer : Warning< "implicit conversion turns floating-point number into integer: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_float_to_integer : Warning< "implicit conversion of out of range value from %0 to %1 changes value " "from %2 to %3">, InGroup, DefaultIgnore; def warn_impcast_float_to_integer_zero : Warning< "implicit conversion from %0 to %1 changes non-zero value from %2 to %3">, InGroup, DefaultIgnore; def warn_impcast_string_literal_to_bool : Warning< "implicit conversion turns string literal into bool: %0 to %1">, InGroup, DefaultIgnore; def warn_impcast_different_enum_types : Warning< "implicit conversion from enumeration type %0 to different enumeration type " "%1">, InGroup; def warn_impcast_bool_to_null_pointer : Warning< "initialization of pointer of type %0 to null from a constant boolean " "expression">, InGroup; def warn_non_literal_null_pointer : Warning< "expression which evaluates to zero treated as a null pointer constant of " "type %0">, InGroup; def warn_impcast_null_pointer_to_integer : Warning< "implicit conversion of %select{NULL|nullptr}0 constant to %1">, InGroup; def warn_impcast_floating_point_to_bool : Warning< "implicit conversion turns floating-point number into bool: %0 to %1">, InGroup; def ext_ms_impcast_fn_obj : ExtWarn< "implicit conversion between pointer-to-function and pointer-to-object is a " "Microsoft extension">, InGroup; def warn_impcast_pointer_to_bool : Warning< "address of%select{| function| array}0 '%1' will always evaluate to " "'true'">, InGroup; def warn_cast_nonnull_to_bool : Warning< "nonnull %select{function call|parameter}0 '%1' will evaluate to " "'true' on first encounter">, InGroup; def warn_this_bool_conversion : Warning< "'this' pointer cannot be null in well-defined C++ code; pointer may be " "assumed to always convert to true">, InGroup; def warn_address_of_reference_bool_conversion : Warning< "reference cannot be bound to dereferenced null pointer in well-defined C++ " "code; pointer may be assumed to always convert to true">, InGroup; def warn_null_pointer_compare : Warning< "comparison of %select{address of|function|array}0 '%1' %select{not |}2" "equal to a null pointer is always %select{true|false}2">, InGroup; def warn_nonnull_expr_compare : Warning< "comparison of nonnull %select{function call|parameter}0 '%1' " "%select{not |}2equal to a null pointer is '%select{true|false}2' on first " "encounter">, InGroup; def warn_this_null_compare : Warning< "'this' pointer cannot be null in well-defined C++ code; comparison may be " "assumed to always evaluate to %select{true|false}0">, InGroup; def warn_address_of_reference_null_compare : Warning< "reference cannot be bound to dereferenced null pointer in well-defined C++ " "code; comparison may be assumed to always evaluate to " "%select{true|false}0">, InGroup; def note_reference_is_return_value : Note<"%0 returns a reference">; def note_function_warning_silence : Note< "prefix with the address-of operator to silence this warning">; def note_function_to_function_call : Note< "suffix with parentheses to turn this into a function call">; def warn_impcast_objective_c_literal_to_bool : Warning< "implicit boolean conversion of Objective-C object literal always " "evaluates to true">, InGroup; def warn_cast_align : Warning< "cast from %0 to %1 increases required alignment from %2 to %3">, InGroup, DefaultIgnore; def warn_old_style_cast : Warning< "use of old-style cast">, InGroup, DefaultIgnore; // Separate between casts to void* and non-void* pointers. // Some APIs use (abuse) void* for something like a user context, // and often that value is an integer even if it isn't a pointer itself. // Having a separate warning flag allows users to control the warning // for their workflow. def warn_int_to_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; def warn_int_to_void_pointer_cast : Warning< "cast to %1 from smaller integer type %0">, InGroup; def warn_attribute_packed_for_bitfield : Warning< "'packed' attribute was ignored on bit-fields with single-byte alignment " "in older versions of GCC and Clang">, InGroup>; def warn_transparent_union_attribute_field_size_align : Warning< "%select{alignment|size}0 of field %1 (%2 bits) does not match the " "%select{alignment|size}0 of the first field in transparent union; " "transparent_union attribute ignored">, InGroup; def note_transparent_union_first_field_size_align : Note< "%select{alignment|size}0 of first field is %1 bits">; def warn_transparent_union_attribute_not_definition : Warning< "transparent_union attribute can only be applied to a union definition; " "attribute ignored">, InGroup; def warn_transparent_union_attribute_floating : Warning< "first field of a transparent union cannot have %select{floating point|" "vector}0 type %1; transparent_union attribute ignored">, InGroup; def warn_transparent_union_attribute_zero_fields : Warning< "transparent union definition must contain at least one field; " "transparent_union attribute ignored">, InGroup; def warn_attribute_type_not_supported : Warning< "%0 attribute argument not supported: %1">, InGroup; def warn_attribute_unknown_visibility : Warning<"unknown visibility %0">, InGroup; def warn_attribute_protected_visibility : Warning<"target does not support 'protected' visibility; using 'default'">, InGroup>; def err_mismatched_visibility: Error<"visibility does not match previous declaration">; def note_previous_attribute : Note<"previous attribute is here">; def note_conflicting_attribute : Note<"conflicting attribute is here">; def note_attribute : Note<"attribute is here">; def err_mismatched_ms_inheritance : Error< "inheritance model does not match %select{definition|previous declaration}0">; def warn_ignored_ms_inheritance : Warning< "inheritance model ignored on %select{primary template|partial specialization}0">, InGroup; def note_previous_ms_inheritance : Note< "previous inheritance model specified here">; def err_machine_mode : Error<"%select{unknown|unsupported}0 machine mode %1">; def err_mode_not_primitive : Error< "mode attribute only supported for integer and floating-point types">; def err_mode_wrong_type : Error< "type of machine mode does not match type of base type">; def warn_vector_mode_deprecated : Warning< "specifying vector types with the 'mode' attribute is deprecated; " "use the 'vector_size' attribute instead">, InGroup; def err_complex_mode_vector_type : Error< "type of machine mode does not support base vector types">; def err_enum_mode_vector_type : Error< "mode %0 is not supported for enumeration types">; def warn_attribute_nonnull_no_pointers : Warning< "'nonnull' attribute applied to function with no pointer arguments">, InGroup; def warn_attribute_nonnull_parm_no_args : Warning< "'nonnull' attribute when used on parameters takes no arguments">, InGroup; def note_declared_nonnull : Note< "declared %select{'returns_nonnull'|'nonnull'}0 here">; def warn_attribute_sentinel_named_arguments : Warning< "'sentinel' attribute requires named arguments">, InGroup; def warn_attribute_sentinel_not_variadic : Warning< "'sentinel' attribute only supported for variadic %select{functions|blocks}0">, InGroup; def err_attribute_sentinel_less_than_zero : Error< "'sentinel' parameter 1 less than zero">; def err_attribute_sentinel_not_zero_or_one : Error< "'sentinel' parameter 2 not 0 or 1">; def warn_cleanup_ext : Warning< "GCC does not allow the 'cleanup' attribute argument to be anything other " "than a simple identifier">, InGroup; def err_attribute_cleanup_arg_not_function : Error< "'cleanup' argument %select{|%1 |%1 }0is not a %select{||single }0function">; def err_attribute_cleanup_func_must_take_one_arg : Error< "'cleanup' function %0 must take 1 parameter">; def err_attribute_cleanup_func_arg_incompatible_type : Error< "'cleanup' function %0 parameter has " "%diff{type $ which is incompatible with type $|incompatible type}1,2">; def err_attribute_regparm_wrong_platform : Error< "'regparm' is not valid on this platform">; def err_attribute_regparm_invalid_number : Error< "'regparm' parameter must be between 0 and %0 inclusive">; def err_attribute_not_supported_in_lang : Error< "%0 attribute is not supported in %select{C|C++|Objective-C}1">; // Clang-Specific Attributes def warn_attribute_iboutlet : Warning< "%0 attribute can only be applied to instance variables or properties">, InGroup; def err_iboutletcollection_type : Error< "invalid type %0 as argument of iboutletcollection attribute">; def err_iboutletcollection_builtintype : Error< "type argument of iboutletcollection attribute cannot be a builtin type">; def warn_iboutlet_object_type : Warning< "%select{instance variable|property}2 with %0 attribute must " "be an object type (invalid %1)">, InGroup; def warn_iboutletcollection_property_assign : Warning< "IBOutletCollection properties should be copy/strong and not assign">, InGroup; def err_attribute_overloadable_missing : Error< "%select{overloaded function|redeclaration of}0 %1 must have the " "'overloadable' attribute">; def note_attribute_overloadable_prev_overload : Note< "previous overload of function is here">; def err_attribute_overloadable_no_prototype : Error< "'overloadable' function %0 must have a prototype">; def warn_ns_attribute_wrong_return_type : Warning< "%0 attribute only applies to %select{functions|methods|properties}1 that " "return %select{an Objective-C object|a pointer|a non-retainable pointer}2">, InGroup; def err_ns_attribute_wrong_parameter_type : Error< "%0 attribute only applies to " "%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">; def warn_ns_attribute_wrong_parameter_type : Warning< "%0 attribute only applies to " "%select{Objective-C object|pointer|pointer-to-CF-pointer}1 parameters">, InGroup; def warn_objc_requires_super_protocol : Warning< "%0 attribute cannot be applied to %select{methods in protocols|dealloc}1">, InGroup>; def note_protocol_decl : Note< "protocol is declared here">; def note_protocol_decl_undefined : Note< "protocol %0 has no definition">; // objc_designated_initializer attribute diagnostics. def warn_objc_designated_init_missing_super_call : Warning< "designated initializer missing a 'super' call to a designated initializer of the super class">, InGroup; def note_objc_designated_init_marked_here : Note< "method marked as designated initializer of the class here">; def warn_objc_designated_init_non_super_designated_init_call : Warning< "designated initializer should only invoke a designated initializer on 'super'">, InGroup; def warn_objc_designated_init_non_designated_init_call : Warning< "designated initializer invoked a non-designated initializer">, InGroup; def warn_objc_secondary_init_super_init_call : Warning< "convenience initializer should not invoke an initializer on 'super'">, InGroup; def warn_objc_secondary_init_missing_init_call : Warning< "convenience initializer missing a 'self' call to another initializer">, InGroup; def warn_objc_implementation_missing_designated_init_override : Warning< "method override for the designated initializer of the superclass %objcinstance0 not found">, InGroup; // objc_bridge attribute diagnostics. def err_objc_attr_not_id : Error< "parameter of %0 attribute must be a single name of an Objective-C %select{class|protocol}1">; def err_objc_attr_typedef_not_id : Error< "parameter of %0 attribute must be 'id' when used on a typedef">; def err_objc_attr_typedef_not_void_pointer : Error< "'objc_bridge(id)' is only allowed on structs and typedefs of void pointers">; def err_objc_cf_bridged_not_interface : Error< "CF object of type %0 is bridged to %1, which is not an Objective-C class">; def err_objc_ns_bridged_invalid_cfobject : Error< "ObjectiveC object of type %0 is bridged to %1, which is not valid CF object">; def warn_objc_invalid_bridge : Warning< "%0 bridges to %1, not %2">, InGroup; def warn_objc_invalid_bridge_to_cf : Warning< "%0 cannot bridge to %1">, InGroup; // objc_bridge_related attribute diagnostics. def err_objc_bridged_related_invalid_class : Error< "could not find Objective-C class %0 to convert %1 to %2">; def err_objc_bridged_related_invalid_class_name : Error< "%0 must be name of an Objective-C class to be able to convert %1 to %2">; def err_objc_bridged_related_known_method : Error< "%0 must be explicitly converted to %1; use %select{%objcclass2|%objcinstance2}3 " "method for this conversion">; def err_objc_attr_protocol_requires_definition : Error< "attribute %0 can only be applied to @protocol definitions, not forward declarations">; // Function Parameter Semantic Analysis. def err_param_with_void_type : Error<"argument may not have 'void' type">; def err_void_only_param : Error< "'void' must be the first and only parameter if specified">; def err_void_param_qualified : Error< "'void' as parameter must not have type qualifiers">; def err_ident_list_in_fn_declaration : Error< "a parameter list without types is only allowed in a function definition">; def ext_param_not_declared : Extension< "parameter %0 was not declared, defaulting to type 'int'">; def err_param_default_argument : Error< "C does not support default arguments">; def err_param_default_argument_redefinition : Error< "redefinition of default argument">; def ext_param_default_argument_redefinition : ExtWarn< err_param_default_argument_redefinition.Text>, InGroup; def err_param_default_argument_missing : Error< "missing default argument on parameter">; def err_param_default_argument_missing_name : Error< "missing default argument on parameter %0">; def err_param_default_argument_references_param : Error< "default argument references parameter %0">; def err_param_default_argument_references_local : Error< "default argument references local variable %0 of enclosing function">; def err_param_default_argument_references_this : Error< "default argument references 'this'">; def err_param_default_argument_nonfunc : Error< "default arguments can only be specified for parameters in a function " "declaration">; def err_param_default_argument_template_redecl : Error< "default arguments cannot be added to a function template that has already " "been declared">; def err_param_default_argument_member_template_redecl : Error< "default arguments cannot be added to an out-of-line definition of a member " "of a %select{class template|class template partial specialization|nested " "class in a template}0">; def err_param_default_argument_on_parameter_pack : Error< "parameter pack cannot have a default argument">; def err_uninitialized_member_for_assign : Error< "cannot define the implicit copy assignment operator for %0, because " "non-static %select{reference|const}1 member %2 cannot use copy " "assignment operator">; def err_uninitialized_member_in_ctor : Error< "%select{constructor for %1|" "implicit default constructor for %1|" "cannot use constructor inherited from %1:}0 must explicitly " "initialize the %select{reference|const}2 member %3">; def err_default_arg_makes_ctor_special : Error< "addition of default argument on redeclaration makes this constructor a " "%select{default|copy|move}0 constructor">; def err_use_of_default_argument_to_function_declared_later : Error< "use of default argument to function %0 that is declared later in class %1">; def note_default_argument_declared_here : Note< "default argument declared here">; def err_recursive_default_argument : Error<"recursive evaluation of default argument">; def ext_param_promoted_not_compatible_with_prototype : ExtWarn< "%diff{promoted type $ of K&R function parameter is not compatible with the " "parameter type $|promoted type of K&R function parameter is not compatible " "with parameter type}0,1 declared in a previous prototype">, InGroup; // C++ Overloading Semantic Analysis. def err_ovl_diff_return_type : Error< "functions that differ only in their return type cannot be overloaded">; def err_ovl_static_nonstatic_member : Error< "static and non-static member functions with the same parameter types " "cannot be overloaded">; def err_ovl_no_viable_function_in_call : Error< "no matching function for call to %0">; def err_ovl_no_viable_member_function_in_call : Error< "no matching member function for call to %0">; def err_ovl_ambiguous_call : Error< "call to %0 is ambiguous">; def err_ovl_deleted_call : Error< "call to %select{unavailable|deleted}0 function %1%2">; def err_ovl_ambiguous_member_call : Error< "call to member function %0 is ambiguous">; def err_ovl_deleted_member_call : Error< "call to %select{unavailable|deleted}0 member function %1%2">; def note_ovl_too_many_candidates : Note< "remaining %0 candidate%s0 omitted; " "pass -fshow-overloads=all to show them">; def note_ovl_candidate : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "is the implicit default constructor|" "is the implicit copy constructor|" "is the implicit move constructor|" "is the implicit copy assignment operator|" "is the implicit move assignment operator|" "inherited constructor|" "inherited constructor }0%1" "%select{| has different class%diff{ (expected $ but has $)|}3,4" "| has different number of parameters (expected %3 but has %4)" "| has type mismatch at %ordinal3 parameter" "%diff{ (expected $ but has $)|}4,5" "| has different return type%diff{ ($ expected but has $)|}3,4" "| has different qualifiers (expected " "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}3 but found " "%select{none|const|restrict|const and restrict|volatile|const and volatile" "|volatile and restrict|const, volatile, and restrict}4)}2">; def note_ovl_candidate_inherited_constructor : Note< "constructor from base class %0 inherited here">; def note_ovl_candidate_illegal_constructor : Note< "candidate %select{constructor|template}0 ignored: " "instantiation %select{takes|would take}0 its own class type by value">; def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; def note_ovl_candidate_inconsistent_deduction : Note< "candidate template ignored: deduced conflicting %select{types|values|" "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">; def note_ovl_candidate_explicit_arg_mismatch_named : Note< "candidate template ignored: invalid explicitly-specified argument " "for template parameter %0">; def note_ovl_candidate_explicit_arg_mismatch_unnamed : Note< "candidate template ignored: invalid explicitly-specified argument " "for %ordinal0 template parameter">; def note_ovl_candidate_instantiation_depth : Note< "candidate template ignored: substitution exceeded maximum template " "instantiation depth">; def note_ovl_candidate_underqualified : Note< "candidate template ignored: cannot deduce a type for %0 that would " "make %2 equal %1">; def note_ovl_candidate_substitution_failure : Note< "candidate template ignored: substitution failure%0%1">; def note_ovl_candidate_disabled_by_enable_if : Note< "candidate template ignored: disabled by %0%1">; def note_ovl_candidate_has_pass_object_size_params: Note< "candidate address cannot be taken because parameter %0 has " "pass_object_size attribute">; def note_ovl_candidate_disabled_by_enable_if_attr : Note< "candidate disabled: %0">; def err_addrof_function_disabled_by_enable_if_attr : Error< "cannot take address of function %0 becuase it has one or more " "non-tautological enable_if conditions">; def note_addrof_ovl_candidate_disabled_by_enable_if_attr : Note< "candidate function made ineligible by enable_if">; def note_ovl_candidate_failed_overload_resolution : Note< "candidate template ignored: couldn't resolve reference to overloaded " "function %0">; def note_ovl_candidate_deduced_mismatch : Note< "candidate template ignored: deduced type " "%diff{$ of %ordinal0 parameter does not match adjusted type $ of argument" "|of %ordinal0 parameter does not match adjusted type of argument}1,2%3">; def note_ovl_candidate_non_deduced_mismatch : Note< "candidate template ignored: could not match %diff{$ against $|types}0,1">; // This note is needed because the above note would sometimes print two // different types with the same name. Remove this note when the above note // can handle that case properly. def note_ovl_candidate_non_deduced_mismatch_qualified : Note< "candidate template ignored: could not match %q0 against %q1">; // Note that we don't treat templates differently for this diagnostic. def note_ovl_candidate_arity : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor}0 %select{|template }1" "not viable: requires%select{ at least| at most|}2 %3 argument%s3, but %4 " "%plural{1:was|:were}4 provided">; def note_ovl_candidate_arity_one : Note<"candidate " "%select{function|function|constructor|function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor}0 %select{|template }1not viable: " "%select{requires at least|allows at most single|requires single}2 " "argument %3, but %plural{0:no|:%4}4 arguments were provided">; def note_ovl_candidate_deleted : Note< "candidate %select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 has been " "%select{explicitly made unavailable|explicitly deleted|" "implicitly deleted}2">; // Giving the index of the bad argument really clutters this message, and // it's relatively unimportant because 1) it's generally obvious which // argument(s) are of the given object type and 2) the fix is usually // to complete the type, which doesn't involve changes to the call line // anyway. If people complain, we can change it. def note_ovl_candidate_bad_conv_incomplete : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 " "not viable: cannot convert argument of incomplete type " "%diff{$ to $|to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" "%select{|; dereference the argument with *|" "; take the address of the argument with &|" "; remove *|" "; remove &}6">; def note_ovl_candidate_bad_list_argument : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 " "not viable: cannot convert initializer list argument to %3">; def note_ovl_candidate_bad_overload : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1" " not viable: no overload of %3 matching %2 for %ordinal4 argument">; def note_ovl_candidate_bad_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1" " not viable: no known conversion " "%diff{from $ to $|from argument type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4" "%select{|; dereference the argument with *|" "; take the address of the argument with &|" "; remove *|" "; remove &}6">; def note_ovl_candidate_bad_arc_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1" " not viable: cannot implicitly convert argument " "%diff{of type $ to $|type to parameter type}2,3 for " "%select{%ordinal5 argument|object argument}4 under ARC">; def note_ovl_candidate_bad_lvalue : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1" " not viable: expects an l-value for " "%select{%ordinal3 argument|object argument}2">; def note_ovl_candidate_bad_addrspace : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) is in " "address space %3, but parameter must be in address space %4">; def note_ovl_candidate_bad_gc : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has %select{no|__weak|__strong}3 " "ownership, but parameter has %select{no|__weak|__strong}4 ownership">; def note_ovl_candidate_bad_ownership : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "%select{%ordinal6|'this'}5 argument (%2) has " "%select{no|__unsafe_unretained|__strong|__weak|__autoreleasing}3 ownership," " but parameter has %select{no|__unsafe_unretained|__strong|__weak|" "__autoreleasing}4 ownership">; def note_ovl_candidate_bad_cvr_this : Note<"candidate " "%select{|function|||function|||||" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)||}0 not viable: " "'this' argument has type %2, but method is not marked " "%select{const|restrict|const or restrict|volatile|const or volatile|" "volatile or restrict|const, volatile, or restrict}3">; def note_ovl_candidate_bad_cvr : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "%ordinal4 argument (%2) would lose " "%select{const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3 qualifier" "%select{||s||s|s|s}3">; def note_ovl_candidate_bad_unaligned : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "%ordinal4 argument (%2) would lose __unaligned qualifier">; def note_ovl_candidate_bad_base_to_derived_conv : Note<"candidate " "%select{function|function|constructor|" "function |function |constructor |" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor }0%1 not viable: " "cannot %select{convert from|convert from|bind}2 " "%select{base class pointer|superclass|base class object of type}2 %3 to " "%select{derived class pointer|subclass|derived class reference}2 %4 for " "%ordinal5 argument">; def note_ovl_candidate_bad_target : Note< "candidate %select{function|function|constructor|" "function|function|constructor|" "constructor (the implicit default constructor)|" "constructor (the implicit copy constructor)|" "constructor (the implicit move constructor)|" "function (the implicit copy assignment operator)|" "function (the implicit move assignment operator)|" "inherited constructor|" "inherited constructor}0 not viable: " "call to " "%select{__device__|__global__|__host__|__host__ __device__|invalid}1 function from" " %select{__device__|__global__|__host__|__host__ __device__|invalid}2 function">; def note_implicit_member_target_infer_collision : Note< "implicit %select{" "default constructor|" "copy constructor|" "move constructor|" "copy assignment operator|" "move assignment operator|" "destructor}0 inferred target collision: call to both " "%select{__device__|__global__|__host__|__host__ __device__}1 and " "%select{__device__|__global__|__host__|__host__ __device__}2 members">; def note_ambiguous_type_conversion: Note< "because of ambiguity in conversion %diff{of $ to $|between types}0,1">; def note_ovl_builtin_binary_candidate : Note< "built-in candidate %0">; def note_ovl_builtin_unary_candidate : Note< "built-in candidate %0">; def err_ovl_no_viable_function_in_init : Error< "no matching constructor for initialization of %0">; def err_ovl_no_conversion_in_cast : Error< "cannot convert %1 to %2 without a conversion operator">; def err_ovl_no_viable_conversion_in_cast : Error< "no matching conversion for %select{|static_cast|reinterpret_cast|" "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; def err_ovl_ambiguous_conversion_in_cast : Error< "ambiguous conversion for %select{|static_cast|reinterpret_cast|" "dynamic_cast|C-style cast|functional-style cast}0 from %1 to %2">; def err_ovl_deleted_conversion_in_cast : Error< "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 uses deleted function">; def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; def err_ref_init_ambiguous : Error< "reference initialization of type %0 with initializer of type %1 is ambiguous">; def err_ovl_deleted_init : Error< "call to %select{unavailable|deleted}0 constructor of %1">; def err_ovl_deleted_special_init : Error< "call to implicitly-deleted %select{default constructor|copy constructor|" "move constructor|copy assignment operator|move assignment operator|" "destructor|function}0 of %1">; def err_ovl_ambiguous_oper_unary : Error< "use of overloaded operator '%0' is ambiguous (operand type %1)">; def err_ovl_ambiguous_oper_binary : Error< "use of overloaded operator '%0' is ambiguous (with operand types %1 and %2)">; def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; def note_assign_lhs_incomplete : Note<"type %0 is incomplete">; def err_ovl_deleted_oper : Error< "overload resolution selected %select{unavailable|deleted}0 operator '%1'%2">; def err_ovl_deleted_special_oper : Error< "object of type %0 cannot be %select{constructed|copied|moved|assigned|" "assigned|destroyed}1 because its %select{default constructor|" "copy constructor|move constructor|copy assignment operator|" "move assignment operator|destructor}1 is implicitly deleted">; def err_ovl_no_viable_subscript : Error<"no viable overloaded operator[] for type %0">; def err_ovl_no_oper : Error<"type %0 does not provide a %select{subscript|call}1 operator">; def err_ovl_unresolvable : Error< "reference to overloaded function could not be resolved; " "did you mean to call it%select{| with no arguments}0?">; def err_bound_member_function : Error< "reference to non-static member function must be called" "%select{|; did you mean to call it with no arguments?}0">; def note_possible_target_of_call : Note<"possible target for call">; def err_ovl_no_viable_object_call : Error< "no matching function for call to object of type %0">; def err_ovl_ambiguous_object_call : Error< "call to object of type %0 is ambiguous">; def err_ovl_deleted_object_call : Error< "call to %select{unavailable|deleted}0 function call operator in type %1%2">; def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to non-static member function without an object argument">; // C++ Address of Overloaded Function def err_addr_ovl_no_viable : Error< "address of overloaded function %0 does not match required type %1">; def err_addr_ovl_ambiguous : Error< "address of overloaded function %0 is ambiguous">; def err_addr_ovl_not_func_ptrref : Error< "address of overloaded function %0 cannot be converted to type %1">; def err_addr_ovl_no_qualifier : Error< "cannot form member pointer of type %0 without '&' and class name">; // C++11 Literal Operators def err_ovl_no_viable_literal_operator : Error< "no matching literal operator for call to %0" "%select{| with argument of type %2| with arguments of types %2 and %3}1" "%select{| or 'const char *'}4" "%select{|, and no matching literal operator template}5">; // C++ Template Declarations def err_template_param_shadow : Error< "declaration of %0 shadows template parameter">; def note_template_param_here : Note<"template parameter is declared here">; def warn_template_export_unsupported : Warning< "exported templates are unsupported">; def err_template_outside_namespace_or_class_scope : Error< "templates can only be declared in namespace or class scope">; def err_template_inside_local_class : Error< "templates cannot be declared inside of a local class">; def err_template_linkage : Error<"templates must have C++ linkage">; def err_template_typedef : Error<"a typedef cannot be a template">; def err_template_unnamed_class : Error< "cannot declare a class template with no name">; def err_template_param_list_different_arity : Error< "%select{too few|too many}0 template parameters in template " "%select{|template parameter }1redeclaration">; def note_template_param_list_different_arity : Note< "%select{too few|too many}0 template parameters in template template " "argument">; def note_template_prev_declaration : Note< "previous template %select{declaration|template parameter}0 is here">; def err_template_param_different_kind : Error< "template parameter has a different kind in template " "%select{|template parameter }0redeclaration">; def note_template_param_different_kind : Note< "template parameter has a different kind in template argument">; def err_template_nontype_parm_different_type : Error< "template non-type parameter has a different type %0 in template " "%select{|template parameter }1redeclaration">; def note_template_nontype_parm_different_type : Note< "template non-type parameter has a different type %0 in template argument">; def note_template_nontype_parm_prev_declaration : Note< "previous non-type template parameter with type %0 is here">; def err_template_nontype_parm_bad_type : Error< "a non-type template parameter cannot have type %0">; def err_template_param_default_arg_redefinition : Error< "template parameter redefines default argument">; def note_template_param_prev_default_arg : Note< "previous default template argument defined here">; def err_template_param_default_arg_missing : Error< "template parameter missing a default argument">; 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">; def err_template_parameter_default_friend_template : Error< "default template argument not permitted on a friend template">; def err_template_template_parm_no_parms : Error< "template template parameter must have its own template parameters">; def ext_variable_template : ExtWarn<"variable templates are a C++14 extension">, InGroup; def warn_cxx11_compat_variable_template : Warning< "variable templates are incompatible with C++ standards before C++14">, InGroup, DefaultIgnore; def err_template_variable_noparams : Error< "extraneous 'template<>' in declaration of variable %0">; def err_template_member : Error<"member %0 declared as a template">; def err_template_member_noparams : Error< "extraneous 'template<>' in declaration of member %0">; def err_template_tag_noparams : Error< "extraneous 'template<>' in declaration of %0 %1">; def err_template_decl_ref : Error< "cannot refer to %select{class|variable}0 template %1 without a template argument list">; // C++ Template Argument Lists def err_template_missing_args : Error< "use of class template %0 requires template arguments">; def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " "%select{class template|function template|template template parameter" "|template}1 %2">; def note_template_decl_here : Note<"template is declared here">; def err_template_arg_must_be_type : Error< "template argument for template type parameter must be a type">; def err_template_arg_must_be_type_suggest : Error< "template argument for template type parameter must be a type; " "did you forget 'typename'?">; def ext_ms_template_type_arg_missing_typename : ExtWarn< "template argument for template type parameter must be a type; " "omitted 'typename' is a Microsoft extension">, InGroup; def err_template_arg_must_be_expr : Error< "template argument for non-type template parameter must be an expression">; def err_template_arg_nontype_ambig : Error< "template argument for non-type template parameter is treated as function type %0">; def err_template_arg_must_be_template : Error< "template argument for template template parameter must be a class template%select{| or type alias template}0">; 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< "template argument is the type of an unresolved overloaded function">; def err_template_arg_not_valid_template : Error< "template argument does not refer to a class or alias template, or template " "template parameter">; def note_template_arg_refers_here_func : Note< "template argument refers to function template %0, here">; def err_template_arg_template_params_mismatch : Error< "template template argument has different template parameters than its " "corresponding template template parameter">; def err_template_arg_not_integral_or_enumeral : Error< "non-type template argument of type %0 must have an integral or enumeration" " type">; def err_template_arg_not_ice : Error< "non-type template argument of type %0 is not an integral constant " "expression">; def err_template_arg_not_address_constant : Error< "non-type template argument of type %0 is not a constant expression">; def warn_cxx98_compat_template_arg_null : Warning< "use of null pointer as non-type template argument is incompatible with " "C++98">, InGroup, DefaultIgnore; def err_template_arg_untyped_null_constant : Error< "null non-type template argument must be cast to template parameter type %0">; def err_template_arg_wrongtype_null_constant : Error< "null non-type template argument of type %0 does not match template parameter " "of type %1">; def err_deduced_non_type_template_arg_type_mismatch : Error< "deduced non-type template argument does not have the same type as the " "its corresponding template parameter%diff{ ($ vs $)|}0,1">; def err_non_type_template_arg_subobject : Error< "non-type template argument refers to subobject '%0'">; def err_non_type_template_arg_addr_label_diff : Error< "template argument / label address difference / what did you expect?">; def err_template_arg_not_convertible : Error< "non-type template argument of type %0 cannot be converted to a value " "of type %1">; def warn_template_arg_negative : Warning< "non-type template argument with value '%0' converted to '%1' for unsigned " "template parameter of type %2">, InGroup, DefaultIgnore; def warn_template_arg_too_large : Warning< "non-type template argument value '%0' truncated to '%1' for " "template parameter of type %2">, InGroup, DefaultIgnore; def err_template_arg_no_ref_bind : Error< "non-type template parameter of reference type " "%diff{$ cannot bind to template argument of type $" "|cannot bind to template of incompatible argument type}0,1">; def err_template_arg_ref_bind_ignores_quals : Error< "reference binding of non-type template parameter " "%diff{of type $ to template argument of type $|to template argument}0,1 " "ignores qualifiers">; def err_template_arg_not_decl_ref : Error< "non-type template argument does not refer to any declaration">; def err_template_arg_not_address_of : Error< "non-type template argument for template parameter of pointer type %0 must " "have its address taken">; def err_template_arg_address_of_non_pointer : Error< "address taken in non-type template argument for template parameter of " "reference type %0">; def err_template_arg_reference_var : Error< "non-type template argument of reference type %0 is not an object">; def err_template_arg_field : Error< "non-type template argument refers to non-static data member %0">; def err_template_arg_method : Error< "non-type template argument refers to non-static member function %0">; def err_template_arg_object_no_linkage : Error< "non-type template argument refers to %select{function|object}0 %1 that " "does not have linkage">; def warn_cxx98_compat_template_arg_object_internal : Warning< "non-type template argument referring to %select{function|object}0 %1 with " "internal linkage is incompatible with C++98">, InGroup, DefaultIgnore; def ext_template_arg_object_internal : ExtWarn< "non-type template argument referring to %select{function|object}0 %1 with " "internal linkage is a C++11 extension">, InGroup; def err_template_arg_thread_local : Error< "non-type template argument refers to thread-local object">; def note_template_arg_internal_object : Note< "non-type template argument refers to %select{function|object}0 here">; def note_template_arg_refers_here : Note< "non-type template argument refers here">; def err_template_arg_not_object_or_func : Error< "non-type template argument does not refer to an object or function">; def err_template_arg_not_pointer_to_member_form : Error< "non-type template argument is not a pointer to member constant">; def err_template_arg_member_ptr_base_derived_not_supported : Error< "sorry, non-type template argument of pointer-to-member type %1 that refers " "to member %q0 of a different class is not supported yet">; 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< "call to pointer to member function of type %0 drops '%1' qualifier%s2">; def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup; def ext_ms_delayed_template_argument: ExtWarn< "using the undeclared type %0 as a default template argument is a " "Microsoft extension">, InGroup; // C++ template specialization def err_template_spec_unknown_kind : Error< "can only provide an explicit specialization for a class template, function " "template, variable template, or a member function, static data member, " "%select{or member class|member class, or member enumeration}0 of a " "class template">; def note_specialized_entity : Note< "explicitly specialized declaration is here">; def note_explicit_specialization_declared_here : Note< "explicit specialization declared here">; def err_template_spec_decl_function_scope : Error< "explicit specialization of %0 in function scope">; def err_template_spec_decl_class_scope : Error< "explicit specialization of %0 in class scope">; def err_template_spec_decl_friend : Error< "cannot declare an explicit specialization in a friend">; def err_template_spec_decl_out_of_scope_global : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member function|" "static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in the global scope">; def err_template_spec_decl_out_of_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must originally be declared in namespace %2">; def ext_template_spec_decl_out_of_scope : ExtWarn< "first declaration of %select{class template|class template partial|" "variable template|variable template partial|" "function template|member function|static data member|member class|" "member enumeration}0 specialization of %1 outside namespace %2 is a " "C++11 extension">, InGroup; def warn_cxx98_compat_template_spec_decl_out_of_scope : Warning< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}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|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 not in a namespace enclosing %2">; def ext_ms_template_spec_redecl_out_of_scope: ExtWarn< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 outside namespace enclosing %2 " "is a Microsoft extension">, InGroup; def err_template_spec_redecl_global_scope : Error< "%select{class template|class template partial|variable template|" "variable template partial|function template|member " "function|static data member|member class|member enumeration}0 " "specialization of %1 must occur at global scope">; def err_spec_member_not_instantiated : Error< "specialization of member %q0 does not specialize an instantiated member">; def note_specialized_decl : Note<"attempt to specialize declaration here">; def err_specialization_after_instantiation : Error< "explicit specialization of %0 after instantiation">; def note_instantiation_required_here : Note< "%select{implicit|explicit}0 instantiation first required here">; def err_template_spec_friend : Error< "template specialization declaration cannot be a friend">; def err_template_spec_default_arg : Error< "default argument not permitted on an explicit " "%select{instantiation|specialization}0 of function %1">; def err_not_class_template_specialization : Error< "cannot specialize a %select{dependent template|template template " "parameter}0">; def err_function_specialization_in_class : Error< "cannot specialize a function %0 within class scope">; def ext_function_specialization_in_class : ExtWarn< "explicit specialization of %0 within class scope is a Microsoft extension">, InGroup; def ext_explicit_specialization_storage_class : ExtWarn< "explicit specialization cannot have a storage class">; def err_explicit_specialization_inconsistent_storage_class : Error< "explicit specialization has extraneous, inconsistent storage class " "'%select{none|extern|static|__private_extern__|auto|register}0'">; // C++ class template specializations and out-of-line definitions def err_template_spec_needs_header : Error< "template specialization requires 'template<>'">; def err_template_spec_needs_template_parameters : Error< "template specialization or definition requires a template parameter list " "corresponding to the nested type %0">; def err_template_param_list_matches_nontemplate : Error< "template parameter list matching the non-templated nested type %0 should " "be empty ('template<>')">; def err_alias_template_extra_headers : Error< "extraneous template parameter list in alias template declaration">; def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; def warn_template_spec_extra_headers : Warning< "extraneous template parameter list in template specialization">; def note_explicit_template_spec_does_not_need_header : Note< "'template<>' header not required for explicitly-specialized class %0 " "declared here">; def err_template_qualified_declarator_no_match : Error< "nested name specifier '%0' for declaration does not refer into a class, " "class template or class template partial specialization">; def err_specialize_member_of_template : Error< "cannot specialize %select{|(with 'template<>') }0a member of an " "unspecialized template">; // C++ Class Template Partial Specialization def err_default_arg_in_partial_spec : Error< "default template argument in a class template partial specialization">; def err_dependent_non_type_arg_in_partial_spec : Error< "non-type template argument depends on a template parameter of the " "partial specialization">; def note_dependent_non_type_default_arg_in_partial_spec : Note< "template parameter is used in default argument declared here">; def err_dependent_typed_non_type_arg_in_partial_spec : Error< "non-type template argument specializes a template parameter with " "dependent type %0">; def err_partial_spec_args_match_primary_template : Error< "%select{class|variable}0 template partial specialization does not " "specialize any template argument; to %select{declare|define}1 the " "primary template, remove the template argument list">; def warn_partial_specs_not_deducible : Warning< "%select{class|variable}0 template partial specialization contains " "%select{a template parameter|template parameters}1 that cannot be " "deduced; this partial specialization will never be used">; def note_partial_spec_unused_parameter : Note< "non-deducible template parameter %0">; def err_partial_spec_ordering_ambiguous : Error< "ambiguous partial specializations of %0">; def note_partial_spec_match : Note<"partial specialization matches %0">; def err_partial_spec_redeclared : Error< "class template partial specialization %0 cannot be redeclared">; def note_partial_specialization_declared_here : Note< "explicit specialization declared here">; def note_prev_partial_spec_here : Note< "previous declaration of class template partial specialization %0 is here">; def err_partial_spec_fully_specialized : Error< "partial specialization of %0 does not use any of its template parameters">; // C++ Variable Template Partial Specialization def err_var_partial_spec_redeclared : Error< "variable template partial specialization %0 cannot be redefined">; def note_var_prev_partial_spec_here : Note< "previous declaration of variable template partial specialization is here">; def err_var_spec_no_template : Error< "no variable template matches%select{| partial}0 specialization">; def err_var_spec_no_template_but_method : Error< "no variable template matches specialization; " "did you mean to use %0 as function template instead?">; // C++ Function template specializations def err_function_template_spec_no_match : Error< "no function template matches function template specialization %0">; def err_function_template_spec_ambiguous : Error< "function template specialization %0 ambiguously refers to more than one " "function template; explicitly specify%select{| additional}1 template " "arguments to identify a particular function template">; def note_function_template_spec_matched : Note< "function template matches specialization %0">; def err_function_template_partial_spec : Error< "function template partial specialization is not allowed">; // C++ Template Instantiation def err_template_recursion_depth_exceeded : Error< "recursive template instantiation exceeded maximum depth of %0">, DefaultFatal, NoSFINAE; def note_template_recursion_depth : Note< "use -ftemplate-depth=N to increase recursive template instantiation depth">; def err_template_instantiate_within_definition : Error< "%select{implicit|explicit}0 instantiation of template %1 within its" " own definition">; def err_template_instantiate_undefined : Error< "%select{implicit|explicit}0 instantiation of undefined template %1">; def err_implicit_instantiate_member_undefined : Error< "implicit instantiation of undefined member %0">; def note_template_class_instantiation_was_here : Note< "class template %0 was instantiated here">; def note_template_class_explicit_specialization_was_here : Note< "class template %0 was explicitly specialized here">; def note_template_class_instantiation_here : Note< "in instantiation of template class %0 requested here">; def note_template_member_class_here : Note< "in instantiation of member class %0 requested here">; def note_template_member_function_here : Note< "in instantiation of member function %q0 requested here">; def note_function_template_spec_here : Note< "in instantiation of function template specialization %q0 requested here">; def note_template_static_data_member_def_here : Note< "in instantiation of static data member %q0 requested here">; def note_template_variable_def_here : Note< "in instantiation of variable template specialization %q0 requested here">; def note_template_enum_def_here : Note< "in instantiation of enumeration %q0 requested here">; def note_template_nsdmi_here : Note< "in instantiation of default member initializer %q0 requested here">; def note_template_type_alias_instantiation_here : Note< "in instantiation of template type alias %0 requested here">; def note_template_exception_spec_instantiation_here : Note< "in instantiation of exception specification for %0 requested here">; def warn_var_template_missing : Warning<"instantiation of variable %q0 " "required here, but no definition is available">, InGroup; def warn_func_template_missing : Warning<"instantiation of function %q0 " "required here, but no definition is available">, InGroup, DefaultIgnore; def note_forward_template_decl : Note< "forward declaration of template entity is here">; def note_inst_declaration_hint : Note<"add an explicit instantiation " "declaration to suppress this warning if %q0 is explicitly instantiated in " "another translation unit">; def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; def note_default_function_arg_instantiation_here : Note< "in instantiation of default function argument expression " "for '%0' required here">; def note_explicit_template_arg_substitution_here : Note< "while substituting explicitly-specified template arguments into function " "template %0 %1">; def note_function_template_deduction_instantiation_here : Note< "while substituting deduced template arguments into function template %0 " "%1">; def note_partial_spec_deduct_instantiation_here : Note< "during template argument deduction for class template partial " "specialization %0 %1">; def note_prior_template_arg_substitution : Note< "while substituting prior template arguments into %select{non-type|template}0" " template parameter%1 %2">; def note_template_default_arg_checking : Note< "while checking a default template argument used here">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; def err_field_instantiates_to_function : Error< "data member instantiated with function type %0">; def err_variable_instantiates_to_function : Error< "%select{variable|static data member}0 instantiated with function type %1">; def err_nested_name_spec_non_tag : Error< "type %0 cannot be used prior to '::' because it has no members">; // C++ Explicit Instantiation def err_explicit_instantiation_duplicate : Error< "duplicate explicit instantiation of %0">; def ext_explicit_instantiation_duplicate : ExtWarn< "duplicate explicit instantiation of %0 ignored as a Microsoft extension">, InGroup; def note_previous_explicit_instantiation : Note< "previous explicit instantiation is here">; 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_nontemplate_type : Error< "explicit instantiation of non-templated type %0">; def note_nontemplate_decl_here : Note< "non-templated declaration is here">; def err_explicit_instantiation_in_class : Error< "explicit instantiation of %0 in class scope">; def err_explicit_instantiation_out_of_scope : Error< "explicit instantiation of %0 not in a namespace enclosing %1">; def err_explicit_instantiation_must_be_global : Error< "explicit instantiation of %0 must occur at global scope">; def warn_explicit_instantiation_out_of_scope_0x : Warning< "explicit instantiation of %0 not in a namespace enclosing %1">, InGroup, DefaultIgnore; def warn_explicit_instantiation_must_be_global_0x : Warning< "explicit instantiation of %0 must occur at global scope">, InGroup, DefaultIgnore; def err_explicit_instantiation_requires_name : Error< "explicit instantiation declaration requires a name">; def err_explicit_instantiation_of_typedef : Error< "explicit instantiation of typedef %0">; def err_explicit_instantiation_storage_class : Error< "explicit instantiation cannot have a storage class">; def err_explicit_instantiation_not_known : Error< "explicit instantiation of %0 does not refer to a function template, " "variable template, member function, member class, or static data member">; def note_explicit_instantiation_here : Note< "explicit instantiation refers here">; def err_explicit_instantiation_data_member_not_instantiated : Error< "explicit instantiation refers to static data member %q0 that is not an " "instantiation">; def err_explicit_instantiation_member_function_not_instantiated : Error< "explicit instantiation refers to member function %q0 that is not an " "instantiation">; def err_explicit_instantiation_ambiguous : Error< "partial ordering for explicit instantiation of %0 is ambiguous">; def note_explicit_instantiation_candidate : Note< "explicit instantiation candidate function template here %0">; def err_explicit_instantiation_inline : Error< "explicit instantiation cannot be 'inline'">; def warn_explicit_instantiation_inline_0x : Warning< "explicit instantiation cannot be 'inline'">, InGroup, DefaultIgnore; def err_explicit_instantiation_constexpr : Error< "explicit instantiation cannot be 'constexpr'">; def ext_explicit_instantiation_without_qualified_id : Extension< "qualifier in explicit instantiation of %q0 requires a template-id " "(a typedef is not permitted)">; def err_explicit_instantiation_without_template_id : Error< "explicit instantiation of %q0 must specify a template argument list">; def err_explicit_instantiation_unqualified_wrong_namespace : Error< "explicit instantiation of %q0 must occur in namespace %1">; def warn_explicit_instantiation_unqualified_wrong_namespace_0x : Warning< "explicit instantiation of %q0 must occur in namespace %1">, InGroup, DefaultIgnore; def err_explicit_instantiation_undefined_member : Error< "explicit instantiation of undefined %select{member class|member function|" "static data member}0 %1 of class template %2">; def err_explicit_instantiation_undefined_func_template : Error< "explicit instantiation of undefined function template %0">; def err_explicit_instantiation_undefined_var_template : Error< "explicit instantiation of undefined variable template %q0">; def err_explicit_instantiation_declaration_after_definition : Error< "explicit instantiation declaration (with 'extern') follows explicit " "instantiation definition (without 'extern')">; def note_explicit_instantiation_definition_here : Note< "explicit instantiation definition is here">; def err_invalid_var_template_spec_type : Error<"type %2 " "of %select{explicit instantiation|explicit specialization|" "partial specialization|redeclaration}0 of %1 does not match" " expected type %3">; def err_mismatched_exception_spec_explicit_instantiation : Error< "exception specification in explicit instantiation does not match " "instantiated one">; def ext_mismatched_exception_spec_explicit_instantiation : ExtWarn< err_mismatched_exception_spec_explicit_instantiation.Text>, InGroup; // C++ typename-specifiers def err_typename_nested_not_found : Error<"no type named %0 in %1">; def err_typename_nested_not_found_enable_if : Error< "no type named 'type' in %0; 'enable_if' cannot be used to disable " "this declaration">; def err_typename_nested_not_type : Error< "typename specifier refers to non-type member %0 in %1">; def note_typename_refers_here : Note< "referenced member %0 is declared here">; def err_typename_missing : Error< "missing 'typename' prior to dependent type name '%0%1'">; def ext_typename_missing : ExtWarn< "missing 'typename' prior to dependent type name '%0%1'">, 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">; def note_using_value_decl_missing_typename : Note< "add 'typename' to treat this using declaration as a type">; def err_template_kw_refers_to_non_template : Error< "%0 following the 'template' keyword does not refer to a template">; def err_template_kw_refers_to_class_template : Error< "'%0%1' instantiated to a class template, not a function template">; def note_referenced_class_template : Error< "class template declared here">; 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 %select{function|variable}0 " "template %1">; def err_template_id_not_a_type : Error< "template name refers to non-type template %0">; def note_template_declared_here : Note< "%select{function template|class template|variable template" "|type alias template|template template parameter}0 " "%1 declared here">; def err_alias_template_expansion_into_fixed_list : Error< "pack expansion used as argument for non-pack parameter of alias template">; def note_parameter_type : Note< "parameter of type %0 is declared here">; // C++11 Variadic Templates def err_template_param_pack_default_arg : Error< "template parameter pack cannot have a default argument">; def err_template_param_pack_must_be_last_template_parameter : Error< "template parameter pack must be the last template parameter">; def err_template_parameter_pack_non_pack : Error< "%select{template type|non-type template|template template}0 parameter" "%select{| pack}1 conflicts with previous %select{template type|" "non-type template|template template}0 parameter%select{ pack|}1">; def note_template_parameter_pack_non_pack : Note< "%select{template type|non-type template|template template}0 parameter" "%select{| pack}1 does not match %select{template type|non-type template" "|template template}0 parameter%select{ pack|}1 in template argument">; def note_template_parameter_pack_here : Note< "previous %select{template type|non-type template|template template}0 " "parameter%select{| pack}1 declared here">; def err_unexpanded_parameter_pack : Error< "%select{expression|base type|declaration type|data member type|bit-field " "size|static assertion|fixed underlying type|enumerator value|" "using declaration|friend declaration|qualifier|initializer|default argument|" "non-type template parameter type|exception type|partial specialization|" "__if_exists name|__if_not_exists name|lambda|block}0 contains" "%plural{0: an|:}1 unexpanded parameter pack" "%plural{0:|1: %2|2:s %2 and %3|:s %2, %3, ...}1">; def err_pack_expansion_without_parameter_packs : Error< "pack expansion does not contain any unexpanded parameter packs">; def err_pack_expansion_length_conflict : Error< "pack expansion contains parameter packs %0 and %1 that have different " "lengths (%2 vs. %3)">; def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " "length (%1 vs. %2) from outer parameter packs">; def err_pack_expansion_member_init : Error< "pack expansion for initialization of member %0">; def err_function_parameter_pack_without_parameter_packs : Error< "type %0 of function parameter pack does not contain any unexpanded " "parameter packs">; def err_ellipsis_in_declarator_not_parameter : Error< "only function and template parameters can be parameter packs">; def err_sizeof_pack_no_pack_name : Error< "%0 does not refer to the name of a parameter pack">; def err_fold_expression_packs_both_sides : Error< "binary fold expression has unexpanded parameter packs in both operands">; def err_fold_expression_empty : Error< "unary fold expression has empty expansion for operator '%0' " "with no fallback value">; def err_fold_expression_bad_operand : Error< "expression not permitted as operand of fold expression">; def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; def err_unexpected_namespace : Error< "unexpected namespace name %0: expected expression">; def err_undeclared_var_use : Error<"use of undeclared identifier %0">; def ext_undeclared_unqual_id_with_dependent_base : ExtWarn< "use of undeclared identifier %0; " "unqualified lookup into dependent bases of class template %1 is a Microsoft extension">, InGroup; def ext_found_via_dependent_bases_lookup : ExtWarn<"use of identifier %0 " "found via unqualified lookup into dependent bases of class templates is a " "Microsoft extension">, InGroup; def note_dependent_var_use : Note<"must qualify identifier to find this " "declaration in dependent base class">; def err_not_found_by_two_phase_lookup : Error<"call to function %0 that is neither " "visible in the template definition nor found by argument-dependent lookup">; def note_not_found_by_two_phase_lookup : Note<"%0 should be declared prior to the " "call site%select{| or in %2| or in an associated namespace of one of its arguments}1">; def err_undeclared_use : Error<"use of undeclared %0">; def warn_partial_availability : Warning<"%0 is only available conditionally">, InGroup, DefaultIgnore; def note_partial_availability_silence : Note< "explicitly redeclare %0 to silence this warning">; def warn_partial_message : Warning<"%0 is partial: %1">, InGroup, DefaultIgnore; def warn_partial_fwdclass_message : Warning< "%0 may be partial because the receiver type is unknown">, InGroup, DefaultIgnore; def warn_deprecated : Warning<"%0 is deprecated">, InGroup; def warn_property_method_deprecated : Warning<"property access is using %0 method which is deprecated">, InGroup; def warn_deprecated_message : Warning<"%0 is deprecated: %1">, InGroup; def warn_deprecated_anonymous_namespace : Warning< "'deprecated' attribute on anonymous namespace ignored">, InGroup; def warn_deprecated_fwdclass_message : Warning< "%0 may be deprecated because the receiver type is unknown">, InGroup; def warn_deprecated_def : Warning< "Implementing deprecated %select{method|class|category}0">, InGroup, DefaultIgnore; def err_unavailable : Error<"%0 is unavailable">; def err_property_method_unavailable : Error<"property access is using %0 method which is unavailable">; def err_unavailable_message : Error<"%0 is unavailable: %1">; def warn_unavailable_fwdclass_message : Warning< "%0 may be unavailable because the receiver type is unknown">, InGroup; def note_availability_specified_here : Note< "%0 has been explicitly marked " "%select{unavailable|deleted|deprecated|partial}1 here">; def note_implicitly_deleted : Note< "explicitly defaulted function was implicitly deleted here">; def note_inherited_deleted_here : Note< "deleted constructor was inherited here">; def warn_not_enough_argument : Warning< "not enough variable arguments in %0 declaration to fit a sentinel">, InGroup; def warn_missing_sentinel : Warning < "missing sentinel in %select{function call|method dispatch|block call}0">, InGroup; def note_sentinel_here : Note< "%select{function|method|block}0 has been explicitly marked sentinel here">; def warn_missing_prototype : Warning< "no previous prototype for function %0">, InGroup>, DefaultIgnore; def note_declaration_not_a_prototype : Note< "this declaration is not a prototype; add 'void' to make it a prototype for a zero-parameter function">; def warn_missing_variable_declarations : Warning< "no previous extern declaration for non-static variable %0">, InGroup>, DefaultIgnore; def err_static_data_member_reinitialization : Error<"static data member %0 already has an initializer">; def err_redefinition : Error<"redefinition of %0">; def err_alias_after_tentative : Error<"alias definition of %0 after tentative definition">; def err_alias_is_definition : Error<"definition %0 cannot also be an %select{alias|ifunc}1">; def err_definition_of_implicitly_declared_member : Error< "definition of implicitly declared %select{default constructor|copy " "constructor|move constructor|copy assignment operator|move assignment " "operator|destructor|function}1">; def err_definition_of_explicitly_defaulted_member : Error< "definition of explicitly defaulted %select{default constructor|copy " "constructor|move constructor|copy assignment operator|move assignment " "operator|destructor|function}0">; def err_redefinition_extern_inline : Error< "redefinition of a 'extern inline' function %0 is not supported in " "%select{C99 mode|C++}1">; def warn_attr_abi_tag_namespace : Warning< "'abi_tag' attribute on %select{non-inline|anonymous}0 namespace ignored">, InGroup; def err_abi_tag_on_redeclaration : Error< "cannot add 'abi_tag' attribute in a redeclaration">; def err_new_abi_tag_on_redeclaration : Error< "'abi_tag' %0 missing in original declaration">; def note_deleted_dtor_no_operator_delete : Note< "virtual destructor requires an unambiguous, accessible 'operator delete'">; def note_deleted_special_member_class_subobject : Note< "%select{default constructor of|copy constructor of|move constructor of|" "copy assignment operator of|move assignment operator of|destructor of|" "constructor inherited by}0 " "%1 is implicitly deleted because " "%select{base class %3|%select{||||variant }4field %3}2 has " "%select{no|a deleted|multiple|an inaccessible|a non-trivial}4 " "%select{%select{default constructor|copy constructor|move constructor|copy " "assignment operator|move assignment operator|destructor|" "%select{default|corresponding|default|default|default}4 constructor}0|" "destructor}5" "%select{||s||}4">; def note_deleted_default_ctor_uninit_field : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because field %2 of " "%select{reference|const-qualified}4 type %3 would not be initialized">; def note_deleted_default_ctor_all_const : Note< "%select{default constructor of|constructor inherited by}0 " "%1 is implicitly deleted because all " "%select{data members|data members of an anonymous union member}2" " are const-qualified">; def note_deleted_copy_ctor_rvalue_reference : Note< "copy constructor of %0 is implicitly deleted because field %1 is of " "rvalue reference type %2">; def note_deleted_copy_user_declared_move : Note< "copy %select{constructor|assignment operator}0 is implicitly deleted because" " %1 has a user-declared move %select{constructor|assignment operator}2">; def note_deleted_assign_field : Note< "%select{copy|move}0 assignment operator of %1 is implicitly deleted " "because field %2 is of %select{reference|const-qualified}4 type %3">; // These should be errors. def warn_undefined_internal : Warning< "%select{function|variable}0 %q1 has internal linkage but is not defined">, InGroup>; def warn_undefined_inline : Warning<"inline function %q0 is not defined">, InGroup>; def err_undefined_inline_var : Error<"inline variable %q0 is not defined">; def note_used_here : Note<"used here">; def err_internal_linkage_redeclaration : Error< "'internal_linkage' attribute does not appear on the first declaration of %0">; def warn_internal_linkage_local_storage : Warning< "'internal_linkage' attribute on a non-static local variable is ignored">, InGroup; def ext_internal_in_extern_inline : ExtWarn< "static %select{function|variable}0 %1 is used in an inline function with " "external linkage">, InGroup; def ext_internal_in_extern_inline_quiet : Extension< "static %select{function|variable}0 %1 is used in an inline function with " "external linkage">, InGroup; def warn_static_local_in_extern_inline : Warning< "non-constant static local variable in inline function may be different " "in different files">, InGroup; def note_convert_inline_to_static : Note< "use 'static' to give inline function %0 internal linkage">; def ext_redefinition_of_typedef : ExtWarn< "redefinition of typedef %0 is a C11 feature">, InGroup >; def err_redefinition_variably_modified_typedef : Error< "redefinition of %select{typedef|type alias}0 for variably-modified type %1">; def err_inline_decl_follows_def : Error< "inline declaration of %0 follows non-inline definition">; def err_inline_declaration_block_scope : Error< "inline declaration of %0 not allowed in block scope">; def err_static_non_static : Error< "static declaration of %0 follows non-static declaration">; def err_different_language_linkage : Error< "declaration of %0 has a different language linkage">; def ext_retained_language_linkage : Extension< "friend function %0 retaining previous language linkage is an extension">, InGroup>; def err_extern_c_global_conflict : Error< "declaration of %1 %select{with C language linkage|in global scope}0 " "conflicts with declaration %select{in global scope|with C language linkage}0">; def note_extern_c_global_conflict : Note< "declared %select{in global scope|with C language linkage}0 here">; def warn_weak_import : Warning < "an already-declared variable is made a weak_import declaration %0">; def ext_static_non_static : Extension< "redeclaring non-static %0 as static is a Microsoft extension">, InGroup; def err_non_static_static : Error< "non-static declaration of %0 follows static declaration">; def err_extern_non_extern : Error< "extern declaration of %0 follows non-extern declaration">; def err_non_extern_extern : Error< "non-extern declaration of %0 follows extern declaration">; def err_non_thread_thread : Error< "non-thread-local declaration of %0 follows thread-local declaration">; def err_thread_non_thread : Error< "thread-local declaration of %0 follows non-thread-local declaration">; def err_thread_thread_different_kind : Error< "thread-local declaration of %0 with %select{static|dynamic}1 initialization " "follows declaration with %select{dynamic|static}1 initialization">; def err_redefinition_different_type : Error< "redefinition of %0 with a different type%diff{: $ vs $|}1,2">; def err_redefinition_different_kind : Error< "redefinition of %0 as different kind of symbol">; def err_redefinition_different_namespace_alias : Error< "redefinition of %0 as an alias for a different namespace">; def note_previous_namespace_alias : Note< "previously defined as an alias for %0">; def warn_forward_class_redefinition : Warning< "redefinition of forward class %0 of a typedef name of an object type is ignored">, InGroup>; def err_redefinition_different_typedef : Error< "%select{typedef|type alias|type alias template}0 " "redefinition with different types%diff{ ($ vs $)|}1,2">; def err_tag_reference_non_tag : Error< "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template|a template template argument}0">; def err_tag_reference_conflict : Error< "implicit declaration introduced by elaborated type conflicts with " "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; def err_dependent_tag_decl : Error< "%select{declaration|definition}0 of " "%select{struct|interface|union|class|enum}1 in a dependent scope">; def err_tag_definition_of_typedef : Error< "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">; def err_conflicting_types : Error<"conflicting types for %0">; def err_different_pass_object_size_params : Error< "conflicting pass_object_size attributes on parameters">; def err_late_asm_label_name : Error< "cannot apply asm label to %select{variable|function}0 after its first use">; def err_different_asm_label : Error<"conflicting asm label">; def err_nested_redefinition : Error<"nested redefinition of %0">; def err_use_with_wrong_tag : Error< "use of %0 with tag type that does not match previous declaration">; def warn_struct_class_tag_mismatch : Warning< "%select{struct|interface|class}0%select{| template}1 %2 was previously " "declared as a %select{struct|interface|class}3%select{| template}1">, InGroup, DefaultIgnore; def warn_struct_class_previous_tag_mismatch : Warning< "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 " "here but previously declared as " "%select{a struct|an interface|a class}3%select{| template}1">, InGroup, DefaultIgnore; def note_struct_class_suggestion : Note< "did you mean %select{struct|interface|class}0 here?">; def ext_forward_ref_enum : Extension< "ISO C forbids forward references to 'enum' types">; def err_forward_ref_enum : Error< "ISO C++ forbids forward references to 'enum' types">; def ext_ms_forward_ref_enum : Extension< "forward references to 'enum' types are a Microsoft extension">, InGroup; def ext_forward_ref_enum_def : Extension< "redeclaration of already-defined enum %0 is a GNU extension">, InGroup; def err_redefinition_of_enumerator : Error<"redefinition of enumerator %0">; def err_duplicate_member : Error<"duplicate member %0">; def err_misplaced_ivar : Error< "instance variables may not be placed in %select{categories|class extension}0">; def warn_ivars_in_interface : Warning< "declaration of instance variables in the interface is deprecated">, InGroup>, DefaultIgnore; def ext_enum_value_not_int : Extension< "ISO C restricts enumerator values to range of 'int' (%0 is too " "%select{small|large}1)">; def ext_enum_too_large : ExtWarn< "enumeration values exceed range of largest integer">, InGroup; def ext_enumerator_increment_too_large : ExtWarn< "incremented enumerator value %0 is not representable in the " "largest integer type">, InGroup; def warn_flag_enum_constant_out_of_range : Warning< "enumeration value %0 is out of range of flags in enumeration type %1">, InGroup; def warn_illegal_constant_array_size : Extension< "size of static array must be an integer constant expression">; def err_vm_decl_in_file_scope : Error< "variably modified type declaration not allowed at file scope">; def err_vm_decl_has_extern_linkage : Error< "variably modified type declaration cannot have 'extern' linkage">; def err_typecheck_field_variable_size : Error< "fields must have a constant size: 'variable length array in structure' " "extension will never be supported">; def err_vm_func_decl : Error< "function declaration cannot have variably modified type">; def err_array_too_large : Error< "array is too large (%0 elements)">; def warn_array_new_too_large : Warning<"array is too large (%0 elements)">, // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" InGroup; // -Wpadded, -Wpacked def warn_padded_struct_field : Warning< "padding %select{struct|interface|class}0 %1 with %2 " "%select{byte|bit}3%s2 to align %4">, InGroup, DefaultIgnore; def warn_padded_struct_anon_field : Warning< "padding %select{struct|interface|class}0 %1 with %2 " "%select{byte|bit}3%s2 to align anonymous bit-field">, InGroup, DefaultIgnore; def warn_padded_struct_size : Warning< "padding size of %0 with %1 %select{byte|bit}2%s1 to alignment boundary">, InGroup, DefaultIgnore; def warn_unnecessary_packed : Warning< "packed attribute is unnecessary for %0">, InGroup, DefaultIgnore; def err_typecheck_negative_array_size : Error<"array size is negative">; def warn_typecheck_negative_array_new_size : Warning<"array size is negative">, // FIXME PR11644: ", will throw std::bad_array_new_length at runtime" InGroup; def warn_typecheck_function_qualifiers_ignored : Warning< "'%0' qualifier on function type %1 has no effect">, InGroup; def warn_typecheck_function_qualifiers_unspecified : Warning< "'%0' qualifier on function type %1 has unspecified behavior">; def warn_typecheck_reference_qualifiers : Warning< "'%0' qualifier on reference type %1 has no effect">, InGroup; def err_typecheck_invalid_restrict_not_pointer : Error< "restrict requires a pointer or reference (%0 is invalid)">; def err_typecheck_invalid_restrict_not_pointer_noarg : Error< "restrict requires a pointer or reference">; def err_typecheck_invalid_restrict_invalid_pointee : Error< "pointer to function type %0 may not be 'restrict' qualified">; def ext_typecheck_zero_array_size : Extension< "zero size arrays are an extension">, InGroup; def err_typecheck_zero_array_size : Error< "zero-length arrays are not permitted in C++">; def warn_typecheck_zero_static_array_size : Warning< "'static' has no effect on zero-length arrays">, InGroup; def err_array_size_non_int : Error<"size of array has non-integer type %0">; def err_init_element_not_constant : Error< "initializer element is not a compile-time constant">; def ext_aggregate_init_not_constant : Extension< "initializer for aggregate is not a compile-time constant">, InGroup; def err_local_cant_init : Error< "'__local' variable cannot have an initializer">; def err_block_extern_cant_init : Error< "'extern' variable cannot have an initializer">; def warn_extern_init : Warning<"'extern' variable has an initializer">, InGroup>; def err_variable_object_no_init : Error< "variable-sized object may not be initialized">; def err_excess_initializers : Error< "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; def ext_excess_initializers : ExtWarn< "excess elements in %select{array|vector|scalar|union|struct}0 initializer">; def err_excess_initializers_in_char_array_initializer : Error< "excess elements in char array initializer">; def ext_excess_initializers_in_char_array_initializer : ExtWarn< "excess elements in char array initializer">; def err_initializer_string_for_char_array_too_long : Error< "initializer-string for char array is too long">; def ext_initializer_string_for_char_array_too_long : ExtWarn< "initializer-string for char array is too long">; def warn_missing_field_initializers : Warning< "missing field %0 initializer">, InGroup, DefaultIgnore; def warn_braces_around_scalar_init : Warning< "braces around scalar initializer">, InGroup>; def ext_many_braces_around_scalar_init : ExtWarn< "too many braces around scalar initializer">, InGroup>; def ext_complex_component_init : Extension< "complex initialization specifying real and imaginary components " "is an extension">, InGroup>; def err_empty_scalar_initializer : Error<"scalar initializer cannot be empty">; def warn_cxx98_compat_empty_scalar_initializer : Warning< "scalar initialized from empty initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_reference_list_init : Warning< "reference initialized from initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_initializer_list_init : Warning< "initialization of initializer_list object is incompatible with C++98">, InGroup, DefaultIgnore; def warn_cxx98_compat_ctor_list_init : Warning< "constructor call from initializer list is incompatible with C++98">, InGroup, DefaultIgnore; def err_illegal_initializer : Error< "illegal initializer (only variables can be initialized)">; def err_illegal_initializer_type : Error<"illegal initializer type %0">; def ext_init_list_type_narrowing : ExtWarn< "type %0 cannot be narrowed to %1 in initializer list">, InGroup, DefaultError, SFINAEFailure; def ext_init_list_variable_narrowing : ExtWarn< "non-constant-expression cannot be narrowed from type %0 to %1 in " "initializer list">, InGroup, DefaultError, SFINAEFailure; def ext_init_list_constant_narrowing : ExtWarn< "constant expression evaluates to %0 which cannot be narrowed to type %1">, InGroup, DefaultError, SFINAEFailure; def warn_init_list_type_narrowing : Warning< "type %0 cannot be narrowed to %1 in initializer list in C++11">, InGroup, DefaultIgnore; def warn_init_list_variable_narrowing : Warning< "non-constant-expression cannot be narrowed from type %0 to %1 in " "initializer list in C++11">, InGroup, DefaultIgnore; def warn_init_list_constant_narrowing : Warning< "constant expression evaluates to %0 which cannot be narrowed to type %1 in " "C++11">, InGroup, DefaultIgnore; def note_init_list_narrowing_silence : Note< "insert an explicit cast to silence this issue">; def err_init_objc_class : Error< "cannot initialize Objective-C class type %0">; def err_implicit_empty_initializer : Error< "initializer for aggregate with no elements requires explicit braces">; def err_bitfield_has_negative_width : Error< "bit-field %0 has negative width (%1)">; def err_anon_bitfield_has_negative_width : Error< "anonymous bit-field has negative width (%0)">; def err_bitfield_has_zero_width : Error<"named bit-field %0 has zero width">; def err_bitfield_width_exceeds_type_width : Error< "width of bit-field %0 (%1 bits) exceeds %select{width|size}2 " "of its type (%3 bit%s3)">; def err_anon_bitfield_width_exceeds_type_width : Error< "width of anonymous bit-field (%0 bits) exceeds %select{width|size}1 " "of its type (%2 bit%s2)">; def err_incorrect_number_of_vector_initializers : Error< "number of elements must be either one or match the size of the vector">; // Used by C++ which allows bit-fields that are wider than the type. def warn_bitfield_width_exceeds_type_width: Warning< "width of bit-field %0 (%1 bits) exceeds the width of its type; value will " "be truncated to %2 bit%s2">, InGroup; def warn_anon_bitfield_width_exceeds_type_width : Warning< "width of anonymous bit-field (%0 bits) exceeds width of its type; value " "will be truncated to %1 bit%s1">, InGroup; def warn_missing_braces : Warning< "suggest braces around initialization of subobject">, InGroup, DefaultIgnore; def err_redefinition_of_label : Error<"redefinition of label %0">; def err_undeclared_label_use : Error<"use of undeclared label %0">; def err_goto_ms_asm_label : Error< "cannot jump from this goto statement to label %0 inside an inline assembly block">; def note_goto_ms_asm_label : Note< "inline assembly label %0 declared here">; def warn_unused_label : Warning<"unused label %0">, InGroup, DefaultIgnore; def err_goto_into_protected_scope : Error< "cannot jump from this goto statement to its label">; def ext_goto_into_protected_scope : ExtWarn< "jump from this goto statement to its label is a Microsoft extension">, InGroup; def warn_cxx98_compat_goto_into_protected_scope : Warning< "jump from this goto statement to its label is incompatible with C++98">, InGroup, DefaultIgnore; def err_switch_into_protected_scope : Error< "cannot jump from switch statement to this case label">; def warn_cxx98_compat_switch_into_protected_scope : Warning< "jump from switch statement to this case label is incompatible with C++98">, InGroup, DefaultIgnore; def err_indirect_goto_without_addrlabel : Error< "indirect goto in function with no address-of-label expressions">; def err_indirect_goto_in_protected_scope : Error< "cannot jump from this indirect goto statement to one of its possible targets">; def warn_cxx98_compat_indirect_goto_in_protected_scope : Warning< "jump from this indirect goto statement to one of its possible targets " "is incompatible with C++98">, InGroup, DefaultIgnore; def note_indirect_goto_target : Note< "possible target of indirect goto statement">; def note_protected_by_variable_init : Note< "jump bypasses variable initialization">; def note_protected_by_variable_nontriv_destructor : Note< "jump bypasses variable with a non-trivial destructor">; def note_protected_by_variable_non_pod : Note< "jump bypasses initialization of non-POD variable">; def note_protected_by_cleanup : Note< "jump bypasses initialization of variable with __attribute__((cleanup))">; def note_protected_by_vla_typedef : Note< "jump bypasses initialization of VLA typedef">; def note_protected_by_vla_type_alias : Note< "jump bypasses initialization of VLA type alias">; def note_protected_by_constexpr_if : Note< "jump enters controlled statement of constexpr if">; def note_protected_by_vla : Note< "jump bypasses initialization of variable length array">; def note_protected_by_objc_try : Note< "jump bypasses initialization of @try block">; def note_protected_by_objc_catch : Note< "jump bypasses initialization of @catch block">; def note_protected_by_objc_finally : Note< "jump bypasses initialization of @finally block">; def note_protected_by_objc_synchronized : Note< "jump bypasses initialization of @synchronized block">; def note_protected_by_objc_autoreleasepool : Note< "jump bypasses auto release push of @autoreleasepool block">; def note_protected_by_cxx_try : Note< "jump bypasses initialization of try block">; def note_protected_by_cxx_catch : Note< "jump bypasses initialization of catch block">; def note_protected_by_seh_try : Note< "jump bypasses initialization of __try block">; def note_protected_by_seh_except : Note< "jump bypasses initialization of __except block">; def note_protected_by_seh_finally : Note< "jump bypasses initialization of __finally block">; def note_protected_by___block : Note< "jump bypasses setup of __block variable">; def note_protected_by_objc_strong_init : Note< "jump bypasses initialization of __strong variable">; def note_protected_by_objc_weak_init : Note< "jump bypasses initialization of __weak variable">; def note_enters_block_captures_cxx_obj : Note< "jump enters lifetime of block which captures a destructible C++ object">; def note_enters_block_captures_strong : Note< "jump enters lifetime of block which strongly captures a variable">; def note_enters_block_captures_weak : Note< "jump enters lifetime of block which weakly captures a variable">; def note_exits_cleanup : Note< "jump exits scope of variable with __attribute__((cleanup))">; def note_exits_dtor : Note< "jump exits scope of variable with non-trivial destructor">; def note_exits_temporary_dtor : Note< "jump exits scope of lifetime-extended temporary with non-trivial " "destructor">; def note_exits___block : Note< "jump exits scope of __block variable">; def note_exits_objc_try : Note< "jump exits @try block">; def note_exits_objc_catch : Note< "jump exits @catch block">; def note_exits_objc_finally : Note< "jump exits @finally block">; def note_exits_objc_synchronized : Note< "jump exits @synchronized block">; def note_exits_cxx_try : Note< "jump exits try block">; def note_exits_cxx_catch : Note< "jump exits catch block">; def note_exits_seh_try : Note< "jump exits __try block">; def note_exits_seh_except : Note< "jump exits __except block">; def note_exits_seh_finally : Note< "jump exits __finally block">; def note_exits_objc_autoreleasepool : Note< "jump exits autoreleasepool block">; def note_exits_objc_strong : Note< "jump exits scope of __strong variable">; def note_exits_objc_weak : Note< "jump exits scope of __weak variable">; def note_exits_block_captures_cxx_obj : Note< "jump exits lifetime of block which captures a destructible C++ object">; def note_exits_block_captures_strong : Note< "jump exits lifetime of block which strongly captures a variable">; def note_exits_block_captures_weak : Note< "jump exits lifetime of block which weakly captures a variable">; def err_func_returning_qualified_void : ExtWarn< "function cannot return qualified void type %0">, InGroup>; def err_func_returning_array_function : Error< "function cannot return %select{array|function}0 type %1">; def err_field_declared_as_function : Error<"field %0 declared as a function">; def err_field_incomplete : Error<"field has incomplete type %0">; def ext_variable_sized_type_in_struct : ExtWarn< "field %0 with variable sized type %1 not at the end of a struct or class is" " a GNU extension">, InGroup; def ext_c99_flexible_array_member : Extension< "flexible array members are a C99 feature">, InGroup; def err_flexible_array_virtual_base : Error< "flexible array member %0 not allowed in " "%select{struct|interface|union|class|enum}1 which has a virtual base class">; def err_flexible_array_empty_aggregate : Error< "flexible array member %0 not allowed in otherwise empty " "%select{struct|interface|union|class|enum}1">; def err_flexible_array_has_nontrivial_dtor : Error< "flexible array member %0 of type %1 with non-trivial destruction">; def ext_flexible_array_in_struct : Extension< "%0 may not be nested in a struct due to flexible array member">, InGroup; def ext_flexible_array_in_array : Extension< "%0 may not be used as an array element due to flexible array member">, InGroup; def err_flexible_array_init : Error< "initialization of flexible array member is not allowed">; def ext_flexible_array_empty_aggregate_ms : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, InGroup; def err_flexible_array_union : Error< "flexible array member %0 in a union is not allowed">; def ext_flexible_array_union_ms : Extension< "flexible array member %0 in a union is a Microsoft extension">, InGroup; def ext_flexible_array_empty_aggregate_gnu : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a GNU extension">, InGroup; def ext_flexible_array_union_gnu : Extension< "flexible array member %0 in a union is a GNU extension">, InGroup; let CategoryName = "ARC Semantic Issue" in { // ARC-mode diagnostics. let CategoryName = "ARC Weak References" in { def err_arc_weak_no_runtime : Error< "cannot create __weak reference because the current deployment target " "does not support weak references">; def err_arc_weak_disabled : Error< "cannot create __weak reference in file using manual reference counting">; def err_synthesizing_arc_weak_property_disabled : Error< "cannot synthesize weak property in file using manual reference counting">; def err_synthesizing_arc_weak_property_no_runtime : Error< "cannot synthesize weak property because the current deployment target " "does not support weak references">; def err_arc_unsupported_weak_class : Error< "class is incompatible with __weak references">; def err_arc_weak_unavailable_assign : Error< "assignment of a weak-unavailable object to a __weak object">; def err_arc_weak_unavailable_property : Error< "synthesizing __weak instance variable of type %0, which does not " "support weak references">; def note_implemented_by_class : Note< "when implemented by class %0">; def err_arc_convesion_of_weak_unavailable : Error< "%select{implicit conversion|cast}0 of weak-unavailable object of type %1 to" " a __weak object of type %2">; } // end "ARC Weak References" category let CategoryName = "ARC Restrictions" in { def err_unavailable_in_arc : Error< "%0 is unavailable in ARC">; def note_arc_forbidden_type : Note< "declaration uses type that is ill-formed in ARC">; def note_performs_forbidden_arc_conversion : Note< "inline function performs a conversion which is forbidden in ARC">; def note_arc_init_returns_unrelated : Note< "init method must return a type related to its receiver type">; def note_arc_weak_disabled : Note< "declaration uses __weak, but ARC is disabled">; def note_arc_weak_no_runtime : Note<"declaration uses __weak, which " "the current deployment target does not support">; def note_arc_field_with_ownership : Note< "field has non-trivial ownership qualification">; def err_arc_illegal_explicit_message : Error< "ARC forbids explicit message send of %0">; def err_arc_unused_init_message : Error< "the result of a delegate init call must be immediately returned " "or assigned to 'self'">; def err_arc_mismatched_cast : Error< "%select{implicit conversion|cast}0 of " "%select{%2|a non-Objective-C pointer type %2|a block pointer|" "an Objective-C pointer|an indirect pointer to an Objective-C pointer}1" " to %3 is disallowed with ARC">; def err_arc_nolifetime_behavior : Error< "explicit ownership qualifier on cast result has no effect">; def err_arc_objc_object_in_tag : Error< "ARC forbids %select{Objective-C objects|blocks}0 in " "%select{struct|interface|union|<>|enum}1">; def err_arc_objc_property_default_assign_on_object : Error< "ARC forbids synthesizing a property of an Objective-C object " "with unspecified ownership or storage attribute">; def err_arc_illegal_selector : Error< "ARC forbids use of %0 in a @selector">; def err_arc_illegal_method_def : Error< "ARC forbids %select{implementation|synthesis}0 of %1">; def warn_arc_strong_pointer_objc_pointer : Warning< "method parameter of type %0 with no explicit ownership">, InGroup>, DefaultIgnore; } // end "ARC Restrictions" category def err_arc_lost_method_convention : Error< "method was declared as %select{an 'alloc'|a 'copy'|an 'init'|a 'new'}0 " "method, but its implementation doesn't match because %select{" "its result type is not an object pointer|" "its result type is unrelated to its receiver type}1">; def note_arc_lost_method_convention : Note<"declaration in interface">; def err_arc_gained_method_convention : Error< "method implementation does not match its declaration">; def note_arc_gained_method_convention : Note< "declaration in interface is not in the '%select{alloc|copy|init|new}0' " "family because %select{its result type is not an object pointer|" "its result type is unrelated to its receiver type}1">; def err_typecheck_arc_assign_self : Error< "cannot assign to 'self' outside of a method in the init family">; def err_typecheck_arc_assign_self_class_method : Error< "cannot assign to 'self' in a class method">; def err_typecheck_arr_assign_enumeration : Error< "fast enumeration variables cannot be modified in ARC by default; " "declare the variable __strong to allow this">; def warn_arc_retained_assign : Warning< "assigning retained object to %select{weak|unsafe_unretained}0 " "%select{property|variable}1" "; object will be released after assignment">, InGroup; def warn_arc_retained_property_assign : Warning< "assigning retained object to unsafe property" "; object will be released after assignment">, InGroup; def warn_arc_literal_assign : Warning< "assigning %select{array literal|dictionary literal|numeric literal|boxed expression||block literal}0" " to a weak %select{property|variable}1" "; object will be released after assignment">, InGroup; def err_arc_new_array_without_ownership : Error< "'new' cannot allocate an array of %0 with no explicit ownership">; def err_arc_autoreleasing_var : Error< "%select{__block variables|global variables|fields|instance variables}0 cannot have " "__autoreleasing ownership">; def err_arc_autoreleasing_capture : Error< "cannot capture __autoreleasing variable in a " "%select{block|lambda by copy}0">; def err_arc_thread_ownership : Error< "thread-local variable has non-trivial ownership: type is %0">; def err_arc_indirect_no_ownership : Error< "%select{pointer|reference}1 to non-const type %0 with no explicit ownership">; def err_arc_array_param_no_ownership : Error< "must explicitly describe intended ownership of an object array parameter">; def err_arc_pseudo_dtor_inconstant_quals : Error< "pseudo-destructor destroys object of type %0 with inconsistently-qualified " "type %1">; def err_arc_init_method_unrelated_result_type : Error< "init methods must return a type related to the receiver type">; def err_arc_nonlocal_writeback : Error< "passing address of %select{non-local|non-scalar}0 object to " "__autoreleasing parameter for write-back">; def err_arc_method_not_found : Error< "no known %select{instance|class}1 method for selector %0">; def err_arc_receiver_forward_class : Error< "receiver %0 for class message is a forward declaration">; def err_arc_may_not_respond : Error< "no visible @interface for %0 declares the selector %1">; def err_arc_receiver_forward_instance : Error< "receiver type %0 for instance message is a forward declaration">; def warn_receiver_forward_instance : Warning< "receiver type %0 for instance message is a forward declaration">, InGroup, DefaultIgnore; def err_arc_collection_forward : Error< "collection expression type %0 is a forward declaration">; def err_arc_multiple_method_decl : Error< "multiple methods named %0 found with mismatched result, " "parameter type or attributes">; def warn_arc_lifetime_result_type : Warning< "ARC %select{unused|__unsafe_unretained|__strong|__weak|__autoreleasing}0 " "lifetime qualifier on return type is ignored">, InGroup; let CategoryName = "ARC Retain Cycle" in { def warn_arc_retain_cycle : Warning< "capturing %0 strongly in this block is likely to lead to a retain cycle">, InGroup; def note_arc_retain_cycle_owner : Note< "block will be retained by %select{the captured object|an object strongly " "retained by the captured object}0">; } // end "ARC Retain Cycle" category def warn_arc_object_memaccess : Warning< "%select{destination for|source of}0 this %1 call is a pointer to " "ownership-qualified type %2">, InGroup; let CategoryName = "ARC and @properties" in { def err_arc_strong_property_ownership : Error< "existing instance variable %1 for strong property %0 may not be " "%select{|__unsafe_unretained||__weak}2">; def err_arc_assign_property_ownership : Error< "existing instance variable %1 for property %0 with %select{unsafe_unretained|assign}2 " "attribute must be __unsafe_unretained">; def err_arc_inconsistent_property_ownership : Error< "%select{|unsafe_unretained|strong|weak}1 property %0 may not also be " "declared %select{|__unsafe_unretained|__strong|__weak|__autoreleasing}2">; } // end "ARC and @properties" category def err_arc_atomic_ownership : Error< "cannot perform atomic operation on a pointer to type %0: type has " "non-trivial ownership">; let CategoryName = "ARC Casting Rules" in { def err_arc_bridge_cast_incompatible : Error< "incompatible types casting %0 to %1 with a %select{__bridge|" "__bridge_transfer|__bridge_retained}2 cast">; def err_arc_bridge_cast_wrong_kind : Error< "cast of %select{Objective-C|block|C}0 pointer type %1 to " "%select{Objective-C|block|C}2 pointer type %3 cannot use %select{__bridge|" "__bridge_transfer|__bridge_retained}4">; def err_arc_cast_requires_bridge : Error< "%select{cast|implicit conversion}0 of %select{Objective-C|block|C}1 " "pointer type %2 to %select{Objective-C|block|C}3 pointer type %4 " "requires a bridged cast">; def note_arc_bridge : Note< "use __bridge to convert directly (no change in ownership)">; def note_arc_cstyle_bridge : Note< "use __bridge with C-style cast to convert directly (no change in ownership)">; def note_arc_bridge_transfer : Note< "use %select{__bridge_transfer|CFBridgingRelease call}1 to transfer " "ownership of a +1 %0 into ARC">; def note_arc_cstyle_bridge_transfer : Note< "use __bridge_transfer with C-style cast to transfer " "ownership of a +1 %0 into ARC">; def note_arc_bridge_retained : Note< "use %select{__bridge_retained|CFBridgingRetain call}1 to make an " "ARC object available as a +1 %0">; def note_arc_cstyle_bridge_retained : Note< "use __bridge_retained with C-style cast to make an " "ARC object available as a +1 %0">; } // ARC Casting category } // ARC category name def err_flexible_array_init_needs_braces : Error< "flexible array requires brace-enclosed initializer">; def err_illegal_decl_array_of_functions : Error< "'%0' declared as array of functions of type %1">; def err_illegal_decl_array_incomplete_type : Error< "array has incomplete element type %0">; def err_illegal_message_expr_incomplete_type : Error< "Objective-C message has incomplete result type %0">; def err_illegal_decl_array_of_references : Error< "'%0' declared as array of references of type %1">; def err_decl_negative_array_size : Error< "'%0' declared as an array with a negative size">; def err_array_static_outside_prototype : Error< "%0 used in array declarator outside of function prototype">; def err_array_static_not_outermost : Error< "%0 used in non-outermost array type derivation">; def err_array_star_outside_prototype : Error< "star modifier used outside of function prototype">; def err_illegal_decl_pointer_to_reference : Error< "'%0' declared as a pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_reference : Error< "'%0' declared as a member pointer to a reference of type %1">; def err_illegal_decl_mempointer_to_void : Error< "'%0' declared as a member pointer to void">; def err_illegal_decl_mempointer_in_nonclass : Error< "'%0' does not point into a class">; def err_mempointer_in_nonclass_type : Error< "member pointer refers into non-class type %0">; def err_reference_to_void : Error<"cannot form a reference to 'void'">; def err_nonfunction_block_type : Error< "block pointer to non-function type is invalid">; def err_return_block_has_expr : Error<"void block should not return a value">; def err_block_return_missing_expr : Error< "non-void block should return a value">; def err_func_def_incomplete_result : Error< "incomplete result type %0 in function definition">; def err_atomic_specifier_bad_type : Error< "_Atomic cannot be applied to " "%select{incomplete |array |function |reference |atomic |qualified |}0type " "%1 %select{||||||which is not trivially copyable}0">; // Expressions. def ext_sizeof_alignof_function_type : Extension< "invalid application of '%select{sizeof|alignof|vec_step}0' to a " "function type">, InGroup; def ext_sizeof_alignof_void_type : Extension< "invalid application of '%select{sizeof|alignof|vec_step}0' to a void " "type">, InGroup; def err_opencl_sizeof_alignof_type : Error< "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to a void type">; def err_sizeof_alignof_incomplete_type : Error< "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to an " "incomplete type %1">; def err_sizeof_alignof_function_type : Error< "invalid application of '%select{sizeof|alignof|vec_step|__builtin_omp_required_simd_align}0' to a " "function type">; def err_openmp_default_simd_align_expr : Error< "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; def err_sizeof_alignof_typeof_bitfield : Error< "invalid application of '%select{sizeof|alignof|typeof}0' to bit-field">; def err_alignof_member_of_incomplete_type : Error< "invalid application of 'alignof' to a field of a class still being defined">; def err_vecstep_non_scalar_vector_type : Error< "'vec_step' requires built-in scalar or vector type, %0 invalid">; def err_offsetof_incomplete_type : Error< "offsetof of incomplete type %0">; def err_offsetof_record_type : Error< "offsetof requires struct, union, or class type, %0 invalid">; def err_offsetof_array_type : Error<"offsetof requires array type, %0 invalid">; def ext_offsetof_extended_field_designator : Extension< "using extended field designator is an extension">, InGroup>; def ext_offsetof_non_pod_type : ExtWarn<"offset of on non-POD type %0">, InGroup; def ext_offsetof_non_standardlayout_type : ExtWarn< "offset of on non-standard-layout type %0">, InGroup; def err_offsetof_bitfield : Error<"cannot compute offset of bit-field %0">; def err_offsetof_field_of_virtual_base : Error< "invalid application of 'offsetof' to a field of a virtual base">; def warn_sub_ptr_zero_size_types : Warning< "subtraction of pointers to type %0 of zero size has undefined behavior">, InGroup; def warn_floatingpoint_eq : Warning< "comparing floating point with == or != is unsafe">, InGroup>, DefaultIgnore; def warn_remainder_division_by_zero : Warning< "%select{remainder|division}0 by zero is undefined">, InGroup; def warn_shift_lhs_negative : Warning<"shifting a negative signed value is undefined">, InGroup>; def warn_shift_negative : Warning<"shift count is negative">, InGroup>; def warn_shift_gt_typewidth : Warning<"shift count >= width of type">, InGroup>; def warn_shift_result_gt_typewidth : Warning< "signed shift result (%0) requires %1 bits to represent, but %2 only has " "%3 bits">, InGroup>; def warn_shift_result_sets_sign_bit : Warning< "signed shift result (%0) sets the sign bit of the shift expression's " "type (%1) and becomes negative">, InGroup>, DefaultIgnore; def warn_precedence_bitwise_rel : Warning< "%0 has lower precedence than %1; %1 will be evaluated first">, InGroup; def note_precedence_bitwise_first : Note< "place parentheses around the %0 expression to evaluate it first">; def note_precedence_silence : Note< "place parentheses around the '%0' expression to silence this warning">; def warn_precedence_conditional : Warning< "operator '?:' has lower precedence than '%0'; '%0' will be evaluated first">, InGroup; def note_precedence_conditional_first : Note< "place parentheses around the '?:' expression to evaluate it first">; def warn_logical_instead_of_bitwise : Warning< "use of logical '%0' with constant operand">, InGroup>; def note_logical_instead_of_bitwise_change_operator : Note< "use '%0' for a bitwise operation">; def note_logical_instead_of_bitwise_remove_constant : Note< "remove constant to silence this warning">; def warn_bitwise_op_in_bitwise_op : Warning< "'%0' within '%1'">, InGroup; def warn_logical_and_in_logical_or : Warning< "'&&' within '||'">, InGroup; def warn_overloaded_shift_in_comparison :Warning< "overloaded operator %select{>>|<<}0 has higher precedence than " "comparison operator">, InGroup; def note_evaluate_comparison_first :Note< "place parentheses around comparison expression to evaluate it first">; def warn_addition_in_bitshift : Warning< "operator '%0' has lower precedence than '%1'; " "'%1' will be evaluated first">, InGroup; def warn_self_assignment : Warning< "explicitly assigning value of variable of type %0 to itself">, InGroup, DefaultIgnore; def warn_self_move : Warning< "explicitly moving variable of type %0 to itself">, InGroup, DefaultIgnore; def warn_redundant_move_on_return : Warning< "redundant move in return statement">, InGroup, DefaultIgnore; def warn_pessimizing_move_on_return : Warning< "moving a local object in a return statement prevents copy elision">, InGroup, DefaultIgnore; def warn_pessimizing_move_on_initialization : Warning< "moving a temporary object prevents copy elision">, InGroup, DefaultIgnore; def note_remove_move : Note<"remove std::move call here">; def warn_string_plus_int : Warning< "adding %0 to a string does not append to the string">, InGroup; def warn_string_plus_char : Warning< "adding %0 to a string pointer does not append to the string">, InGroup; def note_string_plus_scalar_silence : Note< "use array indexing to silence this warning">; def warn_sizeof_array_param : Warning< "sizeof on array function parameter will return size of %0 instead of %1">, InGroup; def warn_sizeof_array_decay : Warning< "sizeof on pointer operation will return size of %0 instead of %1">, InGroup; def err_sizeof_nonfragile_interface : Error< "application of '%select{alignof|sizeof}1' to interface %0 is " "not supported on this architecture and platform">; def err_atdef_nonfragile_interface : Error< "use of @defs is not supported on this architecture and platform">; def err_subscript_nonfragile_interface : Error< "subscript requires size of interface %0, which is not constant for " "this architecture and platform">; def err_arithmetic_nonfragile_interface : Error< "arithmetic on pointer to interface %0, which is not a constant size for " "this architecture and platform">; def ext_subscript_non_lvalue : Extension< "ISO C90 does not allow subscripting non-lvalue array">; def err_typecheck_subscript_value : Error< "subscripted value is not an array, pointer, or vector">; def err_typecheck_subscript_not_integer : Error< "array subscript is not an integer">; def err_subscript_function_type : Error< "subscript of pointer to function type %0">; def err_subscript_incomplete_type : Error< "subscript of pointer to incomplete type %0">; def err_dereference_incomplete_type : Error< "dereference of pointer to incomplete type %0">; def ext_gnu_subscript_void_type : Extension< "subscript of a pointer to void is a GNU extension">, InGroup; def err_typecheck_member_reference_struct_union : Error< "member reference base type %0 is not a structure or union">; def err_typecheck_member_reference_ivar : Error< "%0 does not have a member named %1">; def error_arc_weak_ivar_access : Error< "dereferencing a __weak pointer is not allowed due to possible " "null value caused by race condition, assign it to strong variable first">; def err_typecheck_member_reference_arrow : Error< "member reference type %0 is not a pointer">; def err_typecheck_member_reference_suggestion : Error< "member reference type %0 is %select{a|not a}1 pointer; did you mean to use '%select{->|.}1'?">; def note_typecheck_member_reference_suggestion : Note< "did you mean to use '.' instead?">; def note_member_reference_arrow_from_operator_arrow : Note< "'->' applied to return value of the operator->() declared here">; def err_typecheck_member_reference_type : Error< "cannot refer to type member %0 in %1 with '%select{.|->}2'">; def err_typecheck_member_reference_unknown : Error< "cannot refer to member %0 in %1 with '%select{.|->}2'">; def err_member_reference_needs_call : Error< "base of member reference is a function; perhaps you meant to call " "it%select{| with no arguments}0?">; def warn_subscript_is_char : Warning<"array subscript is of type 'char'">, InGroup, DefaultIgnore; def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">; def err_no_member : Error<"no member named %0 in %1">; def err_no_member_overloaded_arrow : Error< "no member named %0 in %1; did you mean to use '->' instead of '.'?">; def err_member_not_yet_instantiated : Error< "no member %0 in %1; it has not yet been instantiated">; def note_non_instantiated_member_here : Note< "not-yet-instantiated member is declared here">; def err_enumerator_does_not_exist : Error< "enumerator %0 does not exist in instantiation of %1">; def note_enum_specialized_here : Note< "enum %0 was explicitly specialized here">; def err_member_redeclared : Error<"class member cannot be redeclared">; def ext_member_redeclared : ExtWarn<"class member cannot be redeclared">, InGroup; def err_member_redeclared_in_instantiation : Error< "multiple overloads of %0 instantiate to the same signature %1">; def err_member_name_of_class : Error<"member %0 has the same name as its class">; def err_member_def_undefined_record : Error< "out-of-line definition of %0 from class %1 without definition">; def err_member_decl_does_not_match : Error< "out-of-line %select{declaration|definition}2 of %0 " "does not match any declaration in %1">; def err_friend_decl_with_def_arg_must_be_def : Error< "friend declaration specifying a default argument must be a definition">; def err_friend_decl_with_def_arg_redeclared : Error< "friend declaration specifying a default argument must be the only declaration">; def err_friend_decl_does_not_match : Error< "friend declaration of %0 does not match any declaration in %1">; def err_member_decl_does_not_match_suggest : Error< "out-of-line %select{declaration|definition}2 of %0 " "does not match any declaration in %1; did you mean %3?">; def err_member_def_does_not_match_ret_type : Error< "return type of out-of-line definition of %q0 differs from " "that in the declaration">; def err_nonstatic_member_out_of_line : Error< "non-static data member defined out-of-line">; def err_qualified_typedef_declarator : Error< "typedef declarator cannot be qualified">; def err_qualified_param_declarator : Error< "parameter declarator cannot be qualified">; def ext_out_of_line_declaration : ExtWarn< "out-of-line declaration of a member must be a definition">, InGroup, DefaultError; def err_member_extra_qualification : Error< "extra qualification on member %0">; def warn_member_extra_qualification : Warning< err_member_extra_qualification.Text>, InGroup; def warn_namespace_member_extra_qualification : Warning< "extra qualification on member %0">, InGroup>; def err_member_qualification : Error< "non-friend class member %0 cannot have a qualified name">; def note_member_def_close_match : Note<"member declaration nearly matches">; def note_member_def_close_const_match : Note< "member declaration does not match because " "it %select{is|is not}0 const qualified">; def note_member_def_close_param_match : Note< "type of %ordinal0 parameter of member declaration does not match definition" "%diff{ ($ vs $)|}1,2">; def note_local_decl_close_match : Note<"local declaration nearly matches">; def note_local_decl_close_param_match : Note< "type of %ordinal0 parameter of local declaration does not match definition" "%diff{ ($ vs $)|}1,2">; def err_typecheck_ivar_variable_size : Error< "instance variables must have a constant size">; def err_ivar_reference_type : Error< "instance variables cannot be of reference type">; def err_typecheck_illegal_increment_decrement : Error< "cannot %select{decrement|increment}1 value of type %0">; def err_typecheck_expect_int : Error< "used type %0 where integer is required">; def err_typecheck_arithmetic_incomplete_type : Error< "arithmetic on a pointer to an incomplete type %0">; def err_typecheck_pointer_arith_function_type : Error< "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 " "function type%select{|s}2 %1%select{| and %3}2">; def err_typecheck_pointer_arith_void_type : Error< "arithmetic on%select{ a|}0 pointer%select{|s}0 to void">; def err_typecheck_decl_incomplete_type : Error< "variable has incomplete type %0">; def ext_typecheck_decl_incomplete_type : ExtWarn< "tentative definition of variable with internal linkage has incomplete non-array type %0">, InGroup>; def err_tentative_def_incomplete_type : Error< "tentative definition has type %0 that is never completed">; def warn_tentative_incomplete_array : Warning< "tentative array definition assumed to have one element">; def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; def err_array_init_not_init_list : Error< "array initializer must be an initializer " "list%select{| or string literal| or wide string literal}0">; def err_array_init_narrow_string_into_wchar : Error< "initializing wide char array with non-wide string literal">; def err_array_init_wide_string_into_char : Error< "initializing char array with wide string literal">; def err_array_init_incompat_wide_string_into_wchar : Error< "initializing wide char array with incompatible wide string literal">; def err_array_init_different_type : Error< "cannot initialize array %diff{of type $ with array of type $|" "with different type of array}0,1">; def err_array_init_non_constant_array : Error< "cannot initialize array %diff{of type $ with non-constant array of type $|" "with different type of array}0,1">; def ext_array_init_copy : Extension< "initialization of an array " "%diff{of type $ from a compound literal of type $|" "from a compound literal}0,1 is a GNU extension">, InGroup; // This is intentionally not disabled by -Wno-gnu. def ext_array_init_parens : ExtWarn< "parenthesized initialization of a member array is a GNU extension">, InGroup>, DefaultError; def warn_deprecated_string_literal_conversion : Warning< "conversion from string literal to %0 is deprecated">, InGroup; def ext_deprecated_string_literal_conversion : ExtWarn< "ISO C++11 does not allow conversion from string literal to %0">, InGroup, SFINAEFailure; def err_realimag_invalid_type : Error<"invalid type %0 to %1 operator">; def err_typecheck_sclass_fscope : Error< "illegal storage class on file-scoped variable">; def warn_standalone_specifier : Warning<"'%0' ignored on this declaration">, InGroup; def ext_standalone_specifier : ExtWarn<"'%0' is not permitted on a declaration " "of a type">, InGroup; def err_standalone_class_nested_name_specifier : Error< "forward declaration of %select{class|struct|interface|union|enum}0 cannot " "have a nested name specifier">; def err_typecheck_sclass_func : Error<"illegal storage class on function">; def err_static_block_func : Error< "function declared in block scope cannot have 'static' storage class">; def err_typecheck_address_of : Error<"address of %select{bit-field" "|vector element|property expression|register variable}0 requested">; def ext_typecheck_addrof_void : Extension< "ISO C forbids taking the address of an expression of type 'void'">; def err_unqualified_pointer_member_function : Error< "must explicitly qualify name of member function when taking its address">; def err_invalid_form_pointer_member_function : Error< "cannot create a non-constant pointer to member function">; def err_address_of_function_with_pass_object_size_params: Error< "cannot take address of function %0 because parameter %1 has " "pass_object_size attribute">; def err_parens_pointer_member_function : Error< "cannot parenthesize the name of a method when forming a member pointer">; def err_typecheck_invalid_lvalue_addrof_addrof_function : Error< "extra '&' taking address of overloaded function">; def err_typecheck_invalid_lvalue_addrof : Error< "cannot take the address of an rvalue of type %0">; def ext_typecheck_addrof_temporary : ExtWarn< "taking the address of a temporary object of type %0">, InGroup>, DefaultError; def err_typecheck_addrof_temporary : Error< "taking the address of a temporary object of type %0">; def err_typecheck_addrof_dtor : Error< "taking the address of a destructor">; def err_typecheck_unary_expr : Error< "invalid argument type %0 to unary expression">; def err_typecheck_indirection_requires_pointer : Error< "indirection requires pointer operand (%0 invalid)">; def ext_typecheck_indirection_through_void_pointer : ExtWarn< "ISO C++ does not allow indirection on operand of type %0">, InGroup>; def warn_indirection_through_null : Warning< "indirection of non-volatile null pointer will be deleted, not trap">, InGroup; def warn_binding_null_to_reference : Warning< "binding dereferenced null pointer to reference has undefined behavior">, InGroup; def note_indirection_through_null : Note< "consider using __builtin_trap() or qualifying pointer with 'volatile'">; def warn_pointer_indirection_from_incompatible_type : Warning< "dereference of type %1 that was reinterpret_cast from type %0 has undefined " "behavior">, InGroup, DefaultIgnore; def err_objc_object_assignment : Error< "cannot assign to class object (%0 invalid)">; def err_typecheck_invalid_operands : Error< "invalid operands to binary expression (%0 and %1)">; def err_typecheck_sub_ptr_compatible : Error< "%diff{$ and $ are not pointers to compatible types|" "pointers to incompatible types}0,1">; def ext_typecheck_ordered_comparison_of_pointer_integer : ExtWarn< "ordered comparison between pointer and integer (%0 and %1)">; def ext_typecheck_ordered_comparison_of_pointer_and_zero : Extension< "ordered comparison between pointer and zero (%0 and %1) is an extension">; def ext_typecheck_ordered_comparison_of_function_pointers : ExtWarn< "ordered comparison of function pointers (%0 and %1)">; def ext_typecheck_comparison_of_fptr_to_void : Extension< "equality comparison between function pointer and void pointer (%0 and %1)">; def err_typecheck_comparison_of_fptr_to_void : Error< "equality comparison between function pointer and void pointer (%0 and %1)">; def ext_typecheck_comparison_of_pointer_integer : ExtWarn< "comparison between pointer and integer (%0 and %1)">; def err_typecheck_comparison_of_pointer_integer : Error< "comparison between pointer and integer (%0 and %1)">; def ext_typecheck_comparison_of_distinct_pointers : ExtWarn< "comparison of distinct pointer types%diff{ ($ and $)|}0,1">, InGroup; def ext_typecheck_cond_incompatible_operands : ExtWarn< "incompatible operand types (%0 and %1)">; def err_cond_voidptr_arc : Error < "operands to conditional of types%diff{ $ and $|}0,1 are incompatible " "in ARC mode">; def err_typecheck_comparison_of_distinct_pointers : Error< "comparison of distinct pointer types%diff{ ($ and $)|}0,1">; def ext_typecheck_comparison_of_distinct_pointers_nonstandard : ExtWarn< "comparison of distinct pointer types (%0 and %1) uses non-standard " "composite pointer type %2">, InGroup; def err_typecheck_op_on_nonoverlapping_address_space_pointers : Error< "%select{comparison between %diff{ ($ and $)|}0,1" "|arithmetic operation with operands of type %diff{ ($ and $)|}0,1" "|conditional operator with the second and third operands of type " "%diff{ ($ and $)|}0,1}2" " which are pointers to non-overlapping address spaces">; def err_typecheck_assign_const : Error< "%select{" "cannot assign to return value because function %1 returns a const value|" "cannot assign to variable %1 with const-qualified type %2|" "cannot assign to %select{non-|}1static data member %2 " "with const-qualified type %3|" "cannot assign to non-static data member within const member function %1|" "read-only variable is not assignable}0">; def note_typecheck_assign_const : Note< "%select{" "function %1 which returns const-qualified type %2 declared here|" "variable %1 declared const here|" "%select{non-|}1static data member %2 declared const here|" "member function %q1 is declared const here}0">; def warn_mixed_sign_comparison : Warning< "comparison of integers of different signs: %0 and %1">, InGroup, DefaultIgnore; def warn_lunsigned_always_true_comparison : Warning< "comparison of unsigned%select{| enum}2 expression %0 is always %1">, InGroup; def warn_out_of_range_compare : Warning< "comparison of %select{constant %0|true|false}1 with " "%select{expression of type %2|boolean expression}3 is always " "%select{false|true}4">, InGroup; def warn_runsigned_always_true_comparison : Warning< "comparison of %0 unsigned%select{| enum}2 expression is always %1">, InGroup; def warn_comparison_of_mixed_enum_types : Warning< "comparison of two values with different enumeration types" "%diff{ ($ and $)|}0,1">, InGroup>; def warn_null_in_arithmetic_operation : Warning< "use of NULL in arithmetic operation">, InGroup; def warn_null_in_comparison_operation : Warning< "comparison between NULL and non-pointer " "%select{(%1 and NULL)|(NULL and %1)}0">, InGroup; def err_shift_rhs_only_vector : Error< "requested shift is a vector of type %0 but the first operand is not a " "vector (%1)">; def warn_logical_not_on_lhs_of_comparison : Warning< "logical not is only applied to the left hand side of this comparison">, InGroup; def note_logical_not_fix : Note< "add parentheses after the '!' to evaluate the comparison first">; def note_logical_not_silence_with_parens : Note< "add parentheses around left hand side expression to silence this warning">; def err_invalid_this_use : Error< "invalid use of 'this' outside of a non-static member function">; def err_this_static_member_func : Error< "'this' cannot be%select{| implicitly}0 used in a static member function " "declaration">; def err_invalid_member_use_in_static_method : Error< "invalid use of member %0 in static member function">; def err_invalid_qualified_function_type : Error< "%select{static |non-}0member function %select{of type %2 |}1" "cannot have '%3' qualifier">; def err_compound_qualified_function_type : Error< "%select{block pointer|pointer|reference}0 to function type %select{%2 |}1" "cannot have '%3' qualifier">; def err_ref_qualifier_overload : Error< "cannot overload a member function %select{without a ref-qualifier|with " "ref-qualifier '&'|with ref-qualifier '&&'}0 with a member function %select{" "without a ref-qualifier|with ref-qualifier '&'|with ref-qualifier '&&'}1">; def err_invalid_non_static_member_use : Error< "invalid use of non-static data member %0">; def err_nested_non_static_member_use : Error< "%select{call to non-static member function|use of non-static data member}0 " "%2 of %1 from nested type %3">; def warn_cxx98_compat_non_static_member_use : Warning< "use of non-static data member %0 in an unevaluated context is " "incompatible with C++98">, InGroup, DefaultIgnore; def err_invalid_incomplete_type_use : Error< "invalid use of incomplete type %0">; def err_builtin_func_cast_more_than_one_arg : Error< "function-style cast to a builtin type can only take one argument">; def err_value_init_for_array_type : Error< "array types cannot be value-initialized">; def err_value_init_for_function_type : Error< "function types cannot be value-initialized">; def warn_format_nonliteral_noargs : Warning< "format string is not a string literal (potentially insecure)">, InGroup; def warn_format_nonliteral : Warning< "format string is not a string literal">, InGroup, DefaultIgnore; def err_unexpected_interface : Error< "unexpected interface name %0: expected expression">; def err_ref_non_value : Error<"%0 does not refer to a value">; def err_ref_vm_type : Error< "cannot refer to declaration with a variably modified type inside block">; def err_ref_flexarray_type : Error< "cannot refer to declaration of structure variable with flexible array member " "inside block">; def err_ref_array_type : Error< "cannot refer to declaration with an array type inside block">; def err_property_not_found : Error< "property %0 not found on object of type %1">; def err_invalid_property_name : Error< "%0 is not a valid property name (accessing an object of type %1)">; def err_getter_not_found : Error< "no getter method for read from property">; def err_objc_subscript_method_not_found : Error< "expected method to %select{read|write}1 %select{dictionary|array}2 element not " "found on object of type %0">; def err_objc_subscript_index_type : Error< "method index parameter type %0 is not integral type">; def err_objc_subscript_key_type : Error< "method key parameter type %0 is not object type">; def err_objc_subscript_dic_object_type : Error< "method object parameter type %0 is not object type">; def err_objc_subscript_object_type : Error< "cannot assign to this %select{dictionary|array}1 because assigning method's " "2nd parameter of type %0 is not an Objective-C pointer type">; def err_objc_subscript_base_type : Error< "%select{dictionary|array}1 subscript base type %0 is not an Objective-C object">; def err_objc_multiple_subscript_type_conversion : Error< "indexing expression is invalid because subscript type %0 has " "multiple type conversion functions">; def err_objc_subscript_type_conversion : Error< "indexing expression is invalid because subscript type %0 is not an integral" " or Objective-C pointer type">; def err_objc_subscript_pointer : Error< "indexing expression is invalid because subscript type %0 is not an" " Objective-C pointer">; def err_objc_indexing_method_result_type : Error< "method for accessing %select{dictionary|array}1 element must have Objective-C" " object return type instead of %0">; def err_objc_index_incomplete_class_type : Error< "Objective-C index expression has incomplete class type %0">; def err_illegal_container_subscripting_op : Error< "illegal operation on Objective-C container subscripting">; def err_property_not_found_forward_class : Error< "property %0 cannot be found in forward class object %1">; def err_property_not_as_forward_class : Error< "property %0 refers to an incomplete Objective-C class %1 " "(with no @interface available)">; def note_forward_class : Note< "forward declaration of class here">; def err_duplicate_property : Error< "property has a previous declaration">; def ext_gnu_void_ptr : Extension< "arithmetic on%select{ a|}0 pointer%select{|s}0 to void is a GNU extension">, InGroup; def ext_gnu_ptr_func_arith : Extension< "arithmetic on%select{ a|}0 pointer%select{|s}0 to%select{ the|}2 function " "type%select{|s}2 %1%select{| and %3}2 is a GNU extension">, InGroup; def error_readonly_message_assignment : Error< "assigning to 'readonly' return result of an Objective-C message not allowed">; def ext_integer_increment_complex : Extension< "ISO C does not support '++'/'--' on complex integer type %0">; def ext_integer_complement_complex : Extension< "ISO C does not support '~' for complex conjugation of %0">; def err_nosetter_property_assignment : Error< "%select{assignment to readonly property|" "no setter method %1 for assignment to property}0">; def err_nosetter_property_incdec : Error< "%select{%select{increment|decrement}1 of readonly property|" "no setter method %2 for %select{increment|decrement}1 of property}0">; def err_nogetter_property_compound_assignment : Error< "a getter method is needed to perform a compound assignment on a property">; def err_nogetter_property_incdec : Error< "no getter method %1 for %select{increment|decrement}0 of property">; def error_no_subobject_property_setting : Error< "expression is not assignable">; def err_qualified_objc_access : Error< "%select{property|instance variable}0 access cannot be qualified with '%1'">; def ext_freestanding_complex : Extension< "complex numbers are an extension in a freestanding C99 implementation">; // FIXME: Remove when we support imaginary. def err_imaginary_not_supported : Error<"imaginary types are not supported">; // Obj-c expressions def warn_root_inst_method_not_found : Warning< "instance method %0 is being used on 'Class' which is not in the root class">, InGroup; def warn_class_method_not_found : Warning< "class method %objcclass0 not found (return type defaults to 'id')">, InGroup; def warn_instance_method_on_class_found : Warning< "instance method %0 found instead of class method %1">, InGroup; def warn_inst_method_not_found : Warning< "instance method %objcinstance0 not found (return type defaults to 'id')">, InGroup; def warn_instance_method_not_found_with_typo : Warning< "instance method %objcinstance0 not found (return type defaults to 'id')" "; did you mean %objcinstance2?">, InGroup; def warn_class_method_not_found_with_typo : Warning< "class method %objcclass0 not found (return type defaults to 'id')" "; did you mean %objcclass2?">, InGroup; def error_method_not_found_with_typo : Error< "%select{instance|class}1 method %0 not found " "; did you mean %2?">; def error_no_super_class_message : Error< "no @interface declaration found in class messaging of %0">; def error_root_class_cannot_use_super : Error< "%0 cannot use 'super' because it is a root class">; def err_invalid_receiver_to_message_super : Error< "'super' is only valid in a method body">; def err_invalid_receiver_class_message : Error< "receiver type %0 is not an Objective-C class">; def err_missing_open_square_message_send : Error< "missing '[' at start of message send expression">; def warn_bad_receiver_type : Warning< "receiver type %0 is not 'id' or interface pointer, consider " "casting it to 'id'">,InGroup; def err_bad_receiver_type : Error<"bad receiver type %0">; def err_incomplete_receiver_type : Error<"incomplete receiver type %0">; def err_unknown_receiver_suggest : Error< "unknown receiver %0; did you mean %1?">; def error_objc_throw_expects_object : Error< "@throw requires an Objective-C object type (%0 invalid)">; def error_objc_synchronized_expects_object : Error< "@synchronized requires an Objective-C object type (%0 invalid)">; def error_rethrow_used_outside_catch : Error< "@throw (rethrow) used outside of a @catch block">; def err_attribute_multiple_objc_gc : Error< "multiple garbage collection attributes specified for type">; def err_catch_param_not_objc_type : Error< "@catch parameter is not a pointer to an interface type">; def err_illegal_qualifiers_on_catch_parm : Error< "illegal qualifiers on @catch parameter">; def err_storage_spec_on_catch_parm : Error< "@catch parameter cannot have storage specifier '%0'">; def warn_register_objc_catch_parm : Warning< "'register' storage specifier on @catch parameter will be ignored">; def err_qualified_objc_catch_parm : Error< "@catch parameter declarator cannot be qualified">; def warn_objc_pointer_cxx_catch_fragile : Warning< "cannot catch an exception thrown with @throw in C++ in the non-unified " "exception model">, InGroup; def err_objc_object_catch : Error< "cannot catch an Objective-C object by value">; def err_incomplete_type_objc_at_encode : Error< "'@encode' of incomplete type %0">; def warn_objc_circular_container : Warning< "adding '%0' to '%1' might cause circular dependency in container">, InGroup>; def note_objc_circular_container_declared_here : Note<"'%0' declared here">; def warn_setter_getter_impl_required : Warning< "property %0 requires method %1 to be defined - " "use @synthesize, @dynamic or provide a method implementation " "in this class implementation">, InGroup; def warn_setter_getter_impl_required_in_category : Warning< "property %0 requires method %1 to be defined - " "use @dynamic or provide a method implementation in this category">, InGroup; def note_parameter_named_here : Note< "passing argument to parameter %0 here">; def note_parameter_here : Note< "passing argument to parameter here">; def note_method_return_type_change : Note< "compiler has implicitly changed method %0 return type">; def warn_impl_required_for_class_property : Warning< "class property %0 requires method %1 to be defined - " "use @dynamic or provide a method implementation " "in this class implementation">, InGroup; def warn_impl_required_in_category_for_class_property : Warning< "class property %0 requires method %1 to be defined - " "use @dynamic or provide a method implementation in this category">, InGroup; // C++ casts // These messages adhere to the TryCast pattern: %0 is an int specifying the // cast type, %1 is the source type, %2 is the destination type. def err_bad_reinterpret_cast_overload : Error< "reinterpret_cast cannot resolve overloaded function %0 to type %1">; def warn_reinterpret_different_from_static : Warning< "'reinterpret_cast' %select{from|to}3 class %0 %select{to|from}3 its " "%select{virtual base|base at non-zero offset}2 %1 behaves differently from " "'static_cast'">, InGroup; def note_reinterpret_updowncast_use_static: Note< "use 'static_cast' to adjust the pointer correctly while " "%select{upcasting|downcasting}0">; def err_bad_static_cast_overload : Error< "address of overloaded function %0 cannot be static_cast to type %1">; def err_bad_cstyle_cast_overload : Error< "address of overloaded function %0 cannot be cast to type %1">; def err_bad_cxx_cast_generic : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 is not allowed">; def err_bad_cxx_cast_unrelated_class : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2, which are not related by " "inheritance, is not allowed">; def note_type_incomplete : Note<"%0 is incomplete">; def err_bad_cxx_cast_rvalue : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from rvalue to reference type %2">; def err_bad_cxx_cast_bitfield : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from bit-field lvalue to reference type %2">; def err_bad_cxx_cast_qualifiers_away : Error< "%select{const_cast|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" "functional-style cast}0 from %1 to %2 casts away qualifiers">; def err_bad_const_cast_dest : Error< "%select{const_cast||||C-style cast|functional-style cast}0 to %2, " "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 ext_ms_cast_fn_obj : ExtWarn< "static_cast between pointer-to-function and pointer-to-object is a " "Microsoft extension">, InGroup; 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< "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to scalar %2 of different size">; def err_bad_cxx_cast_scalar_to_vector_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from scalar %1 " "to vector %2 of different size">; def err_bad_cxx_cast_vector_to_vector_different_size : Error< "%select{||reinterpret_cast||C-style cast|}0 from vector %1 " "to vector %2 of different size">; def err_bad_lvalue_to_rvalue_cast : Error< "cannot cast from lvalue of type %1 to rvalue reference type %2; types are " "not compatible">; def err_bad_static_cast_pointer_nonpointer : Error< "cannot cast from type %1 to pointer type %2">; def err_bad_static_cast_member_pointer_nonmp : Error< "cannot cast from type %1 to member pointer type %2">; def err_bad_cxx_cast_member_pointer_size : Error< "cannot %select{||reinterpret_cast||C-style cast|}0 from member pointer " "type %1 to member pointer type %2 of different size">; def err_bad_reinterpret_cast_reference : Error< "reinterpret_cast of a %0 to %1 needs its address, which is not allowed">; def warn_undefined_reinterpret_cast : Warning< "reinterpret_cast from %0 to %1 has undefined behavior">, InGroup, DefaultIgnore; // These messages don't adhere to the pattern. // FIXME: Display the path somehow better. def err_ambiguous_base_to_derived_cast : Error< "ambiguous cast from base %0 to derived %1:%2">; def err_static_downcast_via_virtual : Error< "cannot cast %0 to %1 via virtual base %2">; def err_downcast_from_inaccessible_base : Error< "cannot cast %select{private|protected}2 base class %1 to %0">; def err_upcast_to_inaccessible_base : Error< "cannot cast %0 to its %select{private|protected}2 base class %1">; def err_bad_dynamic_cast_not_ref_or_ptr : Error< "%0 is not a reference or pointer">; def err_bad_dynamic_cast_not_class : Error<"%0 is not a class">; def err_bad_dynamic_cast_incomplete : Error<"%0 is an incomplete type">; def err_bad_dynamic_cast_not_ptr : Error<"%0 is not a pointer">; def err_bad_dynamic_cast_not_polymorphic : Error<"%0 is not polymorphic">; // Other C++ expressions def err_need_header_before_typeid : Error< "you need to include before using the 'typeid' operator">; def err_need_header_before_ms_uuidof : Error< "you need to include before using the '__uuidof' operator">; def err_ms___leave_not_in___try : Error< "'__leave' statement not in __try block">; def err_uuidof_without_guid : Error< "cannot call operator __uuidof on a type with no GUID">; def err_uuidof_with_multiple_guids : Error< "cannot call operator __uuidof on a type with multiple GUIDs">; def err_incomplete_typeid : Error<"'typeid' of incomplete type %0">; def err_variably_modified_typeid : Error<"'typeid' of variably modified type %0">; def err_static_illegal_in_new : Error< "the 'static' modifier for the array size is not legal in new expressions">; def err_array_new_needs_size : Error< "array size must be specified in new expressions">; def err_bad_new_type : Error< "cannot allocate %select{function|reference}1 type %0 with new">; def err_new_incomplete_type : Error< "allocation of incomplete type %0">; def err_new_array_nonconst : Error< "only the first dimension of an allocated array may have dynamic size">; def err_new_array_init_args : Error< "array 'new' cannot have initialization arguments">; def ext_new_paren_array_nonconst : ExtWarn< "when type is in parentheses, array cannot have dynamic size">; def err_placement_new_non_placement_delete : Error< "'new' expression with placement arguments refers to non-placement " "'operator delete'">; def err_array_size_not_integral : Error< "array size expression must have integral or %select{|unscoped }0" "enumeration type, not %1">; def err_array_size_incomplete_type : Error< "array size expression has incomplete class type %0">; def err_array_size_explicit_conversion : Error< "array size expression of type %0 requires explicit conversion to type %1">; def note_array_size_conversion : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_array_size_ambiguous_conversion : Error< "ambiguous conversion of array size expression of type %0 to an integral or " "enumeration type">; 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< "'delete' cannot delete objects of type %0 in address space '%1'">; def err_default_init_const : Error< "default initialization of an object of const type %0" "%select{| without a user-provided default constructor}1">; def ext_default_init_const : ExtWarn< "default initialization of an object of const type %0" "%select{| without a user-provided default constructor}1 " "is a Microsoft extension">, InGroup; def err_delete_operand : Error<"cannot delete expression of type %0">; def ext_delete_void_ptr_operand : ExtWarn< "cannot delete expression with pointer-to-'void' type %0">, InGroup; def err_ambiguous_delete_operand : Error< "ambiguous conversion of delete expression of type %0 to a pointer">; def warn_delete_incomplete : Warning< "deleting pointer to incomplete type %0 may cause undefined behavior">, InGroup; def err_delete_incomplete_class_type : Error< "deleting incomplete class type %0; no conversions to pointer type">; def err_delete_explicit_conversion : Error< "converting delete expression from type %0 to type %1 invokes an explicit " "conversion function">; def note_delete_conversion : Note<"conversion to pointer type %0">; def warn_delete_array_type : Warning< "'delete' applied to a pointer-to-array type %0 treated as 'delete[]'">; def warn_mismatched_delete_new : Warning< "'delete%select{|[]}0' applied to a pointer that was allocated with " "'new%select{[]|}0'; did you mean 'delete%select{[]|}0'?">, InGroup>; def note_allocated_here : Note<"allocated with 'new%select{[]|}0' here">; def err_no_suitable_delete_member_function_found : Error< "no suitable member %0 in %1">; def err_ambiguous_suitable_delete_member_function_found : Error< "multiple suitable %0 functions in %1">; def note_member_declared_here : Note< "member %0 declared here">; def err_decrement_bool : Error<"cannot decrement expression of type bool">; def warn_increment_bool : Warning< "incrementing expression of type bool is deprecated and " "incompatible with C++1z">, InGroup; def ext_increment_bool : ExtWarn< "ISO C++1z does not allow incrementing expression of type bool">, DefaultError, InGroup; def err_increment_decrement_enum : Error< "cannot %select{decrement|increment}0 expression of enum type %1">; def err_catch_incomplete_ptr : Error< "cannot catch pointer to incomplete type %0">; def err_catch_incomplete_ref : Error< "cannot catch reference to incomplete type %0">; def err_catch_incomplete : Error<"cannot catch incomplete type %0">; def err_catch_rvalue_ref : Error<"cannot catch exceptions by rvalue reference">; def err_catch_variably_modified : Error< "cannot catch variably modified type %0">; def err_qualified_catch_declarator : Error< "exception declarator cannot be qualified">; def err_early_catch_all : Error<"catch-all handler must come last">; def err_bad_memptr_rhs : Error< "right hand operand to %0 has non-pointer-to-member type %1">; def err_bad_memptr_lhs : Error< "left hand operand to %0 must be a %select{|pointer to }1class " "compatible with the right hand operand, but is %2">; def warn_exception_caught_by_earlier_handler : Warning< "exception of type %0 will be caught by earlier handler">, InGroup; def note_previous_exception_handler : Note<"for type %0">; def err_exceptions_disabled : Error< "cannot use '%0' with exceptions disabled">; def err_objc_exceptions_disabled : Error< "cannot use '%0' with Objective-C exceptions disabled">; def err_seh_try_outside_functions : Error< "cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls">; def err_mixing_cxx_try_seh_try : Error< "cannot use C++ 'try' in the same function as SEH '__try'">; def err_seh_try_unsupported : Error< "SEH '__try' is not supported on this target">; def note_conflicting_try_here : Note< "conflicting %0 here">; def warn_jump_out_of_seh_finally : Warning< "jump out of __finally block has undefined behavior">, InGroup>; def warn_non_virtual_dtor : Warning< "%0 has virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; def warn_delete_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on non-final %1 that has " "virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; def note_delete_non_virtual : Note< "qualify call to silence this warning">; def warn_delete_abstract_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on %1 that is abstract but has " "non-virtual destructor">, InGroup; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup, DefaultIgnore; def note_hidden_overloaded_virtual_declared_here : Note< "hidden overloaded virtual function %q0 declared here" "%select{|: different classes%diff{ ($ vs $)|}2,3" "|: different number of parameters (%2 vs %3)" "|: type mismatch at %ordinal2 parameter%diff{ ($ vs $)|}3,4" "|: different return type%diff{ ($ vs $)|}2,3" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}2 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}3)}1">; def warn_using_directive_in_header : Warning< "using namespace directive in global context in header">, InGroup, DefaultIgnore; def warn_overaligned_type : Warning< "type %0 requires %1 bytes of alignment and the default allocator only " "guarantees %2 bytes">, InGroup, DefaultIgnore; def err_conditional_void_nonvoid : Error< "%select{left|right}1 operand to ? is void, but %select{right|left}1 operand " "is of type %0">; def err_conditional_ambiguous : Error< "conditional expression is ambiguous; " "%diff{$ can be converted to $ and vice versa|" "types can be convert to each other}0,1">; def err_conditional_ambiguous_ovl : Error< "conditional expression is ambiguous; %diff{$ and $|types}0,1 " "can be converted to several common types">; def err_conditional_vector_size : Error< "vector condition type %0 and result type %1 do not have the same number " "of elements">; def err_conditional_vector_element_size : Error< "vector condition type %0 and result type %1 do not have elements of the " "same size">; def err_throw_incomplete : Error< "cannot throw object of incomplete type %0">; def err_throw_incomplete_ptr : Error< "cannot throw pointer to object of incomplete type %0">; def err_return_in_constructor_handler : Error< "return in the catch of a function try block of a constructor is illegal">; def warn_cdtor_function_try_handler_mem_expr : Warning< "cannot refer to a non-static member from the handler of a " "%select{constructor|destructor}0 function try block">, InGroup; let CategoryName = "Lambda Issue" in { def err_capture_more_than_once : Error< "%0 can appear only once in a capture list">; def err_reference_capture_with_reference_default : Error< "'&' cannot precede a capture when the capture default is '&'">; def err_this_capture_with_copy_default : Error< "'this' cannot be explicitly captured when the capture default is '='">; def err_copy_capture_with_copy_default : Error< "'&' must precede a capture when the capture default is '='">; def err_capture_does_not_name_variable : Error< "%0 in capture list does not name a variable">; def err_capture_non_automatic_variable : Error< "%0 cannot be captured because it does not have automatic storage " "duration">; def err_this_capture : Error< "'this' cannot be %select{implicitly |}0captured in this context">; def err_lambda_capture_anonymous_var : Error< "unnamed variable cannot be implicitly captured in a lambda expression">; def err_lambda_capture_flexarray_type : Error< "variable %0 with flexible array member cannot be captured in " "a lambda expression">; def err_lambda_impcap : Error< "variable %0 cannot be implicitly captured in a lambda with no " "capture-default specified">; def note_lambda_decl : Note<"lambda expression begins here">; def err_lambda_unevaluated_operand : Error< "lambda expression in an unevaluated operand">; def err_lambda_in_constant_expression : Error< "a lambda expression may not appear inside of a constant expression">; def err_lambda_return_init_list : Error< "cannot deduce lambda return type from initializer list">; def err_lambda_capture_default_arg : Error< "lambda expression in default argument cannot capture any entity">; def err_lambda_incomplete_result : Error< "incomplete result type %0 in lambda expression">; def err_noreturn_lambda_has_return_expr : Error< "lambda declared 'noreturn' should not return">; def warn_maybe_falloff_nonvoid_lambda : Warning< "control may reach end of non-void lambda">, InGroup; def warn_falloff_nonvoid_lambda : Warning< "control reaches end of non-void lambda">, InGroup; def err_access_lambda_capture : Error< // The ERRORs represent other special members that aren't constructors, in // hopes that someone will bother noticing and reporting if they appear "capture of variable '%0' as type %1 calls %select{private|protected}3 " "%select{default |copy |move |*ERROR* |*ERROR* |*ERROR* |}2constructor">, AccessControl; def note_lambda_to_block_conv : Note< "implicit capture of lambda object due to conversion to block pointer " "here">; // C++14 lambda init-captures. def warn_cxx11_compat_init_capture : Warning< "initialized lambda captures are incompatible with C++ standards " "before C++14">, InGroup, DefaultIgnore; def ext_init_capture : ExtWarn< "initialized lambda captures are a C++14 extension">, InGroup; def err_init_capture_no_expression : Error< "initializer missing for lambda capture %0">; def err_init_capture_multiple_expressions : Error< "initializer for lambda capture %0 contains multiple expressions">; def err_init_capture_paren_braces : Error< "cannot deduce type for lambda capture %1 from " "%select{parenthesized|nested}0 initializer list">; def err_init_capture_deduction_failure : Error< "cannot deduce type for lambda capture %0 from initializer of type %2">; def err_init_capture_deduction_failure_from_init_list : Error< "cannot deduce type for lambda capture %0 from initializer list">; // C++1z '*this' captures. def warn_cxx14_compat_star_this_lambda_capture : Warning< "by value capture of '*this' is incompatible with C++ standards before C++1z">, InGroup, DefaultIgnore; def ext_star_this_lambda_capture_cxx1z : ExtWarn< "capture of '*this' by copy is a C++1z extension">, InGroup; } def err_return_in_captured_stmt : Error< "cannot return from %0">; def err_capture_block_variable : Error< "__block variable %0 cannot be captured in a " "%select{lambda expression|captured statement}1">; def err_operator_arrow_circular : Error< "circular pointer delegation detected">; def err_operator_arrow_depth_exceeded : Error< "use of 'operator->' on type %0 would invoke a sequence of more than %1 " "'operator->' calls">; def note_operator_arrow_here : Note< "'operator->' declared here produces an object of type %0">; def note_operator_arrows_suppressed : Note< "(skipping %0 'operator->'%s0 in backtrace)">; def note_operator_arrow_depth : Note< "use -foperator-arrow-depth=N to increase 'operator->' limit">; def err_pseudo_dtor_base_not_scalar : Error< "object expression of non-scalar type %0 cannot be used in a " "pseudo-destructor expression">; def ext_pseudo_dtor_on_void : ExtWarn< "pseudo-destructors on type void are a Microsoft extension">, InGroup; def err_pseudo_dtor_type_mismatch : Error< "the type of object expression " "%diff{($) does not match the type being destroyed ($)|" "does not match the type being destroyed}0,1 " "in pseudo-destructor expression">; def err_pseudo_dtor_call_with_args : Error< "call to pseudo-destructor cannot have any arguments">; def err_dtor_expr_without_call : Error< "reference to %select{destructor|pseudo-destructor}0 must be called" "%select{|; did you mean to call it with no arguments?}1">; def err_pseudo_dtor_destructor_non_type : Error< "%0 does not refer to a type name in pseudo-destructor expression; expected " "the name of type %1">; def err_invalid_use_of_function_type : Error< "a function type is not allowed here">; def err_invalid_use_of_array_type : Error<"an array type is not allowed here">; def err_typecheck_bool_condition : Error< "value of type %0 is not contextually convertible to 'bool'">; def err_typecheck_ambiguous_condition : Error< "conversion %diff{from $ to $|between types}0,1 is ambiguous">; def err_typecheck_nonviable_condition : Error< "no viable conversion%select{%diff{ from $ to $|}1,2|" "%diff{ from returned value of type $ to function return type $|}1,2}0">; def err_typecheck_nonviable_condition_incomplete : Error< "no viable conversion%diff{ from $ to incomplete type $|}0,1">; def err_typecheck_deleted_function : Error< "conversion function %diff{from $ to $|between types}0,1 " "invokes a deleted function">; def err_expected_class_or_namespace : Error<"%0 is not a class" "%select{ or namespace|, namespace, or enumeration}1">; def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " "because namespace %1 does not enclose namespace %2">; def err_invalid_declarator_global_scope : Error< "definition or redeclaration of %0 cannot name the global scope">; def err_invalid_declarator_in_function : Error< "definition or redeclaration of %0 not allowed inside a function">; def err_invalid_declarator_in_block : Error< "definition or redeclaration of %0 not allowed inside a block">; def err_not_tag_in_scope : Error< "no %select{struct|interface|union|class|enum}0 named %1 in %2">; def err_no_typeid_with_fno_rtti : Error< "cannot use typeid with -fno-rtti">; def err_no_dynamic_cast_with_fno_rtti : Error< "cannot use dynamic_cast with -fno-rtti">; def err_cannot_form_pointer_to_member_of_reference_type : Error< "cannot form a pointer-to-member to member %0 of reference type %1">; def err_incomplete_object_call : Error< "incomplete type in call to object of type %0">; def warn_condition_is_assignment : Warning<"using the result of an " "assignment as a condition without parentheses">, InGroup; // Completely identical except off by default. def warn_condition_is_idiomatic_assignment : Warning<"using the result " "of an assignment as a condition without parentheses">, InGroup>, DefaultIgnore; def note_condition_assign_to_comparison : Note< "use '==' to turn this assignment into an equality comparison">; def note_condition_or_assign_to_comparison : Note< "use '!=' to turn this compound assignment into an inequality comparison">; def note_condition_assign_silence : Note< "place parentheses around the assignment to silence this warning">; def warn_equality_with_extra_parens : Warning<"equality comparison with " "extraneous parentheses">, InGroup; def note_equality_comparison_to_assign : Note< "use '=' to turn this equality comparison into an assignment">; def note_equality_comparison_silence : Note< "remove extraneous parentheses around the comparison to silence this warning">; // assignment related diagnostics (also for argument passing, returning, etc). // In most of these diagnostics the %2 is a value from the // Sema::AssignmentAction enumeration def err_typecheck_convert_incompatible : Error< "%select{%diff{assigning to $ from incompatible type $|" "assigning to type from incompatible type}0,1" "|%diff{passing $ to parameter of incompatible type $|" "passing type to parameter of incompatible type}0,1" "|%diff{returning $ from a function with incompatible result type $|" "returning type from a function with incompatible result type}0,1" "|%diff{converting $ to incompatible type $|" "converting type to incompatible type}0,1" "|%diff{initializing $ with an expression of incompatible type $|" "initializing type with an expression of incompatible type}0,1" "|%diff{sending $ to parameter of incompatible type $|" "sending type to parameter of incompatible type}0,1" "|%diff{casting $ to incompatible type $|" "casting type to incompatible type}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3" "%select{|: different classes%diff{ ($ vs $)|}5,6" "|: different number of parameters (%5 vs %6)" "|: type mismatch at %ordinal5 parameter%diff{ ($ vs $)|}6,7" "|: different return type%diff{ ($ vs $)|}5,6" "|: different qualifiers (" "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}5 vs " "%select{none|const|restrict|const and restrict|volatile|const and volatile|" "volatile and restrict|const, volatile, and restrict}6)}4">; def err_typecheck_missing_return_type_incompatible : Error< "%diff{return type $ must match previous return type $|" "return type must match previous return type}0,1 when %select{block " "literal|lambda expression}2 has unspecified explicit return type">; def not_incomplete_class_and_qualified_id : Note< "conformance of forward class %0 to protocol %1 can not be confirmed">; def warn_incompatible_qualified_id : Warning< "%select{%diff{assigning to $ from incompatible type $|" "assigning to type from incompatible type}0,1" "|%diff{passing $ to parameter of incompatible type $|" "passing type to parameter of incompatible type}0,1" "|%diff{returning $ from a function with incompatible result type $|" "returning type from a function with incompatible result type}0,1" "|%diff{converting $ to incompatible type $|" "converting type to incompatible type}0,1" "|%diff{initializing $ with an expression of incompatible type $|" "initializing type with an expression of incompatible type}0,1" "|%diff{sending $ to parameter of incompatible type $|" "sending type to parameter of incompatible type}0,1" "|%diff{casting $ to incompatible type $|" "casting type to incompatible type}0,1}2">; def ext_typecheck_convert_pointer_int : ExtWarn< "incompatible pointer to integer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_int_pointer : ExtWarn< "incompatible integer to pointer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_pointer_void_func : Extension< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " converts between void pointer and function pointer">; def ext_typecheck_convert_incompatible_pointer_sign : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " converts between pointers to integer types with different sign">, InGroup>; def ext_typecheck_convert_incompatible_pointer : ExtWarn< "incompatible pointer types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" "%select{|; dereference with *|" "; take the address with &|" "; remove *|" "; remove &}3">, InGroup; def ext_typecheck_convert_discards_qualifiers : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " discards qualifiers">, InGroup; def ext_nested_pointer_qualifier_mismatch : ExtWarn< "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " discards qualifiers in nested pointer types">, InGroup; def warn_incompatible_vectors : Warning< "incompatible vector types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">, InGroup, DefaultIgnore; def err_int_to_block_pointer : Error< "invalid block pointer conversion " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">; def err_typecheck_convert_incompatible_block_pointer : Error< "incompatible block pointer types " "%select{%diff{assigning to $ from $|assigning to different types}0,1" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2">; def err_typecheck_incompatible_address_space : Error< "%select{%diff{assigning $ to $|assigning to different types}1,0" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes address space of pointer">; def err_typecheck_incompatible_ownership : Error< "%select{%diff{assigning $ to $|assigning to different types}1,0" "|%diff{passing $ to parameter of type $|" "passing to parameter of different type}0,1" "|%diff{returning $ from a function with result type $|" "returning from function with different return type}0,1" "|%diff{converting $ to type $|converting between types}0,1" "|%diff{initializing $ with an expression of type $|" "initializing with expression of different type}0,1" "|%diff{sending $ to parameter of type $|" "sending to parameter of different type}0,1" "|%diff{casting $ to type $|casting between types}0,1}2" " changes retain/release properties of pointer">; def err_typecheck_comparison_of_distinct_blocks : Error< "comparison of distinct block types%diff{ ($ and $)|}0,1">; def err_typecheck_array_not_modifiable_lvalue : Error< "array type %0 is not assignable">; def err_typecheck_non_object_not_modifiable_lvalue : Error< "non-object type %0 is not assignable">; def err_typecheck_expression_not_modifiable_lvalue : Error< "expression is not assignable">; def err_typecheck_incomplete_type_not_modifiable_lvalue : Error< "incomplete type %0 is not assignable">; def err_typecheck_lvalue_casts_not_supported : Error< "assignment to cast is illegal, lvalue casts are not supported">; def err_typecheck_duplicate_vector_components_not_mlvalue : Error< "vector is not assignable (contains duplicate components)">; def err_block_decl_ref_not_modifiable_lvalue : Error< "variable is not assignable (missing __block type specifier)">; def err_lambda_decl_ref_not_modifiable_lvalue : Error< "cannot assign to a variable captured by copy in a non-mutable lambda">; def err_typecheck_call_not_function : Error< "called object type %0 is not a function or function pointer">; def err_call_incomplete_return : Error< "calling function with incomplete return type %0">; def err_call_function_incomplete_return : Error< "calling %0 with incomplete return type %1">; def err_call_incomplete_argument : Error< "argument type %0 is incomplete">; def err_typecheck_call_too_few_args : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2">; def err_typecheck_call_too_few_args_one : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "single argument %1 was not specified">; def err_typecheck_call_too_few_args_at_least : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at least %1, have %2">; def err_typecheck_call_too_few_args_at_least_one : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "at least argument %1 must be specified">; def err_typecheck_call_too_few_args_suggest : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2; did you mean %3?">; def err_typecheck_call_too_few_args_at_least_suggest : Error< "too few %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at least %1, have %2; did you mean %3?">; def err_typecheck_call_too_many_args : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2">; def err_typecheck_call_too_many_args_one : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected single argument %1, have %2 arguments">; def err_typecheck_call_too_many_args_at_most : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2">; def err_typecheck_call_too_many_args_at_most_one : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most single argument %1, have %2 arguments">; def err_typecheck_call_too_many_args_suggest : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected %1, have %2; did you mean %3?">; def err_typecheck_call_too_many_args_at_most_suggest : Error< "too many %select{|||execution configuration }0arguments to " "%select{function|block|method|kernel function}0 call, " "expected at most %1, have %2; did you mean %3?">; def err_arc_typecheck_convert_incompatible_pointer : Error< "incompatible pointer types passing retainable parameter of type %0" "to a CF function expecting %1 type">; def err_builtin_fn_use : Error<"builtin functions must be directly called">; def warn_call_wrong_number_of_arguments : Warning< "too %select{few|many}0 arguments in call to %1">; def err_atomic_builtin_must_be_pointer : Error< "address argument to atomic builtin must be a pointer (%0 invalid)">; def err_atomic_builtin_must_be_pointer_intptr : Error< "address argument to atomic builtin must be a pointer to integer or pointer" " (%0 invalid)">; def err_atomic_builtin_must_be_pointer_intfltptr : Error< "address argument to atomic builtin must be a pointer to integer," " floating-point or pointer (%0 invalid)">; def err_atomic_builtin_pointer_size : Error< "address argument to atomic builtin must be a pointer to 1,2,4,8 or 16 byte " "type (%0 invalid)">; def err_atomic_exclusive_builtin_pointer_size : Error< "address argument to load or store exclusive builtin must be a pointer to" " 1,2,4 or 8 byte type (%0 invalid)">; def err_atomic_op_needs_atomic : Error< "address argument to atomic operation must be a pointer to _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_non_const_atomic : Error< "address argument to atomic operation must be a pointer to non-const _Atomic " "type (%0 invalid)">; def err_atomic_op_needs_non_const_pointer : Error< "address argument to atomic operation must be a pointer to non-const " "type (%0 invalid)">; def err_atomic_op_needs_trivial_copy : Error< "address argument to atomic operation must be a pointer to a " "trivially-copyable type (%0 invalid)">; def err_atomic_op_needs_atomic_int_or_ptr : Error< "address argument to atomic operation must be a pointer to %select{|atomic }0" "integer or pointer (%1 invalid)">; def err_atomic_op_bitwise_needs_atomic_int : Error< "address argument to bitwise atomic operation must be a pointer to " "%select{|atomic }0integer (%1 invalid)">; def warn_atomic_op_has_invalid_memory_order : Warning< "memory order argument to atomic operation is invalid">, InGroup>; def err_overflow_builtin_must_be_int : Error< "operand argument to overflow builtin must be an integer (%0 invalid)">; def err_overflow_builtin_must_be_ptr_int : Error< "result argument to overflow builtin must be a pointer " "to a non-const integer (%0 invalid)">; def err_atomic_load_store_uses_lib : Error< "atomic %select{load|store}0 requires runtime support that is not " "available for this target">; def err_nontemporal_builtin_must_be_pointer : Error< "address argument to nontemporal builtin must be a pointer (%0 invalid)">; def err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector : Error< "address argument to nontemporal builtin must be a pointer to integer, float, " "pointer, or a vector of such types (%0 invalid)">; def err_deleted_function_use : Error<"attempt to use a deleted function">; def err_deleted_inherited_ctor_use : Error< "constructor inherited by %0 from base class %1 is implicitly deleted">; def err_kern_type_not_void_return : Error< "kernel function type %0 must have void return type">; def err_kern_is_nonstatic_method : Error< "kernel function %0 must be a free function or static member function">; def err_config_scalar_return : Error< "CUDA special function 'cudaConfigureCall' must have scalar return type">; def err_kern_call_not_global_function : Error< "kernel call to non-global function %0">; def err_global_call_not_config : Error< "call to global function %0 not configured">; def err_ref_bad_target : Error< "reference to %select{__device__|__global__|__host__|__host__ __device__}0 " "function %1 in %select{__device__|__global__|__host__|__host__ __device__}2 function">; def warn_kern_is_method : Extension< "kernel function %0 is a member function; this may not be accepted by nvcc">, InGroup; def warn_kern_is_inline : Warning< "ignored 'inline' attribute on kernel function %0">, InGroup; def err_variadic_device_fn : Error< "CUDA device code does not support variadic functions">; def err_va_arg_in_device : Error< "CUDA device code does not support va_arg">; def err_alias_not_supported_on_nvptx : Error<"CUDA does not support aliases">; def err_cuda_unattributed_constexpr_cannot_overload_device : Error< "constexpr function '%0' without __host__ or __device__ attributes cannot " "overload __device__ function with same signature. Add a __host__ " "attribute, or build with -fno-cuda-host-device-constexpr.">; def note_cuda_conflicting_device_function_declared_here : Note< "conflicting __device__ function declared here">; def err_dynamic_var_init : Error< "dynamic initialization is not supported for " "__device__, __constant__, and __shared__ variables.">; def err_shared_var_init : Error< "initialization is not supported for __shared__ variables.">; def err_device_static_local_var : Error< "Within a __device__/__global__ function, " "only __shared__ variables may be marked \"static\"">; def warn_non_pod_vararg_with_format_string : Warning< "cannot pass %select{non-POD|non-trivial}0 object of type %1 to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">, InGroup, DefaultError; // The arguments to this diagnostic should match the warning above. def err_cannot_pass_objc_interface_to_vararg_format : Error< "cannot pass object with interface type %1 by value to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">; def err_cannot_pass_objc_interface_to_vararg : Error< "cannot pass object with interface type %0 by value through variadic " "%select{function|block|method|constructor}1">; 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 warn_pass_class_arg_to_vararg : Warning< "passing object of class type %0 through variadic " "%select{function|block|method|constructor}1" "%select{|; did you mean to call '%3'?}2">, InGroup, DefaultIgnore; def err_cannot_pass_to_vararg : Error< "cannot pass %select{expression of type %1|initializer list}0 to variadic " "%select{function|block|method|constructor}2">; def err_cannot_pass_to_vararg_format : Error< "cannot pass %select{expression of type %1|initializer list}0 to variadic " "%select{function|block|method|constructor}2; expected type from format " "string was %3">; def err_typecheck_call_invalid_ordered_compare : Error< "ordered compare requires two args of floating point type" "%diff{ ($ and $)|}0,1">; def err_typecheck_call_invalid_unary_fp : Error< "floating point classification requires argument of floating point type " "(passed in %0)">; def err_typecheck_cond_expect_int_float : Error< "used type %0 where integer or floating point type is required">; def err_typecheck_cond_expect_scalar : Error< "used type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_expect_nonfloat : Error< "used type %0 where floating point type is not allowed">; def ext_typecheck_cond_one_void : Extension< "C99 forbids conditional expressions with only one void side">; def err_typecheck_cast_to_incomplete : Error< "cast to incomplete type %0">; def ext_typecheck_cast_nonscalar : Extension< "C99 forbids casting nonscalar type %0 to the same type">; def ext_typecheck_cast_to_union : Extension< "cast to union type is a GNU extension">, InGroup; def err_typecheck_cast_to_union_no_type : Error< "cast to union type from type %0 not present in union">; def err_cast_pointer_from_non_pointer_int : Error< "operand of type %0 cannot be cast to a pointer type">; def warn_cast_pointer_from_sel : Warning< "cast of type %0 to %1 is deprecated; use sel_getName instead">, InGroup; def warn_function_def_in_objc_container : Warning< "function definition inside an Objective-C container is deprecated">, InGroup; def warn_cast_calling_conv : Warning< "cast between incompatible calling conventions '%0' and '%1'; " "calls through this pointer may abort at runtime">, InGroup>; def note_change_calling_conv_fixit : Note< "consider defining %0 with the '%1' calling convention">; def warn_bad_function_cast : Warning< "cast from function call of type %0 to non-matching type %1">, InGroup, DefaultIgnore; def err_cast_pointer_to_non_pointer_int : Error< "pointer cannot be cast to type %0">; def err_typecheck_expect_scalar_operand : Error< "operand of type %0 where arithmetic or pointer type is required">; def err_typecheck_cond_incompatible_operands : Error< "incompatible operand types%diff{ ($ and $)|}0,1">; def ext_typecheck_cond_incompatible_operands_nonstandard : ExtWarn< "incompatible operand types%diff{ ($ and $)|}0,1 use non-standard composite " "pointer type %2">; def err_cast_selector_expr : Error< "cannot type cast @selector expression">; def ext_typecheck_cond_incompatible_pointers : ExtWarn< "pointer type mismatch%diff{ ($ and $)|}0,1">, InGroup>; def ext_typecheck_cond_pointer_integer_mismatch : ExtWarn< "pointer/integer type mismatch in conditional expression" "%diff{ ($ and $)|}0,1">, InGroup>; def err_typecheck_choose_expr_requires_constant : Error< "'__builtin_choose_expr' requires a constant expression">; def warn_unused_expr : Warning<"expression result unused">, InGroup; def warn_unused_voidptr : Warning< "expression result unused; should this cast be to 'void'?">, InGroup; def warn_unused_property_expr : Warning< "property access result unused - getters should not be used for side effects">, InGroup; def warn_unused_container_subscript_expr : Warning< "container access result unused - container access should not be used for side effects">, InGroup; def warn_unused_call : Warning< "ignoring return value of function declared with %0 attribute">, InGroup; def warn_side_effects_unevaluated_context : Warning< "expression with side effects has no effect in an unevaluated context">, InGroup; def warn_side_effects_typeid : Warning< "expression with side effects will be evaluated despite being used as an " "operand to 'typeid'">, InGroup; def warn_unused_result : Warning< "ignoring return value of function declared with %0 attribute">, InGroup>; def warn_unused_volatile : Warning< "expression result unused; assign into a variable to force a volatile load">, InGroup>; def ext_cxx14_attr : Extension< "use of the %0 attribute is a C++14 extension">, InGroup; def ext_cxx1z_attr : Extension< "use of the %0 attribute is a C++1z extension">, InGroup; def warn_unused_comparison : Warning< "%select{%select{|in}1equality|relational}0 comparison result unused">, InGroup; def note_inequality_comparison_to_or_assign : Note< "use '|=' to turn this inequality comparison into an or-assignment">; def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; def err_dimension_expr_not_constant_integer : Error< "dimension expression does not evaluate to a constant unsigned int">; def err_typecheck_cond_incompatible_operands_null : Error< "non-pointer operand type %0 incompatible with %select{NULL|nullptr}1">; def ext_empty_struct_union : Extension< "empty %select{struct|union}0 is a GNU extension">, InGroup; def ext_no_named_members_in_struct_union : Extension< "%select{struct|union}0 without named members is a GNU extension">, InGroup; def warn_zero_size_struct_union_compat : Warning<"%select{|empty }0" "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, InGroup, DefaultIgnore; def warn_zero_size_struct_union_in_extern_c : Warning<"%select{|empty }0" "%select{struct|union}1 has size 0 in C, %select{size 1|non-zero size}2 in C++">, InGroup; def warn_cast_qual : Warning<"cast from %0 to %1 drops %select{const and " "volatile qualifiers|const qualifier|volatile qualifier}2">, InGroup, DefaultIgnore; def warn_cast_qual2 : Warning<"cast from %0 to %1 must have all intermediate " "pointers const qualified to be safe">, InGroup, DefaultIgnore; def warn_redefine_extname_not_applied : Warning< "#pragma redefine_extname is applicable to external C declarations only; " "not applied to %select{function|variable}0 %1">, InGroup; } // End of general sema category. // inline asm. let CategoryName = "Inline Assembly Issue" in { def err_asm_invalid_lvalue_in_output : Error<"invalid lvalue in asm output">; def err_asm_invalid_output_constraint : Error< "invalid output constraint '%0' in asm">; def err_asm_invalid_lvalue_in_input : Error< "invalid lvalue in asm input for constraint '%0'">; def err_asm_invalid_input_constraint : Error< "invalid input constraint '%0' in asm">; def err_asm_immediate_expected : Error<"constraint '%0' expects " "an integer constant expression">; def err_asm_invalid_type_in_input : Error< "invalid type %0 in asm input for constraint '%1'">; def err_asm_tying_incompatible_types : Error< "unsupported inline asm: input with type " "%diff{$ matching output with type $|}0,1">; def err_asm_unexpected_constraint_alternatives : Error< "asm constraint has an unexpected number of alternatives: %0 vs %1">; def err_asm_incomplete_type : Error<"asm operand has incomplete type %0">; def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; def err_asm_invalid_global_var_reg : Error<"register '%0' unsuitable for " "global register variables on this target">; def err_asm_register_size_mismatch : Error<"size of register '%0' does not " "match variable size">; def err_asm_bad_register_type : Error<"bad type for named register variable">; def err_asm_invalid_input_size : Error< "invalid input size for constraint '%0'">; def err_asm_invalid_output_size : Error< "invalid output size for constraint '%0'">; def err_invalid_asm_cast_lvalue : Error< "invalid use of a cast in a inline asm context requiring an l-value: " "remove the cast or build with -fheinous-gnu-extensions">; def err_invalid_asm_value_for_constraint : Error <"value '%0' out of range for constraint '%1'">; def err_asm_non_addr_value_in_memory_constraint : Error < "reference to a %select{bit-field|vector element|global register variable}0" " in asm %select{input|output}1 with a memory constraint '%2'">; def err_asm_input_duplicate_match : Error< "more than one input constraint matches the same output '%0'">; def warn_asm_label_on_auto_decl : Warning< "ignored asm label '%0' on automatic variable">; def warn_invalid_asm_cast_lvalue : Warning< "invalid use of a cast in an inline asm context requiring an l-value: " "accepted due to -fheinous-gnu-extensions, but clang may remove support " "for this in the future">; def warn_asm_mismatched_size_modifier : Warning< "value size does not match register size specified by the constraint " "and modifier">, InGroup; def note_asm_missing_constraint_modifier : Note< "use constraint modifier \"%0\"">; def note_asm_input_duplicate_first : Note< "constraint '%0' is already present here">; } let CategoryName = "Semantic Issue" in { def err_invalid_conversion_between_vectors : Error< "invalid conversion between vector type%diff{ $ and $|}0,1 of different " "size">; def err_invalid_conversion_between_vector_and_integer : Error< "invalid conversion between vector type %0 and integer type %1 " "of different size">; def err_opencl_function_pointer_variable : Error< "pointers to functions are not allowed">; def err_opencl_taking_function_address : Error< "taking address of function is not allowed">; def err_invalid_conversion_between_vector_and_scalar : Error< "invalid conversion between vector type %0 and scalar type %1">; // C++ member initializers. def err_only_constructors_take_base_inits : Error< "only constructors take base initializers">; def err_multiple_mem_initialization : Error < "multiple initializations given for non-static member %0">; def err_multiple_mem_union_initialization : Error < "initializing multiple members of union">; def err_multiple_base_initialization : Error < "multiple initializations given for base %0">; def err_mem_init_not_member_or_class : Error< "member initializer %0 does not name a non-static data member or base " "class">; def warn_initializer_out_of_order : Warning< "%select{field|base class}0 %1 will be initialized after " "%select{field|base}2 %3">, InGroup, DefaultIgnore; def warn_abstract_vbase_init_ignored : Warning< "initializer for virtual base class %0 of abstract class %1 " "will never be used">, InGroup>, DefaultIgnore; def err_base_init_does_not_name_class : Error< "constructor initializer %0 does not name a class">; def err_base_init_direct_and_virtual : Error< "base class initializer %0 names both a direct base class and an " "inherited virtual base class">; def err_not_direct_base_or_virtual : Error< "type %0 is not a direct or virtual base of %1">; def err_in_class_initializer_non_const : Error< "non-const static data member must be initialized out of line">; def err_in_class_initializer_volatile : Error< "static const volatile data member must be initialized out of line">; def err_in_class_initializer_bad_type : Error< "static data member of type %0 must be initialized out of line">; def ext_in_class_initializer_float_type : ExtWarn< "in-class initializer for static data member of type %0 is a GNU extension">, InGroup; def ext_in_class_initializer_float_type_cxx11 : ExtWarn< "in-class initializer for static data member of type %0 requires " "'constexpr' specifier">, InGroup, DefaultError; def note_in_class_initializer_float_type_cxx11 : Note<"add 'constexpr'">; def err_in_class_initializer_literal_type : Error< "in-class initializer for static data member of type %0 requires " "'constexpr' specifier">; def err_in_class_initializer_non_constant : Error< "in-class initializer for static data member is not a constant expression">; def err_in_class_initializer_not_yet_parsed : Error<"cannot use defaulted default constructor of %0 within the class " "outside of member functions because %1 has an initializer">; def err_in_class_initializer_not_yet_parsed_outer_class : Error<"cannot use defaulted default constructor of %0 within " "%1 outside of member functions because %2 has an initializer">; def err_in_class_initializer_cycle : Error<"default member initializer for %0 uses itself">; def err_exception_spec_cycle : Error<"exception specification of %0 uses itself">; def ext_in_class_initializer_non_constant : Extension< "in-class initializer for static data member is not a constant expression; " "folding it to a constant is a GNU extension">, InGroup; def err_thread_dynamic_init : Error< "initializer for thread-local variable must be a constant expression">; def err_thread_nontrivial_dtor : Error< "type of thread-local variable has non-trivial destruction">; def note_use_thread_local : Note< "use 'thread_local' to allow this">; // C++ anonymous unions and GNU anonymous structs/unions def ext_anonymous_union : Extension< "anonymous unions are a C11 extension">, InGroup; def ext_gnu_anonymous_struct : Extension< "anonymous structs are a GNU extension">, InGroup; def ext_c11_anonymous_struct : Extension< "anonymous structs are a C11 extension">, InGroup; def err_anonymous_union_not_static : Error< "anonymous unions at namespace or global scope must be declared 'static'">; def err_anonymous_union_with_storage_spec : Error< "anonymous union at class scope must not have a storage specifier">; def err_anonymous_struct_not_member : Error< "anonymous %select{structs|structs and classes}0 must be " "%select{struct or union|class}0 members">; def err_anonymous_record_member_redecl : Error< "member of anonymous %select{struct|union}0 redeclares %1">; def err_anonymous_record_with_type : Error< "types cannot be declared in an anonymous %select{struct|union}0">; def ext_anonymous_record_with_type : Extension< "types declared in an anonymous %select{struct|union}0 are a Microsoft " "extension">, InGroup; def ext_anonymous_record_with_anonymous_type : Extension< "anonymous types declared in an anonymous %select{struct|union}0 " "are an extension">, InGroup>; def err_anonymous_record_with_function : Error< "functions cannot be declared in an anonymous %select{struct|union}0">; def err_anonymous_record_with_static : Error< "static members cannot be declared in an anonymous %select{struct|union}0">; def err_anonymous_record_bad_member : Error< "anonymous %select{struct|union}0 can only contain non-static data members">; def err_anonymous_record_nonpublic_member : Error< "anonymous %select{struct|union}0 cannot contain a " "%select{private|protected}1 data member">; def ext_ms_anonymous_record : ExtWarn< "anonymous %select{structs|unions}0 are a Microsoft extension">, InGroup; // C++ local classes def err_reference_to_local_var_in_enclosing_function : Error< "reference to local variable %0 declared in enclosing function %1">; def err_reference_to_local_var_in_enclosing_block : Error< "reference to local variable %0 declared in enclosing block literal">; def err_reference_to_local_var_in_enclosing_lambda : Error< "reference to local variable %0 declared in enclosing lambda expression">; def err_reference_to_local_var_in_enclosing_context : Error< "reference to local variable %0 declared in enclosing context">; def err_static_data_member_not_allowed_in_local_class : Error< "static data member %0 not allowed in local class %1">; // C++ derived classes def err_base_clause_on_union : Error<"unions cannot have base classes">; def err_base_must_be_class : Error<"base specifier must name a class">; def err_union_as_base_class : Error<"unions cannot be base classes">; def err_circular_inheritance : Error< "circular inheritance between %0 and %1">; def err_base_class_has_flexible_array_member : Error< "base class %0 has a flexible array member">; def err_incomplete_base_class : Error<"base class has incomplete type">; def err_duplicate_base_class : Error< "base class %0 specified more than once as a direct base class">; def warn_inaccessible_base_class : Warning< "direct base %0 is inaccessible due to ambiguity:%1">, InGroup>; // FIXME: better way to display derivation? Pass entire thing into diagclient? def err_ambiguous_derived_to_base_conv : Error< "ambiguous conversion from derived class %0 to base class %1:%2">; def err_ambiguous_memptr_conv : Error< "ambiguous conversion from pointer to member of %select{base|derived}0 " "class %1 to pointer to member of %select{derived|base}0 class %2:%3">; def err_memptr_conv_via_virtual : Error< "conversion from pointer to member of class %0 to pointer to member " "of class %1 via virtual base %2 is not allowed">; // C++ member name lookup def err_ambiguous_member_multiple_subobjects : Error< "non-static member %0 found in multiple base-class subobjects of type %1:%2">; def err_ambiguous_member_multiple_subobject_types : Error< "member %0 found in multiple base classes of different types">; def note_ambiguous_member_found : Note<"member found by ambiguous name lookup">; def err_ambiguous_reference : Error<"reference to %0 is ambiguous">; def note_ambiguous_candidate : Note<"candidate found by name lookup is %q0">; def err_ambiguous_tag_hiding : Error<"a type named %0 is hidden by a " "declaration in a different namespace">; def note_hidden_tag : Note<"type declaration hidden">; def note_hiding_object : Note<"declaration hides type">; // C++ operator overloading def err_operator_overload_needs_class_or_enum : Error< "overloaded %0 must have at least one parameter of class " "or enumeration type">; def err_operator_overload_variadic : Error<"overloaded %0 cannot be variadic">; def err_operator_overload_static : Error< "overloaded %0 cannot be a static member function">; def err_operator_overload_default_arg : Error< "parameter of overloaded %0 cannot have a default argument">; def err_operator_overload_must_be : Error< "overloaded %0 must be a %select{unary|binary|unary or binary}2 operator " "(has %1 parameter%s1)">; def err_operator_overload_must_be_member : Error< "overloaded %0 must be a non-static member function">; def err_operator_overload_post_incdec_must_be_int : Error< "parameter of overloaded post-%select{increment|decrement}1 operator must " "have type 'int' (not %0)">; // C++ allocation and deallocation functions. def err_operator_new_delete_declared_in_namespace : Error< "%0 cannot be declared inside a namespace">; def err_operator_new_delete_declared_static : Error< "%0 cannot be declared static in global scope">; def ext_operator_new_delete_declared_inline : ExtWarn< "replacement function %0 cannot be declared 'inline'">, InGroup>; def err_operator_new_delete_invalid_result_type : Error< "%0 must return type %1">; def err_operator_new_delete_dependent_result_type : Error< "%0 cannot have a dependent return type; use %1 instead">; def err_operator_new_delete_too_few_parameters : Error< "%0 must have at least one parameter">; def err_operator_new_delete_template_too_few_parameters : Error< "%0 template must have at least two parameters">; def warn_operator_new_returns_null : Warning< "%0 should not return a null pointer unless it is declared 'throw()'" "%select{| or 'noexcept'}1">, InGroup; def err_operator_new_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; " "use size_t (%1) instead">; def err_operator_new_param_type : Error< "%0 takes type size_t (%1) as first parameter">; def err_operator_new_default_arg: Error< "parameter of %0 cannot have a default argument">; def err_operator_delete_dependent_param_type : Error< "%0 cannot take a dependent type as first parameter; use %1 instead">; def err_operator_delete_param_type : Error< "first parameter of %0 must have type %1">; // C++ literal operators def err_literal_operator_outside_namespace : Error< "literal operator %0 must be in a namespace or global scope">; def err_literal_operator_id_outside_namespace : Error< "non-namespace scope '%0' cannot have a literal operator member">; def err_literal_operator_default_argument : Error< "literal operator cannot have a default argument">; def err_literal_operator_bad_param_count : Error< "non-template literal operator must have one or two parameters">; def err_literal_operator_invalid_param : Error< "parameter of literal operator must have type 'unsigned long long', 'long double', 'char', 'wchar_t', 'char16_t', 'char32_t', or 'const char *'">; def err_literal_operator_param : Error< "invalid literal operator parameter type %0, did you mean %1?">; def err_literal_operator_template_with_params : Error< "literal operator template cannot have any parameters">; def err_literal_operator_template : Error< "template parameter list for literal operator must be either 'char...' or 'typename T, T...'">; def err_literal_operator_extern_c : Error< "literal operator must have C++ linkage">; def ext_string_literal_operator_template : ExtWarn< "string literal operator templates are a GNU extension">, InGroup; def warn_user_literal_reserved : Warning< "user-defined literal suffixes not starting with '_' are reserved" "%select{; no literal will invoke this operator|}0">, InGroup; // C++ conversion functions def err_conv_function_not_member : Error< "conversion function must be a non-static member function">; def err_conv_function_return_type : Error< "conversion function cannot have a return type">; def err_conv_function_with_params : Error< "conversion function cannot have any parameters">; def err_conv_function_variadic : Error< "conversion function cannot be variadic">; def err_conv_function_to_array : Error< "conversion function cannot convert to an array type">; def err_conv_function_to_function : Error< "conversion function cannot convert to a function type">; def err_conv_function_with_complex_decl : Error< "cannot specify any part of a return type in the " "declaration of a conversion function" "%select{" "; put the complete type after 'operator'|" "; use a typedef to declare a conversion to %1|" "; use an alias template to declare a conversion to %1|" "}0">; def err_conv_function_redeclared : Error< "conversion function cannot be redeclared">; def warn_conv_to_self_not_used : Warning< "conversion function converting %0 to itself will never be used">; def warn_conv_to_base_not_used : Warning< "conversion function converting %0 to its base class %1 will never be used">; def warn_conv_to_void_not_used : Warning< "conversion function converting %0 to %1 will never be used">; def warn_not_compound_assign : Warning< "use of unary operator that may be intended as compound assignment (%0=)">; // C++11 explicit conversion operators 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_special_member_params : Error< "an explicitly-defaulted %select{|copy |move }0constructor cannot " "have default arguments">; def err_defaulted_special_member_variadic : Error< "an explicitly-defaulted %select{|copy |move }0constructor cannot " "be variadic">; def err_defaulted_special_member_return_type : Error< "explicitly-defaulted %select{copy|move}0 assignment operator must " "return %1">; def err_defaulted_special_member_quals : Error< "an explicitly-defaulted %select{copy|move}0 assignment operator may not " "have 'const'%select{, 'constexpr'|}1 or 'volatile' qualifiers">; def err_defaulted_special_member_volatile_param : Error< "the parameter for an explicitly-defaulted %select{<>|" "copy constructor|move constructor|copy assignment operator|" "move assignment operator|<>}0 may not be volatile">; def err_defaulted_special_member_move_const_param : Error< "the parameter for an explicitly-defaulted move " "%select{constructor|assignment operator}0 may not be const">; def err_defaulted_special_member_copy_const_param : Error< "the parameter for this explicitly-defaulted copy " "%select{constructor|assignment operator}0 is const, but a member or base " "requires it to be non-const">; def err_defaulted_copy_assign_not_ref : Error< "the parameter for an explicitly-defaulted copy assignment operator must be an " "lvalue reference type">; def err_incorrect_defaulted_exception_spec : Error< "exception specification of explicitly defaulted %select{default constructor|" "copy constructor|move constructor|copy assignment operator|move assignment " "operator|destructor}0 does not match the " "calculated one">; def err_incorrect_defaulted_constexpr : Error< "defaulted definition of %select{default constructor|copy constructor|" "move constructor|copy assignment operator|move assignment operator}0 " "is not constexpr">; def err_out_of_line_default_deletes : Error< "defaulting this %select{default constructor|copy constructor|move " "constructor|copy assignment operator|move assignment operator|destructor}0 " "would delete it after its first declaration">; def warn_vbase_moved_multiple_times : Warning< "defaulted move assignment operator of %0 will move assign virtual base " "class %1 multiple times">, InGroup>; def note_vbase_moved_here : Note< "%select{%1 is a virtual base class of base class %2 declared here|" "virtual base class %1 declared here}0">; def ext_implicit_exception_spec_mismatch : ExtWarn< "function previously declared with an %select{explicit|implicit}0 exception " "specification redeclared with an %select{implicit|explicit}0 exception " "specification">, InGroup>; def warn_ptr_arith_precedes_bounds : Warning< "the pointer decremented by %0 refers before the beginning of the array">, InGroup, DefaultIgnore; def warn_ptr_arith_exceeds_bounds : Warning< "the pointer incremented by %0 refers past the end of the array (that " "contains %1 element%s2)">, InGroup, DefaultIgnore; def warn_array_index_precedes_bounds : Warning< "array index %0 is before the beginning of the array">, InGroup; def warn_array_index_exceeds_bounds : Warning< "array index %0 is past the end of the array (which contains %1 " "element%s2)">, InGroup; def note_array_index_out_of_bounds : Note< "array %0 declared here">; def warn_printf_insufficient_data_args : Warning< "more '%%' conversions than data arguments">, InGroup; def warn_printf_data_arg_not_used : Warning< "data argument not used by format string">, InGroup; def warn_format_invalid_conversion : Warning< "invalid conversion specifier '%0'">, InGroup; def warn_printf_incomplete_specifier : Warning< "incomplete format specifier">, InGroup; def warn_missing_format_string : Warning< "format string missing">, InGroup; def warn_scanf_nonzero_width : Warning< "zero field width in scanf format string is unused">, InGroup; def warn_format_conversion_argument_type_mismatch : Warning< "format specifies type %0 but the argument has " "%select{type|underlying type}2 %1">, InGroup; def warn_format_conversion_argument_type_mismatch_pedantic : Extension< "format specifies type %0 but the argument has " "%select{type|underlying type}2 %1">, InGroup; def warn_format_argument_needs_cast : Warning< "%select{values of type|enum values with underlying type}2 '%0' should not " "be used as format arguments; add an explicit cast to %1 instead">, InGroup; def warn_printf_positional_arg_exceeds_data_args : Warning < "data argument position '%0' exceeds the number of data arguments (%1)">, InGroup; def warn_format_zero_positional_specifier : Warning< "position arguments in format strings start counting at 1 (not 0)">, InGroup; def warn_format_invalid_positional_specifier : Warning< "invalid position specified for %select{field width|field precision}0">, InGroup; def warn_format_mix_positional_nonpositional_args : Warning< "cannot mix positional and non-positional arguments in format string">, InGroup; def warn_static_array_too_small : Warning< "array argument is too small; contains %0 elements, callee requires at least %1">, InGroup; def note_callee_static_array : Note< "callee declares array parameter as static here">; def warn_empty_format_string : Warning< "format string is empty">, InGroup; def warn_format_string_is_wide_literal : Warning< "format string should not be a wide string">, InGroup; def warn_printf_format_string_contains_null_char : Warning< "format string contains '\\0' within the string body">, InGroup; def warn_printf_format_string_not_null_terminated : Warning< "format string is not null-terminated">, InGroup; def warn_printf_asterisk_missing_arg : Warning< "'%select{*|.*}0' specified field %select{width|precision}0 is missing a matching 'int' argument">, InGroup; def warn_printf_asterisk_wrong_type : Warning< "field %select{width|precision}0 should have type %1, but argument has type %2">, InGroup; def warn_printf_nonsensical_optional_amount: Warning< "%select{field width|precision}0 used with '%1' conversion specifier, resulting in undefined behavior">, InGroup; def warn_printf_nonsensical_flag: Warning< "flag '%0' results in undefined behavior with '%1' conversion specifier">, InGroup; def warn_format_nonsensical_length: Warning< "length modifier '%0' results in undefined behavior or no effect with '%1' conversion specifier">, InGroup; def warn_format_non_standard_positional_arg: Warning< "positional arguments are not supported by ISO C">, InGroup, DefaultIgnore; def warn_format_non_standard: Warning< "'%0' %select{length modifier|conversion specifier}1 is not supported by ISO C">, InGroup, DefaultIgnore; def warn_format_non_standard_conversion_spec: Warning< "using length modifier '%0' with conversion specifier '%1' is not supported by ISO C">, InGroup, DefaultIgnore; def warn_printf_ignored_flag: Warning< "flag '%0' is ignored when flag '%1' is present">, InGroup; def warn_printf_empty_objc_flag: Warning< "missing object format flag">, InGroup; def warn_printf_ObjCflags_without_ObjCConversion: Warning< "object format flags cannot be used with '%0' conversion specifier">, InGroup; def warn_printf_invalid_objc_flag: Warning< "'%0' is not a valid object format flag">, InGroup; def warn_scanf_scanlist_incomplete : Warning< "no closing ']' for '%%[' in scanf format string">, InGroup; def note_format_string_defined : Note<"format string is defined here">; def note_format_fix_specifier : Note<"did you mean to use '%0'?">; def note_printf_c_str: Note<"did you mean to call the %0 method?">; def note_format_security_fixit: Note< "treat the string as an argument to avoid this">; def warn_null_arg : Warning< "null passed to a callee that requires a non-null argument">, InGroup; def warn_null_ret : Warning< "null returned from %select{function|method}0 that requires a non-null return value">, InGroup; // CHECK: returning address/reference of stack memory def warn_ret_stack_addr_ref : Warning< "%select{address of|reference to}0 stack memory associated with local " "variable %1 returned">, InGroup; def warn_ret_local_temp_addr_ref : Warning< "returning %select{address of|reference to}0 local temporary object">, InGroup; def warn_ret_addr_label : Warning< "returning address of label, which is local">, InGroup; def err_ret_local_block : Error< "returning block that lives on the local stack">; def note_ref_var_local_bind : Note< "binding reference variable %0 here">; // Check for initializing a member variable with the address or a reference to // a constructor parameter. def warn_bind_ref_member_to_parameter : Warning< "binding reference member %0 to stack allocated parameter %1">, InGroup; def warn_init_ptr_member_to_parameter_addr : Warning< "initializing pointer member %0 with the stack address of parameter %1">, InGroup; def warn_bind_ref_member_to_temporary : Warning< "binding reference %select{|subobject of }1member %0 to a temporary value">, InGroup; def note_ref_or_ptr_member_declared_here : Note< "%select{reference|pointer}0 member declared here">; def note_ref_subobject_of_member_declared_here : Note< "member with reference subobject declared here">; // For non-floating point, expressions of the form x == x or x != x // should result in a warning, since these always evaluate to a constant. // Array comparisons have similar warnings def warn_comparison_always : Warning< "%select{self-|array }0comparison always evaluates to %select{false|true|a constant}1">, InGroup; def warn_comparison_bitwise_always : Warning< "bitwise comparison always evaluates to %select{false|true}0">, InGroup; def warn_tautological_overlap_comparison : Warning< "overlapping comparisons always evaluate to %select{false|true}0">, InGroup, DefaultIgnore; def warn_stringcompare : Warning< "result of comparison against %select{a string literal|@encode}0 is " "unspecified (use strncmp instead)">, InGroup; def warn_identity_field_assign : Warning< "assigning %select{field|instance variable}0 to itself">, InGroup; // Type safety attributes def err_type_tag_for_datatype_not_ice : Error< "'type_tag_for_datatype' attribute requires the initializer to be " "an %select{integer|integral}0 constant expression">; def err_type_tag_for_datatype_too_large : Error< "'type_tag_for_datatype' attribute requires the initializer to be " "an %select{integer|integral}0 constant expression " "that can be represented by a 64 bit integer">; def warn_type_tag_for_datatype_wrong_kind : Warning< "this type tag was not designed to be used with this function">, InGroup; def warn_type_safety_type_mismatch : Warning< "argument type %0 doesn't match specified %1 type tag " "%select{that requires %3|}2">, InGroup; def warn_type_safety_null_pointer_required : Warning< "specified %0 type tag requires a null pointer">, InGroup; // Generic selections. def err_assoc_type_incomplete : Error< "type %0 in generic association incomplete">; def err_assoc_type_nonobject : Error< "type %0 in generic association not an object type">; def err_assoc_type_variably_modified : Error< "type %0 in generic association is a variably modified type">; def err_assoc_compatible_types : Error< "type %0 in generic association compatible with previously specified type %1">; def note_compat_assoc : Note< "compatible type %0 specified here">; def err_generic_sel_no_match : Error< "controlling expression type %0 not compatible with any generic association type">; def err_generic_sel_multi_match : Error< "controlling expression type %0 compatible with %1 generic association types">; // Blocks def err_blocks_disable : Error<"blocks support disabled - compile with -fblocks" " or %select{pick a deployment target that supports them|for OpenCL 2.0 or above}0">; def err_block_returning_array_function : Error< "block cannot return %select{array|function}0 type %1">; // Builtin annotation def err_builtin_annotation_first_arg : Error< "first argument to __builtin_annotation must be an integer">; def err_builtin_annotation_second_arg : Error< "second argument to __builtin_annotation must be a non-wide string constant">; // CFString checking def err_cfstring_literal_not_string_constant : Error< "CFString literal is not a string constant">; def warn_cfstring_truncated : Warning< "input conversion stopped due to an input byte that does not " "belong to the input codeset UTF-8">, InGroup>; // Statements. def err_continue_not_in_loop : Error< "'continue' statement not in loop statement">; def err_break_not_in_loop_or_switch : Error< "'break' statement not in loop or switch statement">; def warn_loop_ctrl_binds_to_inner : Warning< "'%0' is bound to current loop, GCC binds it to the enclosing loop">, InGroup; def warn_break_binds_to_switch : Warning< "'break' is bound to loop, GCC binds it to switch">, InGroup; def err_default_not_in_switch : Error< "'default' statement not in switch statement">; def err_case_not_in_switch : Error<"'case' statement not in switch statement">; def warn_bool_switch_condition : Warning< "switch condition has boolean value">, InGroup; def warn_case_value_overflow : Warning< "overflow converting case value to switch condition type (%0 to %1)">, InGroup; def err_duplicate_case : Error<"duplicate case value '%0'">; def err_duplicate_case_differing_expr : Error< "duplicate case value: '%0' and '%1' both equal '%2'">; def warn_case_empty_range : Warning<"empty case range specified">; def warn_missing_case_for_condition : Warning<"no case matching constant switch condition '%0'">; def warn_def_missing_case : Warning<"%plural{" "1:enumeration value %1 not explicitly handled in switch|" "2:enumeration values %1 and %2 not explicitly handled in switch|" "3:enumeration values %1, %2, and %3 not explicitly handled in switch|" ":%0 enumeration values not explicitly handled in switch: %1, %2, %3...}0">, InGroup, DefaultIgnore; def warn_missing_case : Warning<"%plural{" "1:enumeration value %1 not handled in switch|" "2:enumeration values %1 and %2 not handled in switch|" "3:enumeration values %1, %2, and %3 not handled in switch|" ":%0 enumeration values not handled in switch: %1, %2, %3...}0">, InGroup; def warn_unannotated_fallthrough : Warning< "unannotated fall-through between switch labels">, InGroup, DefaultIgnore; def warn_unannotated_fallthrough_per_function : Warning< "unannotated fall-through between switch labels in partly-annotated " "function">, InGroup, DefaultIgnore; def note_insert_fallthrough_fixit : Note< "insert '%0;' to silence this warning">; def note_insert_break_fixit : Note< "insert 'break;' to avoid fall-through">; def err_fallthrough_attr_wrong_target : Error< "%0 attribute is only allowed on empty statements">; def note_fallthrough_insert_semi_fixit : Note<"did you forget ';'?">; def err_fallthrough_attr_outside_switch : Error< "fallthrough annotation is outside switch statement">; def err_fallthrough_attr_invalid_placement : Error< "fallthrough annotation does not directly precede switch label">; def warn_fallthrough_attr_unreachable : Warning< "fallthrough annotation in unreachable code">, InGroup, DefaultIgnore; def warn_unreachable_default : Warning< "default label in switch which covers all enumeration values">, InGroup, DefaultIgnore; def warn_not_in_enum : Warning<"case value not in enumerated type %0">, InGroup; def warn_not_in_enum_assignment : Warning<"integer constant not in range " "of enumerated type %0">, InGroup>, DefaultIgnore; def err_typecheck_statement_requires_scalar : Error< "statement requires expression of scalar type (%0 invalid)">; def err_typecheck_statement_requires_integer : Error< "statement requires expression of integer type (%0 invalid)">; def err_multiple_default_labels_defined : Error< "multiple default labels in one switch">; def err_switch_multiple_conversions : Error< "multiple conversions from switch condition type %0 to an integral or " "enumeration type">; def note_switch_conversion : Note< "conversion to %select{integral|enumeration}0 type %1">; def err_switch_explicit_conversion : Error< "switch condition type %0 requires explicit conversion to %1">; def err_switch_incomplete_class_type : Error< "switch condition has incomplete class type %0">; def warn_empty_if_body : Warning< "if statement has empty body">, InGroup; def warn_empty_for_body : Warning< "for loop has empty body">, InGroup; def warn_empty_range_based_for_body : Warning< "range-based for loop has empty body">, InGroup; def warn_empty_while_body : Warning< "while loop has empty body">, InGroup; def warn_empty_switch_body : Warning< "switch statement has empty body">, InGroup; def note_empty_body_on_separate_line : Note< "put the semicolon on a separate line to silence this warning">; def err_va_start_used_in_non_variadic_function : Error< "'va_start' used in function with fixed args">; def err_va_start_used_in_wrong_abi_function : Error< "'va_start' used in %select{System V|Win64}0 ABI function">; def err_ms_va_start_used_in_sysv_function : Error< "'__builtin_ms_va_start' used in System V ABI function">; def warn_second_arg_of_va_start_not_last_named_param : Warning< "second argument to 'va_start' is not the last named parameter">, InGroup; def warn_va_start_type_is_undefined : Warning< "passing %select{an object that undergoes default argument promotion|" "an object of reference type|a parameter declared with the 'register' " "keyword}0 to 'va_start' has undefined behavior">, InGroup; def err_first_argument_to_va_arg_not_of_type_va_list : Error< "first argument to 'va_arg' is of type %0 and not 'va_list'">; def err_second_parameter_to_va_arg_incomplete: Error< "second argument to 'va_arg' is of incomplete type %0">; def err_second_parameter_to_va_arg_abstract: Error< "second argument to 'va_arg' is of abstract type %0">; def warn_second_parameter_to_va_arg_not_pod : Warning< "second argument to 'va_arg' is of non-POD type %0">, InGroup, DefaultError; def warn_second_parameter_to_va_arg_ownership_qualified : Warning< "second argument to 'va_arg' is of ARC ownership-qualified type %0">, InGroup, DefaultError; def warn_second_parameter_to_va_arg_never_compatible : Warning< "second argument to 'va_arg' is of promotable type %0; this va_arg has " "undefined behavior because arguments will be promoted to %1">, InGroup; def warn_return_missing_expr : Warning< "non-void %select{function|method}1 %0 should return a value">, DefaultError, InGroup; def ext_return_missing_expr : ExtWarn< "non-void %select{function|method}1 %0 should return a value">, DefaultError, InGroup; def ext_return_has_expr : ExtWarn< "%select{void function|void method|constructor|destructor}1 %0 " "should not return a value">, DefaultError, InGroup; def ext_return_has_void_expr : Extension< "void %select{function|method|block}1 %0 should not return void expression">; def err_return_init_list : Error< "%select{void function|void method|constructor|destructor}1 %0 " "must not return a value">; def err_ctor_dtor_returns_void : Error< "%select{constructor|destructor}1 %0 must not return void expression">; def warn_noreturn_function_has_return_expr : Warning< "function %0 declared 'noreturn' should not return">, InGroup; def warn_falloff_noreturn_function : Warning< "function declared 'noreturn' should not return">, InGroup; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; def err_noreturn_missing_on_first_decl : Error< "function declared '[[noreturn]]' after its first declaration">; def note_noreturn_missing_first_decl : Note< "declaration missing '[[noreturn]]' attribute is here">; def err_carries_dependency_missing_on_first_decl : Error< "%select{function|parameter}0 declared '[[carries_dependency]]' " "after its first declaration">; def note_carries_dependency_missing_first_decl : Note< "declaration missing '[[carries_dependency]]' attribute is here">; def err_carries_dependency_param_not_function_decl : Error< "'[[carries_dependency]]' attribute only allowed on parameter in a function " "declaration or lambda">; def err_block_on_nonlocal : Error< "__block attribute not allowed, only allowed on local variables">; def err_block_on_vm : Error< "__block attribute not allowed on declaration with a variably modified type">; def err_shufflevector_non_vector : Error< "first two arguments to __builtin_shufflevector must be vectors">; def err_shufflevector_incompatible_vector : Error< "first two arguments to __builtin_shufflevector must have the same type">; def err_shufflevector_nonconstant_argument : Error< "index for __builtin_shufflevector must be a constant integer">; def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; def err_convertvector_non_vector_type : Error< "second argument to __builtin_convertvector must be a vector type">; def err_convertvector_incompatible_vector : Error< "first two arguments to __builtin_convertvector must have the same number of elements">; def err_first_argument_to_cwsc_not_call : Error< "first argument to __builtin_call_with_static_chain must be a non-member call expression">; def err_first_argument_to_cwsc_block_call : Error< "first argument to __builtin_call_with_static_chain must not be a block call">; def err_first_argument_to_cwsc_builtin_call : Error< "first argument to __builtin_call_with_static_chain must not be a builtin call">; def err_first_argument_to_cwsc_pdtor_call : Error< "first argument to __builtin_call_with_static_chain must not be a pseudo-destructor call">; def err_second_argument_to_cwsc_not_pointer : Error< "second argument to __builtin_call_with_static_chain must be of pointer type">; def err_vector_incorrect_num_initializers : Error< "%select{too many|too few}0 elements in vector initialization (expected %1 elements, have %2)">; def err_altivec_empty_initializer : Error<"expected initializer">; def err_invalid_neon_type_code : Error< "incompatible constant for this __builtin_neon function">; def err_argument_invalid_range : Error< "argument should be a value from %0 to %1">; +def err_argument_not_multiple : Error< + "argument should be a multiple of %0">; def warn_neon_vector_initializer_non_portable : Warning< "vector initializers are not compatible with NEON intrinsics in big endian " "mode">, InGroup>; def note_neon_vector_initializer_non_portable : Note< "consider using vld1_%0%1() to initialize a vector from memory, or " "vcreate_%0%1() to initialize from an integer constant">; def note_neon_vector_initializer_non_portable_q : Note< "consider using vld1q_%0%1() to initialize a vector from memory, or " "vcombine_%0%1(vcreate_%0%1(), vcreate_%0%1()) to initialize from integer " "constants">; def err_systemz_invalid_tabort_code : Error< "invalid transaction abort code">; def err_64_bit_builtin_32_bit_tgt : Error< "this builtin is only available on 64-bit targets">; def err_ppc_builtin_only_on_pwr7 : Error< "this builtin is only valid on POWER7 or later CPUs">; def err_x86_builtin_32_bit_tgt : Error< "this builtin is only available on x86-64 targets">; def err_builtin_longjmp_unsupported : Error< "__builtin_longjmp is not supported for the current target">; def err_builtin_setjmp_unsupported : Error< "__builtin_setjmp is not supported for the current target">; def err_builtin_longjmp_invalid_val : Error< "argument to __builtin_longjmp must be a constant 1">; def err_builtin_requires_language : Error<"'%0' is only available in %1">; def err_constant_integer_arg_type : Error< "argument to %0 must be a constant integer">; def ext_mixed_decls_code : Extension< "ISO C90 forbids mixing declarations and code">, InGroup>; def err_non_local_variable_decl_in_for : Error< "declaration of non-local variable in 'for' loop">; def err_non_variable_decl_in_for : Error< "non-variable declaration in 'for' loop">; def err_toomany_element_decls : Error< "only one element declaration is allowed">; def err_selector_element_not_lvalue : Error< "selector element is not a valid lvalue">; def err_selector_element_type : Error< "selector element type %0 is not a valid object">; def err_selector_element_const_type : Error< "selector element of type %0 cannot be a constant l-value expression">; def err_collection_expr_type : Error< "the type %0 is not a pointer to a fast-enumerable object">; def warn_collection_expr_type : Warning< "collection expression type %0 may not respond to %1">; def err_invalid_conversion_between_ext_vectors : Error< "invalid conversion between ext-vector type %0 and %1">; def warn_duplicate_attribute_exact : Warning< "attribute %0 is already applied">, InGroup; def warn_duplicate_attribute : Warning< "attribute %0 is already applied with different parameters">, InGroup; def warn_sync_fetch_and_nand_semantics_change : Warning< "the semantics of this intrinsic changed with GCC " "version 4.4 - the newer semantics are provided here">, InGroup>; // Type def ext_invalid_sign_spec : Extension<"'%0' cannot be signed or unsigned">; def warn_receiver_forward_class : Warning< "receiver %0 is a forward class and corresponding @interface may not exist">, InGroup; def note_method_sent_forward_class : Note<"method %0 is used for the forward class">; def ext_missing_declspec : ExtWarn< "declaration specifier missing, defaulting to 'int'">; def ext_missing_type_specifier : ExtWarn< "type specifier missing, defaults to 'int'">, InGroup; def err_decimal_unsupported : Error< "GNU decimal type extension not supported">; def err_missing_type_specifier : Error< "C++ requires a type specifier for all declarations">; def err_objc_array_of_interfaces : Error< "array of interface %0 is invalid (probably should be an array of pointers)">; def ext_c99_array_usage : Extension< "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " "feature">, InGroup; def err_c99_array_usage_cxx : Error< "%select{qualifier in |static |}0array size %select{||'[*] '}0is a C99 " "feature, not permitted in C++">; def err_type_requires_extension : Error< "use of type %0 requires %1 extension to be enabled">; def err_type_unsupported : Error< "%0 is not supported on this target">; def err_nsconsumed_attribute_mismatch : Error< "overriding method has mismatched ns_consumed attribute on its" " parameter">; def err_nsreturns_retained_attribute_mismatch : Error< "overriding method has mismatched ns_returns_%select{not_retained|retained}0" " attributes">; def note_getter_unavailable : Note< "or because setter is declared here, but no getter method %0 is found">; def err_invalid_protocol_qualifiers : Error< "invalid protocol qualifiers on non-ObjC type">; def warn_ivar_use_hidden : Warning< "local declaration of %0 hides instance variable">, InGroup>; def warn_direct_initialize_call : Warning< "explicit call to +initialize results in duplicate call to +initialize">, InGroup; def warn_direct_super_initialize_call : Warning< "explicit call to [super initialize] should only be in implementation " "of +initialize">, InGroup; def error_ivar_use_in_class_method : Error< "instance variable %0 accessed in class method">; def error_implicit_ivar_access : Error< "instance variable %0 cannot be accessed because 'self' has been redeclared">; def error_private_ivar_access : Error<"instance variable %0 is private">, AccessControl; def error_protected_ivar_access : Error<"instance variable %0 is protected">, AccessControl; def warn_maynot_respond : Warning<"%0 may not respond to %1">; def ext_typecheck_base_super : Warning< "method parameter type " "%diff{$ does not match super class method parameter type $|" "does not match super class method parameter type}0,1">, InGroup, DefaultIgnore; def warn_missing_method_return_type : Warning< "method has no return type specified; defaults to 'id'">, InGroup, DefaultIgnore; def warn_direct_ivar_access : Warning<"instance variable %0 is being " "directly accessed">, InGroup>, DefaultIgnore; // Spell-checking diagnostics def err_unknown_typename : Error< "unknown type name %0">; def err_unknown_type_or_class_name_suggest : Error< "unknown %select{type|class}1 name %0; did you mean %2?">; def err_unknown_typename_suggest : Error< "unknown type name %0; did you mean %1?">; def err_unknown_nested_typename_suggest : Error< "no type named %0 in %1; did you mean %select{|simply }2%3?">; def err_no_member_suggest : Error<"no member named %0 in %1; did you mean %select{|simply }2%3?">; def err_undeclared_use_suggest : Error< "use of undeclared %0; did you mean %1?">; def err_undeclared_var_use_suggest : Error< "use of undeclared identifier %0; did you mean %1?">; def err_no_template_suggest : Error<"no template named %0; did you mean %1?">; def err_no_member_template_suggest : Error< "no template named %0 in %1; did you mean %select{|simply }2%3?">; def err_mem_init_not_member_or_class_suggest : Error< "initializer %0 does not name a non-static data member or base " "class; did you mean the %select{base class|member}1 %2?">; def err_field_designator_unknown_suggest : Error< "field designator %0 does not refer to any field in type %1; did you mean " "%2?">; def err_typecheck_member_reference_ivar_suggest : Error< "%0 does not have a member named %1; did you mean %2?">; def err_property_not_found_suggest : Error< "property %0 not found on object of type %1; did you mean %2?">; def err_class_property_found : Error< "property %0 is a class property; did you mean to access it with class '%1'?">; def err_ivar_access_using_property_syntax_suggest : Error< "property %0 not found on object of type %1; did you mean to access instance variable %2?">; def warn_property_access_suggest : Warning< "property %0 not found on object of type %1; did you mean to access property %2?">, InGroup; def err_property_found_suggest : Error< "property %0 found on object of type %1; did you mean to access " "it with the \".\" operator?">; def err_undef_interface_suggest : Error< "cannot find interface declaration for %0; did you mean %1?">; def warn_undef_interface_suggest : Warning< "cannot find interface declaration for %0; did you mean %1?">; def err_undef_superclass_suggest : Error< "cannot find interface declaration for %0, superclass of %1; did you mean " "%2?">; def err_undeclared_protocol_suggest : Error< "cannot find protocol declaration for %0; did you mean %1?">; def note_base_class_specified_here : Note< "base class %0 specified here">; def err_using_directive_suggest : Error< "no namespace named %0; did you mean %1?">; def err_using_directive_member_suggest : Error< "no namespace named %0 in %1; did you mean %select{|simply }2%3?">; def note_namespace_defined_here : Note<"namespace %0 defined here">; def err_sizeof_pack_no_pack_name_suggest : Error< "%0 does not refer to the name of a parameter pack; did you mean %1?">; def note_parameter_pack_here : Note<"parameter pack %0 declared here">; def err_uncasted_use_of_unknown_any : Error< "%0 has unknown type; cast it to its declared type to use it">; def err_uncasted_call_of_unknown_any : Error< "%0 has unknown return type; cast the call to its declared return type">; def err_uncasted_send_to_unknown_any_method : Error< "no known method %select{%objcinstance1|%objcclass1}0; cast the " "message send to the method's return type">; def err_unsupported_unknown_any_decl : Error< "%0 has unknown type, which is not supported for this kind of declaration">; def err_unsupported_unknown_any_expr : Error< "unsupported expression with unknown type">; def err_unsupported_unknown_any_call : Error< "call to unsupported expression with unknown type">; def err_unknown_any_addrof : Error< "the address of a declaration with unknown type " "can only be cast to a pointer type">; def err_unknown_any_var_function_type : Error< "variable %0 with unknown type cannot be given a function type">; def err_unknown_any_function : Error< "function %0 with unknown type must be given a function type">; def err_filter_expression_integral : Error< "filter expression type should be an integral value not %0">; def err_non_asm_stmt_in_naked_function : Error< "non-ASM statement in naked function is not supported">; def err_asm_naked_this_ref : Error< "'this' pointer references not allowed in naked functions">; def err_asm_naked_parm_ref : Error< "parameter references not allowed in naked functions">; // OpenCL warnings and errors. def err_invalid_astype_of_different_size : Error< "invalid reinterpretation: sizes of %0 and %1 must match">; def err_static_kernel : Error< "kernel functions cannot be declared static">; def err_opencl_ptrptr_kernel_param : Error< "kernel parameter cannot be declared as a pointer to a pointer">; def err_opencl_private_ptr_kernel_param : Error< "kernel parameter cannot be declared as a pointer to the __private address space">; def err_opencl_function_variable : Error< "%select{non-kernel function|function scope}0 variable cannot be declared in %1 address space">; def err_static_function_scope : Error< "variables in function scope cannot be declared static">; def err_opencl_bitfields : Error< "bitfields are not supported in OpenCL">; def err_opencl_vla : Error< "variable length arrays are not supported in OpenCL">; def err_bad_kernel_param_type : Error< "%0 cannot be used as the type of a kernel parameter">; def err_record_with_pointers_kernel_param : Error< "%select{struct|union}0 kernel parameters may not contain pointers">; def note_within_field_of_type : Note< "within field of type %0 declared here">; def note_illegal_field_declared_here : Note< "field of illegal %select{type|pointer type}0 %1 declared here">; def err_event_t_global_var : Error< "the event_t type cannot be used to declare a program scope variable">; def err_opencl_type_struct_or_union_field : Error< "the %0 type cannot be used to declare a structure or union field">; def err_event_t_addr_space_qual : Error< "the event_t type can only be used with __private address space qualifier">; def err_expected_kernel_void_return_type : Error< "kernel must have void return type">; def err_sampler_argument_required : Error< "sampler_t variable required - got %0">; def err_wrong_sampler_addressspace: Error< "sampler type cannot be used with the __local and __global address space qualifiers">; def error_opencl_cast_non_zero_to_event_t : Error< "cannot cast non-zero value '%0' to 'event_t'">; def err_opencl_global_invalid_addr_space : Error< "%select{program scope|static local|extern}0 variable must reside in %1 address space">; def err_missing_actual_pipe_type : Error< "missing actual type specifier for pipe">; def err_reference_pipe_type : Error < "pipes packet types cannot be of reference type">; def err_opencl_no_main : Error<"%select{function|kernel}0 cannot be called 'main'">; def err_opencl_kernel_attr : Error<"attribute %0 can only be applied to a kernel function">; def err_opencl_return_value_with_address_space : Error< "return value cannot be qualified with address space">; def err_opencl_constant_no_init : Error< "variable in constant address space must be initialized">; def err_atomic_init_constant : Error< "atomic variable can only be assigned to a compile time constant" " in the declaration statement in the program scope">; def err_opencl_implicit_vector_conversion : Error< "implicit conversions between vector types (%0 and %1) are not permitted">; def err_opencl_block_proto_variadic : Error< "invalid block prototype, variadic arguments are not allowed in OpenCL">; def err_opencl_invalid_type_array : Error< "array of %0 type is invalid in OpenCL">; def err_opencl_ternary_with_block : Error< "block type cannot be used as expression in ternary expression in OpenCL">; def err_opencl_pointer_to_type : Error< "pointer to type %0 is invalid in OpenCL">; def err_opencl_type_can_only_be_used_as_function_parameter : Error < "type %0 can only be used as a function parameter in OpenCL">; def warn_opencl_attr_deprecated_ignored : Warning < "%0 attribute is deprecated and ignored in OpenCL version %1">, InGroup; // OpenCL v2.0 s6.13.6 -- Builtin Pipe Functions def err_opencl_builtin_pipe_first_arg : Error< "first argument to %0 must be a pipe type">; def err_opencl_builtin_pipe_arg_num : Error< "invalid number of arguments to function: %0">; def err_opencl_builtin_pipe_invalid_arg : Error< "invalid argument type to function %0 (expecting %1 having %2)">; def err_opencl_builtin_pipe_invalid_access_modifier : Error< "invalid pipe access modifier (expecting %0)">; // OpenCL access qualifier def err_opencl_invalid_access_qualifier : Error< "access qualifier can only be used for pipe and image type">; def err_opencl_invalid_read_write : Error< "access qualifier %0 can not be used for %1 %select{|prior to OpenCL version 2.0}2">; def err_opencl_multiple_access_qualifiers : Error< "multiple access qualifiers">; def note_opencl_typedef_access_qualifier : Note< "previously declared '%0' here">; // OpenCL Section 6.8.g def err_opencl_unknown_type_specifier : Error< "OpenCL version %0 does not support the '%1' %select{type qualifier|storage class specifier}2">; // OpenCL v2.0 s6.12.5 Blocks restrictions def err_opencl_block_storage_type : Error< "the __block storage type is not permitted">; def err_opencl_invalid_block_declaration : Error< "invalid block variable declaration - must be %select{const qualified|initialized}0">; def err_opencl_extern_block_declaration : Error< "invalid block variable declaration - using 'extern' storage class is disallowed">; // OpenCL v2.0 s6.13.9 - Address space qualifier functions. def err_opencl_builtin_to_addr_arg_num : Error< "invalid number of arguments to function: %0">; def err_opencl_builtin_to_addr_invalid_arg : Error< "invalid argument %0 to function: %1, expecting a generic pointer argument">; // OpenCL v2.0 s6.13.17 Enqueue kernel restrictions. def err_opencl_enqueue_kernel_incorrect_args : Error< "illegal call to enqueue_kernel, incorrect argument types">; def err_opencl_enqueue_kernel_expected_type : Error< "illegal call to enqueue_kernel, expected %0 argument type">; def err_opencl_enqueue_kernel_local_size_args : Error< "mismatch in number of block parameters and local size arguments passed">; def err_opencl_enqueue_kernel_invalid_local_size_type : Error< "local memory sizes need to be specified as uint">; def err_opencl_enqueue_kernel_blocks_non_local_void_args : Error< "blocks used in device side enqueue are expected to have parameters of type 'local void*'">; def err_opencl_enqueue_kernel_blocks_no_args : Error< "blocks in this form of device side enqueue call are expected to have have no parameters">; } // end of sema category let CategoryName = "OpenMP Issue" in { // OpenMP support. def err_omp_expected_var_arg : Error< "%0 is not a global variable, static local variable or static data member">; def err_omp_expected_var_arg_suggest : Error< "%0 is not a global variable, static local variable or static data member; " "did you mean %1">; def err_omp_global_var_arg : Error< "arguments of '#pragma omp %0' must have %select{global storage|static storage duration}1">; def err_omp_ref_type_arg : Error< "arguments of '#pragma omp %0' cannot be of reference type %1">; def err_omp_region_not_file_context : Error< "directive must be at file or namespace scope">; def err_omp_var_scope : Error< "'#pragma omp %0' must appear in the scope of the %q1 variable declaration">; def err_omp_var_used : Error< "'#pragma omp %0' must precede all references to variable %q1">; def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is %select{thread-local|a global named register variable}1">; def err_omp_private_incomplete_type : Error< "a private variable with incomplete type %0">; def err_omp_firstprivate_incomplete_type : Error< "a firstprivate variable with incomplete type %0">; def err_omp_lastprivate_incomplete_type : Error< "a lastprivate variable with incomplete type %0">; def err_omp_reduction_incomplete_type : Error< "a reduction list item with incomplete type %0">; def err_omp_unexpected_clause_value : Error< "expected %0 in OpenMP clause '%1'">; def err_omp_expected_var_name_member_expr : Error< "expected variable name%select{| or data member of current class}0">; def err_omp_expected_var_name_member_expr_or_array_item : Error< "expected variable name%select{|, data member of current class}0, array element or array section">; def err_omp_expected_named_var_member_or_array_expression: Error< "expected expression containing only member accesses and/or array sections based on named variables">; def err_omp_bit_fields_forbidden_in_clause : Error< "bit fields cannot be used to specify storage in a '%0' clause">; def err_array_section_does_not_specify_contiguous_storage : Error< "array section does not specify contiguous storage">; def err_omp_union_type_not_allowed : Error< "mapped storage cannot be derived from a union">; def err_omp_expected_access_to_data_field : Error< "expected access to data field">; def err_omp_multiple_array_items_in_map_clause : Error< "multiple array elements associated with the same variable are not allowed in map clauses of the same construct">; def err_omp_pointer_mapped_along_with_derived_section : Error< "pointer cannot be mapped along with a section derived from itself">; def err_omp_original_storage_is_shared_and_does_not_contain : Error< "original storage of expression in data environment is shared but data environment do not fully contain mapped expression storage">; def err_omp_same_pointer_derreferenced : Error< "same pointer derreferenced in multiple different ways in map clause expressions">; def note_omp_task_predetermined_firstprivate_here : Note< "predetermined as a firstprivate in a task construct here">; def err_omp_threadprivate_incomplete_type : Error< "threadprivate variable with incomplete type %0">; def err_omp_no_dsa_for_variable : Error< "variable %0 must have explicitly specified data sharing attributes">; def err_omp_wrong_dsa : Error< "%0 variable cannot be %1">; def err_omp_variably_modified_type_not_supported : Error< "arguments of OpenMP clause '%0' in '#pragma omp %2' directive cannot be of variably-modified type %1">; def note_omp_explicit_dsa : Note< "defined as %0">; def note_omp_predetermined_dsa : Note< "%select{static data member is predetermined as shared|" "variable with static storage duration is predetermined as shared|" "loop iteration variable is predetermined as private|" "loop iteration variable is predetermined as linear|" "loop iteration variable is predetermined as lastprivate|" "constant variable is predetermined as shared|" "global variable is predetermined as shared|" "non-shared variable in a task construct is predetermined as firstprivate|" "variable with automatic storage duration is predetermined as private}0" "%select{|; perhaps you forget to enclose 'omp %2' directive into a parallel or another task region?}1">; def note_omp_implicit_dsa : Note< "implicitly determined as %0">; def err_omp_loop_var_dsa : Error< "loop iteration variable in the associated loop of 'omp %1' directive may not be %0, predetermined as %2">; def err_omp_not_for : Error< "%select{statement after '#pragma omp %1' must be a for loop|" "expected %2 for loops after '#pragma omp %1'%select{|, but found only %4}3}0">; def note_omp_collapse_ordered_expr : Note< "as specified in %select{'collapse'|'ordered'|'collapse' and 'ordered'}0 clause%select{||s}0">; def err_omp_negative_expression_in_clause : Error< "argument to '%0' clause must be a %select{non-negative|strictly positive}1 integer value">; def err_omp_not_integral : Error< "expression must have integral or unscoped enumeration " "type, not %0">; def err_omp_threadprivate_in_target : Error< "threadprivate variables cannot be used in target constructs">; def err_omp_incomplete_type : Error< "expression has incomplete class type %0">; def err_omp_explicit_conversion : Error< "expression requires explicit conversion from %0 to %1">; def note_omp_conversion_here : Note< "conversion to %select{integral|enumeration}0 type %1 declared here">; def err_omp_ambiguous_conversion : Error< "ambiguous conversion from type %0 to an integral or unscoped " "enumeration type">; def err_omp_required_access : Error< "%0 variable must be %1">; def err_omp_const_variable : Error< "const-qualified variable cannot be %0">; def err_omp_const_reduction_list_item : Error< "const-qualified list item cannot be reduction">; def err_omp_linear_incomplete_type : Error< "a linear variable with incomplete type %0">; def err_omp_linear_expected_int_or_ptr : Error< "argument of a linear clause should be of integral or pointer " "type, not %0">; def warn_omp_linear_step_zero : Warning< "zero linear step (%0 %select{|and other variables in clause }1should probably be const)">, InGroup; def warn_omp_alignment_not_power_of_two : Warning< "aligned clause will be ignored because the requested alignment is not a power of 2">, InGroup; def err_omp_enclosed_declare_target : Error< "declare target region may not be enclosed within another declare target region">; def err_omp_invalid_target_decl : Error< "%0 used in declare target directive is not a variable or a function name">; def err_omp_declare_target_multiple : Error< "%0 appears multiple times in clauses on the same declare target directive">; def err_omp_declare_target_to_and_link : Error< "%0 must not appear in both clauses 'to' and 'link'">; def warn_omp_not_in_target_context : Warning< "declaration is not declared in any declare target region">, InGroup; def err_omp_aligned_expected_array_or_ptr : Error< "argument of aligned clause should be array" "%select{ or pointer|, pointer, reference to array or reference to pointer}1" ", not %0">; def err_omp_aligned_twice : Error< "%select{a variable|a parameter|'this'}0 cannot appear in more than one aligned clause">; def err_omp_local_var_in_threadprivate_init : Error< "variable with local storage in initial value of threadprivate variable">; def err_omp_loop_not_canonical_init : Error< "initialization clause of OpenMP for loop is not in canonical form " "('var = init' or 'T var = init')">; def ext_omp_loop_not_canonical_init : ExtWarn< "initialization clause of OpenMP for loop is not in canonical form " "('var = init' or 'T var = init')">, InGroup; def err_omp_loop_not_canonical_cond : Error< "condition of OpenMP for loop must be a relational comparison " "('<', '<=', '>', or '>=') of loop variable %0">; def err_omp_loop_not_canonical_incr : Error< "increment clause of OpenMP for loop must perform simple addition " "or subtraction on loop variable %0">; def err_omp_loop_variable_type : Error< "variable must be of integer or %select{pointer|random access iterator}0 type">; def err_omp_loop_incr_not_compatible : Error< "increment expression must cause %0 to %select{decrease|increase}1 " "on each iteration of OpenMP for loop">; def note_omp_loop_cond_requres_compatible_incr : Note< "loop step is expected to be %select{negative|positive}0 due to this condition">; def err_omp_loop_diff_cxx : Error< "could not calculate number of iterations calling 'operator-' with " "upper and lower loop bounds">; def err_omp_loop_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP for loop">; def err_omp_simd_region_cannot_use_stmt : Error< "'%0' statement cannot be used in OpenMP simd region">; def warn_omp_loop_64_bit_var : Warning< "OpenMP loop iteration variable cannot have more than 64 bits size and will be narrowed">, InGroup; def err_omp_unknown_reduction_identifier : Error< "incorrect reduction identifier, expected one of '+', '-', '*', '&', '|', '^', " "'&&', '||', 'min' or 'max' or declare reduction for type %0">; def err_omp_not_resolved_reduction_identifier : Error< "unable to resolve declare reduction construct for type %0">; def err_omp_reduction_ref_type_arg : Error< "argument of OpenMP clause 'reduction' must reference the same object in all threads">; def err_omp_clause_not_arithmetic_type_arg : Error< "arguments of OpenMP clause 'reduction' for 'min' or 'max' must be of %select{scalar|arithmetic}0 type">; def err_omp_clause_floating_type_arg : Error< "arguments of OpenMP clause 'reduction' with bitwise operators cannot be of floating type">; def err_omp_once_referenced : Error< "variable can appear only once in OpenMP '%0' clause">; def err_omp_once_referenced_in_target_update : Error< "variable can appear only once in OpenMP 'target update' construct">; def note_omp_referenced : Note< "previously referenced here">; def err_omp_reduction_in_task : Error< "reduction variables may not be accessed in an explicit task">; def err_omp_reduction_id_not_compatible : Error< "list item of type %0 is not valid for specified reduction operation: unable to provide default initialization value">; def err_omp_prohibited_region : Error< "region cannot be%select{| closely}0 nested inside '%1' region" "%select{|; perhaps you forget to enclose 'omp %3' directive into a parallel region?|" "; perhaps you forget to enclose 'omp %3' directive into a for or a parallel for region with 'ordered' clause?|" "; perhaps you forget to enclose 'omp %3' directive into a target region?|" "; perhaps you forget to enclose 'omp %3' directive into a teams region?}2">; def err_omp_prohibited_region_simd : Error< "OpenMP constructs may not be nested inside a simd region">; def err_omp_prohibited_region_atomic : Error< "OpenMP constructs may not be nested inside an atomic region">; def err_omp_prohibited_region_critical_same_name : Error< "cannot nest 'critical' regions having the same name %0">; def note_omp_previous_critical_region : Note< "previous 'critical' region starts here">; def err_omp_sections_not_compound_stmt : Error< "the statement for '#pragma omp sections' must be a compound statement">; def err_omp_parallel_sections_not_compound_stmt : Error< "the statement for '#pragma omp parallel sections' must be a compound statement">; def err_omp_orphaned_section_directive : Error< "%select{orphaned 'omp section' directives are prohibited, it|'omp section' directive}0" " must be closely nested to a sections region%select{|, not a %1 region}0">; def err_omp_sections_substmt_not_section : Error< "statement in 'omp sections' directive must be enclosed into a section region">; def err_omp_parallel_sections_substmt_not_section : Error< "statement in 'omp parallel sections' directive must be enclosed into a section region">; def err_omp_parallel_reduction_in_task_firstprivate : Error< "argument of a reduction clause of a %0 construct must not appear in a firstprivate clause on a task construct">; def err_omp_atomic_read_not_expression_statement : Error< "the statement for 'atomic read' must be an expression statement of form 'v = x;'," " where v and x are both lvalue expressions with scalar type">; def note_omp_atomic_read_write: Note< "%select{expected an expression statement|expected built-in assignment operator|expected expression of scalar type|expected lvalue expression}0">; def err_omp_atomic_write_not_expression_statement : Error< "the statement for 'atomic write' must be an expression statement of form 'x = expr;'," " where x is a lvalue expression with scalar type">; def err_omp_atomic_update_not_expression_statement : Error< "the statement for 'atomic update' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," " where x is an l-value expression with scalar type">; def err_omp_atomic_not_expression_statement : Error< "the statement for 'atomic' must be an expression statement of form '++x;', '--x;', 'x++;', 'x--;', 'x binop= expr;', 'x = x binop expr' or 'x = expr binop x'," " where x is an l-value expression with scalar type">; def note_omp_atomic_update: Note< "%select{expected an expression statement|expected built-in binary or unary operator|expected unary decrement/increment operation|" "expected expression of scalar type|expected assignment expression|expected built-in binary operator|" "expected one of '+', '*', '-', '/', '&', '^', '%|', '<<', or '>>' built-in operations|expected in right hand side of expression}0">; def err_omp_atomic_capture_not_expression_statement : Error< "the statement for 'atomic capture' must be an expression statement of form 'v = ++x;', 'v = --x;', 'v = x++;', 'v = x--;', 'v = x binop= expr;', 'v = x = x binop expr' or 'v = x = expr binop x'," " where x and v are both l-value expressions with scalar type">; def err_omp_atomic_capture_not_compound_statement : Error< "the statement for 'atomic capture' must be a compound statement of form '{v = x; x binop= expr;}', '{x binop= expr; v = x;}'," " '{v = x; x = x binop expr;}', '{v = x; x = expr binop x;}', '{x = x binop expr; v = x;}', '{x = expr binop x; v = x;}' or '{v = x; x = expr;}'," " '{v = x; x++;}', '{v = x; ++x;}', '{++x; v = x;}', '{x++; v = x;}', '{v = x; x--;}', '{v = x; --x;}', '{--x; v = x;}', '{x--; v = x;}'" " where x is an l-value expression with scalar type">; def note_omp_atomic_capture: Note< "%select{expected assignment expression|expected compound statement|expected exactly two expression statements|expected in right hand side of the first expression}0">; def err_omp_atomic_several_clauses : Error< "directive '#pragma omp atomic' cannot contain more than one 'read', 'write', 'update' or 'capture' clause">; def note_omp_atomic_previous_clause : Note< "'%0' clause used here">; def err_omp_target_contains_not_only_teams : Error< "target construct with nested teams region contains statements outside of the teams construct">; def note_omp_nested_teams_construct_here : Note< "nested teams construct here">; def note_omp_nested_statement_here : Note< "%select{statement|directive}0 outside teams construct here">; def err_omp_single_copyprivate_with_nowait : Error< "the 'copyprivate' clause must not be used with the 'nowait' clause">; def note_omp_nowait_clause_here : Note< "'nowait' clause is here">; def err_omp_single_decl_in_declare_simd : Error< "single declaration is expected after 'declare simd' directive">; def err_omp_function_expected : Error< "'#pragma omp declare simd' can only be applied to functions">; def err_omp_wrong_cancel_region : Error< "one of 'for', 'parallel', 'sections' or 'taskgroup' is expected">; def err_omp_parent_cancel_region_nowait : Error< "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be nowait">; def err_omp_parent_cancel_region_ordered : Error< "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be ordered">; def err_omp_reduction_wrong_type : Error<"reduction type cannot be %select{qualified with 'const', 'volatile' or 'restrict'|a function|a reference|an array}0 type">; def err_omp_wrong_var_in_declare_reduction : Error<"only %select{'omp_priv' or 'omp_orig'|'omp_in' or 'omp_out'}0 variables are allowed in %select{initializer|combiner}0 expression">; def err_omp_declare_reduction_redefinition : Error<"redefinition of user-defined reduction for type %0">; def err_omp_array_section_use : Error<"OpenMP array section is not allowed here">; def err_omp_typecheck_section_value : Error< "subscripted value is not an array or pointer">; def err_omp_typecheck_section_not_integer : Error< "array section %select{lower bound|length}0 is not an integer">; def err_omp_section_function_type : Error< "section of pointer to function type %0">; def warn_omp_section_is_char : Warning<"array section %select{lower bound|length}0 is of type 'char'">, InGroup, DefaultIgnore; def err_omp_section_incomplete_type : Error< "section of pointer to incomplete type %0">; def err_omp_section_negative : Error< "section %select{lower bound|length}0 is evaluated to a negative value %1">; def err_omp_section_length_undefined : Error< "section length is unspecified and cannot be inferred because subscripted value is %select{not an array|an array of unknown bound}0">; def err_omp_wrong_linear_modifier : Error< "expected %select{'val' modifier|one of 'ref', val' or 'uval' modifiers}0">; def err_omp_wrong_linear_modifier_non_reference : Error< "variable of non-reference type %0 can be used only with 'val' modifier, but used with '%1'">; def err_omp_wrong_simdlen_safelen_values : Error< "the value of 'simdlen' parameter must be less than or equal to the value of the 'safelen' parameter">; def err_omp_wrong_if_directive_name_modifier : Error< "directive name modifier '%0' is not allowed for '#pragma omp %1'">; def err_omp_no_more_if_clause : Error< "no more 'if' clause is allowed">; def err_omp_unnamed_if_clause : Error< "expected %select{|one of}0 %1 directive name modifier%select{|s}0">; def note_omp_previous_named_if_clause : Note< "previous clause with directive name modifier specified here">; def err_omp_ordered_directive_with_param : Error< "'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">; def err_omp_ordered_directive_without_param : Error< "'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">; def note_omp_ordered_param : Note< "'ordered' clause with specified parameter">; def err_omp_expected_base_var_name : Error< "expected variable name as a base of the array %select{subscript|section}0">; def err_omp_map_shared_storage : Error< "variable already marked as mapped in current construct">; def err_omp_not_mappable_type : Error< "type %0 is not mappable to target">; def err_omp_invalid_map_type_for_directive : Error< "%select{map type '%1' is not allowed|map type must be specified}0 for '#pragma omp %2'">; def err_omp_no_map_for_directive : Error< "expected at least one map clause for '#pragma omp %0'">; def note_omp_polymorphic_in_target : Note< "mappable type cannot be polymorphic">; def note_omp_static_member_in_target : Note< "mappable type cannot contain static members">; def err_omp_threadprivate_in_clause : Error< "threadprivate variables are not allowed in '%0' clause">; def err_omp_wrong_ordered_loop_count : Error< "the parameter of the 'ordered' clause must be greater than or equal to the parameter of the 'collapse' clause">; def note_collapse_loop_count : Note< "parameter of the 'collapse' clause">; def err_omp_grainsize_num_tasks_mutually_exclusive : Error< "'%0' and '%1' clause are mutually exclusive and may not appear on the same directive">; def note_omp_previous_grainsize_num_tasks : Note< "'%0' clause is specified here">; def err_omp_hint_clause_no_name : Error< "the name of the construct must be specified in presence of 'hint' clause">; def err_omp_critical_with_hint : Error< "constructs with the same name must have a 'hint' clause with the same value">; def note_omp_critical_hint_here : Note< "%select{|previous }0'hint' clause with value '%1'">; def note_omp_critical_no_hint : Note< "%select{|previous }0directive with no 'hint' clause specified">; def err_omp_firstprivate_distribute_private_teams : Error< "private variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; def err_omp_firstprivate_and_lastprivate_in_distribute : Error< "lastprivate variable cannot be firstprivate in '#pragma omp distribute'">; def err_omp_firstprivate_distribute_in_teams_reduction : Error< "reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">; def err_omp_depend_clause_thread_simd : Error< "'depend' clauses cannot be mixed with '%0' clause">; def err_omp_depend_sink_expected_loop_iteration : Error< "expected %0 loop iteration variable">; def err_omp_depend_sink_unexpected_expr : Error< "unexpected expression: number of expressions is larger than the number of associated loops">; def err_omp_depend_sink_expected_plus_minus : Error< "expected '+' or '-' operation">; def err_omp_depend_sink_source_not_allowed : Error< "'depend(%select{source|sink:vec}0)' clause%select{|s}0 cannot be mixed with 'depend(%select{sink:vec|source}0)' clause%select{s|}0">; def err_omp_linear_ordered : Error< "'linear' clause cannot be specified along with 'ordered' clause with a parameter">; def err_omp_unexpected_schedule_modifier : Error< "modifier '%0' cannot be used along with modifier '%1'">; def err_omp_schedule_nonmonotonic_static : Error< "'nonmonotonic' modifier can only be specified with 'dynamic' or 'guided' schedule kind">; def err_omp_schedule_nonmonotonic_ordered : Error< "'schedule' clause with 'nonmonotonic' modifier cannot be specified if an 'ordered' clause is specified">; def err_omp_ordered_simd : Error< "'ordered' clause with a parameter can not be specified in '#pragma omp %0' directive">; def err_omp_variable_in_map_and_dsa : Error< "%0 variable cannot be in a map clause in '#pragma omp %1' directive">; def err_omp_param_or_this_in_clause : Error< "expected reference to one of the parameters of function %0%select{| or 'this'}1">; def err_omp_expected_uniform_param : Error< "expected a reference to a parameter specified in a 'uniform' clause">; def err_omp_expected_int_param : Error< "expected a reference to an integer-typed parameter">; def err_omp_at_least_one_motion_clause_required : Error< "expected at least one 'to' clause or 'from' clause specified to '#pragma omp target update'">; def err_omp_usedeviceptr_not_a_pointer : Error< "expected pointer or reference to pointer in 'use_device_ptr' clause">; def err_omp_argument_type_isdeviceptr : Error < "expected pointer, array, reference to pointer, or reference to array in 'is_device_ptr clause'">; def warn_omp_nesting_simd : Warning< "OpenMP only allows an ordered construct with the simd clause nested in a simd construct">, InGroup; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { // Objective-C related result type compatibility def warn_related_result_type_compatibility_class : Warning< "method is expected to return an instance of its class type " "%diff{$, but is declared to return $|" ", but is declared to return different type}0,1">; def warn_related_result_type_compatibility_protocol : Warning< "protocol method is expected to return an instance of the implementing " "class, but is declared to return %0">; def note_related_result_type_family : Note< "%select{overridden|current}0 method is part of the '%select{|alloc|copy|init|" "mutableCopy|new|autorelease|dealloc|finalize|release|retain|retainCount|" "self}1' method family%select{| and is expected to return an instance of its " "class type}0">; def note_related_result_type_overridden : Note< "overridden method returns an instance of its class type">; def note_related_result_type_inferred : Note< "%select{class|instance}0 method %1 is assumed to return an instance of " "its receiver type (%2)">; def note_related_result_type_explicit : Note< "%select{overridden|current}0 method is explicitly declared 'instancetype'" "%select{| and is expected to return an instance of its class type}0">; } let CategoryName = "Modules Issue" in { def err_module_private_specialization : Error< "%select{template|partial|member}0 specialization cannot be " "declared __module_private__">; def err_module_private_local : Error< "%select{local variable|parameter|typedef}0 %1 cannot be declared " "__module_private__">; def err_module_private_local_class : Error< "local %select{struct|interface|union|class|enum}0 cannot be declared " "__module_private__">; def err_module_unimported_use : Error< "%select{declaration|definition|default argument|" "explicit specialization|partial specialization}0 of %1 must be imported " "from module '%2' before it is required">; def err_module_unimported_use_header : Error< "missing '#include %3'; " "%select{declaration|definition|default argument|" "explicit specialization|partial specialization}0 of %1 must be imported " "from module '%2' before it is required">; def err_module_unimported_use_multiple : Error< "%select{declaration|definition|default argument|" "explicit specialization|partial specialization}0 of %1 must be imported " "from one of the following modules before it is required:%2">; def ext_module_import_in_extern_c : ExtWarn< "import of C++ module '%0' appears within extern \"C\" language linkage " "specification">, DefaultError, InGroup>; def note_module_import_in_extern_c : Note< "extern \"C\" language linkage specification begins here">; def err_module_import_not_at_top_level_fatal : Error< "import of module '%0' appears within %1">, DefaultFatal; def ext_module_import_not_at_top_level_noop : ExtWarn< "redundant #include of module '%0' appears within %1">, DefaultError, InGroup>; def note_module_import_not_at_top_level : Note<"%0 begins here">; def err_module_self_import : Error< "import of module '%0' appears within same top-level module '%1'">; def err_module_import_in_implementation : Error< "@import of module '%0' in implementation of '%1'; use #import">; def ext_equivalent_internal_linkage_decl_in_modules : ExtWarn< "ambiguous use of internal linkage declaration %0 defined in multiple modules">, InGroup>; def note_equivalent_internal_linkage_decl : Note< "declared here%select{ in module '%1'|}0">; } let CategoryName = "Coroutines Issue" in { def err_return_in_coroutine : Error< "return statement not allowed in coroutine; did you mean 'co_return'?">; def note_declared_coroutine_here : Note< "function is a coroutine due to use of " "'%select{co_await|co_yield|co_return}0' here">; def err_coroutine_objc_method : Error< "Objective-C methods as coroutines are not yet supported">; def err_coroutine_unevaluated_context : Error< "'%0' cannot be used in an unevaluated context">; def err_coroutine_outside_function : Error< "'%0' cannot be used outside a function">; def err_coroutine_ctor_dtor : Error< "'%1' cannot be used in a %select{constructor|destructor}0">; def err_coroutine_constexpr : Error< "'%0' cannot be used in a constexpr function">; def err_coroutine_varargs : Error< "'%0' cannot be used in a varargs function">; def ext_coroutine_without_co_await_co_yield : ExtWarn< "'co_return' used in a function " "that uses neither 'co_await' nor 'co_yield'">, InGroup>; def err_implied_std_coroutine_traits_not_found : Error< "you need to include before defining a coroutine">; def err_malformed_std_coroutine_traits : Error< "'std::coroutine_traits' must be a class template">; def err_implied_std_coroutine_traits_promise_type_not_found : Error< "this function cannot be a coroutine: %q0 has no member named 'promise_type'">; def err_implied_std_coroutine_traits_promise_type_not_class : Error< "this function cannot be a coroutine: %0 is not a class">; def err_coroutine_traits_missing_specialization : Error< "this function cannot be a coroutine: missing definition of " "specialization %q0">; } let CategoryName = "Documentation Issue" in { def warn_not_a_doxygen_trailing_member_comment : Warning< "not a Doxygen trailing comment">, InGroup, DefaultIgnore; } // end of documentation issue category let CategoryName = "Instrumentation Issue" in { def warn_profile_data_out_of_date : Warning< "profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1" " no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">, InGroup; def warn_profile_data_unprofiled : Warning< "no profile data available for file \"%0\"">, InGroup; } // end of instrumentation issue category let CategoryName = "Nullability Issue" in { def warn_mismatched_nullability_attr : Warning< "nullability specifier %0 conflicts with existing specifier %1">, InGroup; def warn_nullability_declspec : Warning< "nullability specifier %0 cannot be applied " "to non-pointer type %1; did you mean to apply the specifier to the " "%select{pointer|block pointer|member pointer|function pointer|" "member function pointer}2?">, InGroup, DefaultError; def note_nullability_here : Note<"%0 specified here">; def err_nullability_nonpointer : Error< "nullability specifier %0 cannot be applied to non-pointer type %1">; def warn_nullability_lost : Warning< "implicit conversion from nullable pointer %0 to non-nullable pointer " "type %1">, InGroup, DefaultIgnore; def err_nullability_cs_multilevel : Error< "nullability keyword %0 cannot be applied to multi-level pointer type %1">; def note_nullability_type_specifier : Note< "use nullability type specifier %0 to affect the innermost " "pointer type of %1">; def warn_null_resettable_setter : Warning< "synthesized setter %0 for null_resettable property %1 does not handle nil">, InGroup; def warn_nullability_missing : Warning< "%select{pointer|block pointer|member pointer}0 is missing a nullability " "type specifier (_Nonnull, _Nullable, or _Null_unspecified)">, InGroup; def err_objc_type_arg_explicit_nullability : Error< "type argument %0 cannot explicitly specify nullability">; def err_objc_type_param_bound_explicit_nullability : Error< "type parameter %0 bound %1 cannot explicitly specify nullability">; } let CategoryName = "Generics Issue" in { def err_objc_type_param_bound_nonobject : Error< "type bound %0 for type parameter %1 is not an Objective-C pointer type">; def err_objc_type_param_bound_missing_pointer : Error< "missing '*' in type bound %0 for type parameter %1">; def err_objc_type_param_bound_qualified : Error< "type bound %1 for type parameter %0 cannot be qualified with '%2'">; def err_objc_type_param_redecl : Error< "redeclaration of type parameter %0">; def err_objc_type_param_arity_mismatch : Error< "%select{forward class declaration|class definition|category|extension}0 has " "too %select{few|many}1 type parameters (expected %2, have %3)">; def err_objc_type_param_bound_conflict : Error< "type bound %0 for type parameter %1 conflicts with " "%select{implicit|previous}2 bound %3%select{for type parameter %5|}4">; def err_objc_type_param_variance_conflict : Error< "%select{in|co|contra}0variant type parameter %1 conflicts with previous " "%select{in|co|contra}2variant type parameter %3">; def note_objc_type_param_here : Note<"type parameter %0 declared here">; def err_objc_type_param_bound_missing : Error< "missing type bound %0 for type parameter %1 in %select{@interface|@class}2">; def err_objc_parameterized_category_nonclass : Error< "%select{extension|category}0 of non-parameterized class %1 cannot have type " "parameters">; def err_objc_parameterized_forward_class : Error< "forward declaration of non-parameterized class %0 cannot have type " "parameters">; def err_objc_parameterized_forward_class_first : Error< "class %0 previously declared with type parameters">; def err_objc_type_arg_missing_star : Error< "type argument %0 must be a pointer (requires a '*')">; def err_objc_type_arg_qualified : Error< "type argument %0 cannot be qualified with '%1'">; def err_objc_type_arg_missing : Error< "no type or protocol named %0">; def err_objc_type_args_and_protocols : Error< "angle brackets contain both a %select{type|protocol}0 (%1) and a " "%select{protocol|type}0 (%2)">; def err_objc_type_args_non_class : Error< "type arguments cannot be applied to non-class type %0">; def err_objc_type_args_non_parameterized_class : Error< "type arguments cannot be applied to non-parameterized class %0">; def err_objc_type_args_specialized_class : Error< "type arguments cannot be applied to already-specialized class type %0">; def err_objc_type_args_wrong_arity : Error< "too %select{many|few}0 type arguments for class %1 (have %2, expected %3)">; } def err_objc_type_arg_not_id_compatible : Error< "type argument %0 is neither an Objective-C object nor a block type">; def err_objc_type_arg_does_not_match_bound : Error< "type argument %0 does not satisfy the bound (%1) of type parameter %2">; def warn_objc_redundant_qualified_class_type : Warning< "parameterized class %0 already conforms to the protocols listed; did you " "forget a '*'?">, InGroup; def warn_block_literal_attributes_on_omitted_return_type : Warning< "attribute %0 ignored, because it cannot be applied to omitted return type">, InGroup; def warn_block_literal_qualifiers_on_omitted_return_type : Warning< "'%0' qualifier on omitted return type %1 has no effect">, InGroup; } // end of sema component. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0d1c8fa48cdc..437a44a30711 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -1,9662 +1,9664 @@ //===--- Sema.h - Semantic Analysis & AST Building --------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the Sema class, which performs semantic analysis and // builds ASTs. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SEMA_SEMA_H #define LLVM_CLANG_SEMA_SEMA_H #include "clang/AST/Attr.h" #include "clang/AST/Availability.h" #include "clang/AST/DeclarationName.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/LocInfoType.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Sema/AnalysisBasedWarnings.h" #include "clang/Sema/CleanupInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/TinyPtrVector.h" #include #include #include #include namespace llvm { class APSInt; template struct DenseMapInfo; template class DenseSet; class SmallBitVector; class InlineAsmIdentifierInfo; } namespace clang { class ADLResult; class ASTConsumer; class ASTContext; class ASTMutationListener; class ASTReader; class ASTWriter; class ArrayType; class AttributeList; class BlockDecl; class CapturedDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; typedef SmallVector CXXCastPath; class CXXConstructorDecl; class CXXConversionDecl; class CXXDeleteExpr; class CXXDestructorDecl; class CXXFieldCollector; class CXXMemberCallExpr; class CXXMethodDecl; class CXXScopeSpec; class CXXTemporary; class CXXTryStmt; class CallExpr; class ClassTemplateDecl; class ClassTemplatePartialSpecializationDecl; class ClassTemplateSpecializationDecl; class VarTemplatePartialSpecializationDecl; class CodeCompleteConsumer; class CodeCompletionAllocator; class CodeCompletionTUInfo; class CodeCompletionResult; class Decl; class DeclAccessPair; class DeclContext; class DeclRefExpr; class DeclaratorDecl; class DeducedTemplateArgument; class DependentDiagnostic; class DesignatedInitExpr; class Designation; class EnableIfAttr; class EnumConstantDecl; class Expr; class ExtVectorType; class FormatAttr; class FriendDecl; class FunctionDecl; class FunctionProtoType; class FunctionTemplateDecl; class ImplicitConversionSequence; class InitListExpr; class InitializationKind; class InitializationSequence; class InitializedEntity; class IntegerLiteral; class LabelStmt; class LambdaExpr; class LangOptions; class LocalInstantiationScope; class LookupResult; class MacroInfo; typedef ArrayRef> ModuleIdPath; class ModuleLoader; class MultiLevelTemplateArgumentList; class NamedDecl; class ObjCCategoryDecl; class ObjCCategoryImplDecl; class ObjCCompatibleAliasDecl; class ObjCContainerDecl; class ObjCImplDecl; class ObjCImplementationDecl; class ObjCInterfaceDecl; class ObjCIvarDecl; template class ObjCList; class ObjCMessageExpr; class ObjCMethodDecl; class ObjCPropertyDecl; class ObjCProtocolDecl; class OMPThreadPrivateDecl; class OMPDeclareReductionDecl; class OMPDeclareSimdDecl; class OMPClause; struct OverloadCandidate; class OverloadCandidateSet; class OverloadExpr; class ParenListExpr; class ParmVarDecl; class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; class StandardConversionSequence; class Stmt; class StringLiteral; class SwitchStmt; class TemplateArgument; class TemplateArgumentList; class TemplateArgumentLoc; class TemplateDecl; class TemplateParameterList; class TemplatePartialOrderingContext; class TemplateTemplateParmDecl; class Token; class TypeAliasDecl; class TypedefDecl; class TypedefNameDecl; class TypeLoc; class TypoCorrectionConsumer; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; class UnresolvedSetImpl; class UnresolvedSetIterator; class UsingDecl; class UsingShadowDecl; class ValueDecl; class VarDecl; class VarTemplateSpecializationDecl; class VisibilityAttr; class VisibleDeclConsumer; class IndirectFieldDecl; struct DeductionFailureInfo; class TemplateSpecCandidateSet; namespace sema { class AccessedEntity; class BlockScopeInfo; class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; class DelayedDiagnosticPool; class FunctionScopeInfo; class LambdaScopeInfo; class PossiblyUnreachableDiag; class TemplateDeductionInfo; } namespace threadSafety { class BeforeSet; void threadSafetyCleanup(BeforeSet* Cache); } // FIXME: No way to easily map from TemplateTypeParmTypes to // TemplateTypeParmDecls, so we have this horrible PointerUnion. typedef std::pair, SourceLocation> UnexpandedParameterPack; /// Describes whether we've seen any nullability information for the given /// file. struct FileNullability { /// The first pointer declarator (of any pointer kind) in the file that does /// not have a corresponding nullability annotation. SourceLocation PointerLoc; /// Which kind of pointer declarator we saw. uint8_t PointerKind; /// Whether we saw any type nullability annotations in the given file. bool SawTypeNullability = false; }; /// A mapping from file IDs to a record of whether we've seen nullability /// information in that file. class FileNullabilityMap { /// A mapping from file IDs to the nullability information for each file ID. llvm::DenseMap Map; /// A single-element cache based on the file ID. struct { FileID File; FileNullability Nullability; } Cache; public: FileNullability &operator[](FileID file) { // Check the single-element cache. if (file == Cache.File) return Cache.Nullability; // It's not in the single-element cache; flush the cache if we have one. if (!Cache.File.isInvalid()) { Map[Cache.File] = Cache.Nullability; } // Pull this entry into the cache. Cache.File = file; Cache.Nullability = Map[file]; return Cache.Nullability; } }; /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema &) = delete; void operator=(const Sema &) = delete; ///\brief Source of additional semantic information. ExternalSemaSource *ExternalSource; ///\brief Whether Sema has generated a multiplexer and has to delete it. bool isMultiplexExternalSource; static bool mightHaveNonExternalLinkage(const DeclaratorDecl *FD); bool isVisibleSlow(const NamedDecl *D); bool shouldLinkPossiblyHiddenDecl(const NamedDecl *Old, const NamedDecl *New) { // We are about to link these. It is now safe to compute the linkage of // the new decl. If the new decl has external linkage, we will // link it with the hidden decl (which also has external linkage) and // it will keep having external linkage. If it has internal linkage, we // will not link it. Since it has no previous decls, it will remain // with internal linkage. return isVisible(Old) || New->isExternallyVisible(); } bool shouldLinkPossiblyHiddenDecl(LookupResult &Old, const NamedDecl *New); public: typedef OpaquePtr DeclGroupPtrTy; typedef OpaquePtr TemplateTy; typedef OpaquePtr TypeTy; OpenCLOptions OpenCLFeatures; FPOptions FPFeatures; const LangOptions &LangOpts; Preprocessor &PP; ASTContext &Context; ASTConsumer &Consumer; DiagnosticsEngine &Diags; SourceManager &SourceMgr; /// \brief Flag indicating whether or not to collect detailed statistics. bool CollectStats; /// \brief Code-completion consumer. CodeCompleteConsumer *CodeCompleter; /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; /// \brief Generally null except when we temporarily switch decl contexts, /// like in \see ActOnObjCTemporaryExitContainerContext. DeclContext *OriginalLexicalContext; /// VAListTagName - The declaration name corresponding to __va_list_tag. /// This is used as part of a hack to omit that class from ADL results. DeclarationName VAListTagName; bool MSStructPragmaOn; // True when \#pragma ms_struct on /// \brief Controls member pointer representation format under the MS ABI. LangOptions::PragmaMSPointersToMembersKind MSPointerToMemberRepresentationMethod; /// Stack of active SEH __finally scopes. Can be empty. SmallVector CurrentSEHFinally; /// \brief Source location for newly created implicit MSInheritanceAttrs SourceLocation ImplicitMSInheritanceAttrLoc; enum PragmaMsStackAction { PSK_Reset = 0x0, // #pragma () PSK_Set = 0x1, // #pragma (value) PSK_Push = 0x2, // #pragma (push[, id]) PSK_Pop = 0x4, // #pragma (pop[, id]) PSK_Show = 0x8, // #pragma (show) -- only for "pack"! PSK_Push_Set = PSK_Push | PSK_Set, // #pragma (push[, id], value) PSK_Pop_Set = PSK_Pop | PSK_Set, // #pragma (pop[, id], value) }; template struct PragmaStack { struct Slot { llvm::StringRef StackSlotLabel; ValueType Value; SourceLocation PragmaLocation; Slot(llvm::StringRef StackSlotLabel, ValueType Value, SourceLocation PragmaLocation) : StackSlotLabel(StackSlotLabel), Value(Value), PragmaLocation(PragmaLocation) {} }; void Act(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, ValueType Value); // MSVC seems to add artificial slots to #pragma stacks on entering a C++ // method body to restore the stacks on exit, so it works like this: // // struct S { // #pragma (push, InternalPragmaSlot, ) // void Method {} // #pragma (pop, InternalPragmaSlot) // }; // // It works even with #pragma vtordisp, although MSVC doesn't support // #pragma vtordisp(push [, id], n) // syntax. // // Push / pop a named sentinel slot. void SentinelAction(PragmaMsStackAction Action, StringRef Label) { assert((Action == PSK_Push || Action == PSK_Pop) && "Can only push / pop #pragma stack sentinels!"); Act(CurrentPragmaLocation, Action, Label, CurrentValue); } // Constructors. explicit PragmaStack(const ValueType &Default) : DefaultValue(Default), CurrentValue(Default) {} SmallVector Stack; ValueType DefaultValue; // Value used for PSK_Reset action. ValueType CurrentValue; SourceLocation CurrentPragmaLocation; }; // FIXME: We should serialize / deserialize these if they occur in a PCH (but // we shouldn't do so if they're in a module). /// \brief Whether to insert vtordisps prior to virtual bases in the Microsoft /// C++ ABI. Possible values are 0, 1, and 2, which mean: /// /// 0: Suppress all vtordisps /// 1: Insert vtordisps in the presence of vbase overrides and non-trivial /// structors /// 2: Always insert vtordisps to support RTTI on partially constructed /// objects PragmaStack VtorDispStack; // #pragma pack. // Sentinel to represent when the stack is set to mac68k alignment. static const unsigned kMac68kAlignmentSentinel = ~0U; PragmaStack PackStack; // Segment #pragmas. PragmaStack DataSegStack; PragmaStack BSSSegStack; PragmaStack ConstSegStack; PragmaStack CodeSegStack; // RAII object to push / pop sentinel slots for all MS #pragma stacks. // Actions should be performed only if we enter / exit a C++ method body. class PragmaStackSentinelRAII { public: PragmaStackSentinelRAII(Sema &S, StringRef SlotLabel, bool ShouldAct); ~PragmaStackSentinelRAII(); private: Sema &S; StringRef SlotLabel; bool ShouldAct; }; /// A mapping that describes the nullability we've seen in each header file. FileNullabilityMap NullabilityMap; /// Last section used with #pragma init_seg. StringLiteral *CurInitSeg; SourceLocation CurInitSegLoc; /// VisContext - Manages the stack for \#pragma GCC visibility. void *VisContext; // Really a "PragmaVisStack*" /// \brief This represents the last location of a "#pragma clang optimize off" /// directive if such a directive has not been closed by an "on" yet. If /// optimizations are currently "on", this is set to an invalid location. SourceLocation OptimizeOffPragmaLocation; /// \brief Flag indicating if Sema is building a recovery call expression. /// /// This flag is used to avoid building recovery call expressions /// if Sema is already doing so, which would cause infinite recursions. bool IsBuildingRecoveryCallExpr; /// Used to control the generation of ExprWithCleanups. CleanupInfo Cleanup; /// ExprCleanupObjects - This is the stack of objects requiring /// cleanup that are created by the current full expression. The /// element type here is ExprWithCleanups::Object. SmallVector ExprCleanupObjects; /// \brief Store a list of either DeclRefExprs or MemberExprs /// that contain a reference to a variable (constant) that may or may not /// be odr-used in this Expr, and we won't know until all lvalue-to-rvalue /// and discarded value conversions have been applied to all subexpressions /// of the enclosing full expression. This is cleared at the end of each /// full expression. llvm::SmallPtrSet MaybeODRUseExprs; /// \brief Stack containing information about each of the nested /// function, block, and method scopes that are currently active. /// /// This array is never empty. Clients should ignore the first /// element, which is used to cache a single FunctionScopeInfo /// that's used to parse every top-level function. SmallVector FunctionScopes; typedef LazyVector ExtVectorDeclsType; /// ExtVectorDecls - This is a list all the extended vector types. This allows /// us to associate a raw vector type with one of the ext_vector type names. /// This is only necessary for issuing pretty diagnostics. ExtVectorDeclsType ExtVectorDecls; /// FieldCollector - Collects CXXFieldDecls during parsing of C++ classes. std::unique_ptr FieldCollector; typedef llvm::SmallSetVector NamedDeclSetType; /// \brief Set containing all declared private fields that are not used. NamedDeclSetType UnusedPrivateFields; /// \brief Set containing all typedefs that are likely unused. llvm::SmallSetVector UnusedLocalTypedefNameCandidates; /// \brief Delete-expressions to be analyzed at the end of translation unit /// /// This list contains class members, and locations of delete-expressions /// that could not be proven as to whether they mismatch with new-expression /// used in initializer of the field. typedef std::pair DeleteExprLoc; typedef llvm::SmallVector DeleteLocs; llvm::MapVector DeleteExprs; typedef llvm::SmallPtrSet RecordDeclSetTy; /// PureVirtualClassDiagSet - a set of class declarations which we have /// emitted a list of pure virtual functions. Used to prevent emitting the /// same list more than once. std::unique_ptr PureVirtualClassDiagSet; /// ParsingInitForAutoVars - a set of declarations with auto types for which /// we are currently parsing the initializer. llvm::SmallPtrSet ParsingInitForAutoVars; /// \brief Look for a locally scoped extern "C" declaration by the given name. NamedDecl *findLocallyScopedExternCDecl(DeclarationName Name); typedef LazyVector TentativeDefinitionsType; /// \brief All the tentative definitions encountered in the TU. TentativeDefinitionsType TentativeDefinitions; typedef LazyVector UnusedFileScopedDeclsType; /// \brief The set of file scoped decls seen so far that have not been used /// and must warn if not used. Only contains the first declaration. UnusedFileScopedDeclsType UnusedFileScopedDecls; typedef LazyVector DelegatingCtorDeclsType; /// \brief All the delegating constructors seen so far in the file, used for /// cycle detection at the end of the TU. DelegatingCtorDeclsType DelegatingCtorDecls; /// \brief All the overriding functions seen during a class definition /// that had their exception spec checks delayed, plus the overridden /// function. SmallVector, 2> DelayedExceptionSpecChecks; /// \brief All the members seen during a class definition which were both /// explicitly defaulted and had explicitly-specified exception /// specifications, along with the function type containing their /// user-specified exception specification. Those exception specifications /// were overridden with the default specifications, but we still need to /// check whether they are compatible with the default specification, and /// we can't do that until the nesting set of class definitions is complete. SmallVector, 2> DelayedDefaultedMemberExceptionSpecs; typedef llvm::MapVector LateParsedTemplateMapT; LateParsedTemplateMapT LateParsedTemplateMap; /// \brief Callback to the parser to parse templated functions when needed. typedef void LateTemplateParserCB(void *P, LateParsedTemplate &LPT); typedef void LateTemplateParserCleanupCB(void *P); LateTemplateParserCB *LateTemplateParser; LateTemplateParserCleanupCB *LateTemplateParserCleanup; void *OpaqueParser; void SetLateTemplateParser(LateTemplateParserCB *LTP, LateTemplateParserCleanupCB *LTPCleanup, void *P) { LateTemplateParser = LTP; LateTemplateParserCleanup = LTPCleanup; OpaqueParser = P; } class DelayedDiagnostics; class DelayedDiagnosticsState { sema::DelayedDiagnosticPool *SavedPool; friend class Sema::DelayedDiagnostics; }; typedef DelayedDiagnosticsState ParsingDeclState; typedef DelayedDiagnosticsState ProcessingContextState; /// A class which encapsulates the logic for delaying diagnostics /// during parsing and other processing. class DelayedDiagnostics { /// \brief The current pool of diagnostics into which delayed /// diagnostics should go. sema::DelayedDiagnosticPool *CurPool; public: DelayedDiagnostics() : CurPool(nullptr) {} /// Adds a delayed diagnostic. void add(const sema::DelayedDiagnostic &diag); // in DelayedDiagnostic.h /// Determines whether diagnostics should be delayed. bool shouldDelayDiagnostics() { return CurPool != nullptr; } /// Returns the current delayed-diagnostics pool. sema::DelayedDiagnosticPool *getCurrentPool() const { return CurPool; } /// Enter a new scope. Access and deprecation diagnostics will be /// collected in this pool. DelayedDiagnosticsState push(sema::DelayedDiagnosticPool &pool) { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = &pool; return state; } /// Leave a delayed-diagnostic state that was previously pushed. /// Do not emit any of the diagnostics. This is performed as part /// of the bookkeeping of popping a pool "properly". void popWithoutEmitting(DelayedDiagnosticsState state) { CurPool = state.SavedPool; } /// Enter a new scope where access and deprecation diagnostics are /// not delayed. DelayedDiagnosticsState pushUndelayed() { DelayedDiagnosticsState state; state.SavedPool = CurPool; CurPool = nullptr; return state; } /// Undo a previous pushUndelayed(). void popUndelayed(DelayedDiagnosticsState state) { assert(CurPool == nullptr); CurPool = state.SavedPool; } } DelayedDiagnostics; /// A RAII object to temporarily push a declaration context. class ContextRAII { private: Sema &S; DeclContext *SavedContext; ProcessingContextState SavedContextState; QualType SavedCXXThisTypeOverride; public: ContextRAII(Sema &S, DeclContext *ContextToPush, bool NewThisContext = true) : S(S), SavedContext(S.CurContext), SavedContextState(S.DelayedDiagnostics.pushUndelayed()), SavedCXXThisTypeOverride(S.CXXThisTypeOverride) { assert(ContextToPush && "pushing null context"); S.CurContext = ContextToPush; if (NewThisContext) S.CXXThisTypeOverride = QualType(); } void pop() { if (!SavedContext) return; S.CurContext = SavedContext; S.DelayedDiagnostics.popUndelayed(SavedContextState); S.CXXThisTypeOverride = SavedCXXThisTypeOverride; SavedContext = nullptr; } ~ContextRAII() { pop(); } }; /// \brief RAII object to handle the state changes required to synthesize /// a function body. class SynthesizedFunctionScope { Sema &S; Sema::ContextRAII SavedContext; public: SynthesizedFunctionScope(Sema &S, DeclContext *DC) : S(S), SavedContext(S, DC) { S.PushFunctionScope(); S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); } ~SynthesizedFunctionScope() { S.PopExpressionEvaluationContext(); S.PopFunctionScopeInfo(); } }; /// WeakUndeclaredIdentifiers - Identifiers contained in /// \#pragma weak before declared. rare. may alias another /// identifier, declared or undeclared llvm::MapVector WeakUndeclaredIdentifiers; /// ExtnameUndeclaredIdentifiers - Identifiers contained in /// \#pragma redefine_extname before declared. Used in Solaris system headers /// to define functions that occur in multiple standards to call the version /// in the currently selected standard. llvm::DenseMap ExtnameUndeclaredIdentifiers; /// \brief Load weak undeclared identifiers from the external source. void LoadExternalWeakUndeclaredIdentifiers(); /// WeakTopLevelDecl - Translation-unit scoped declarations generated by /// \#pragma weak during processing of other Decls. /// I couldn't figure out a clean way to generate these in-line, so /// we store them here and handle separately -- which is a hack. /// It would be best to refactor this. SmallVector WeakTopLevelDecl; IdentifierResolver IdResolver; /// Translation Unit Scope - useful to Objective-C actions that need /// to lookup file scope declarations in the "ordinary" C decl namespace. /// For example, user-defined classes, built-in "id" type, etc. Scope *TUScope; /// \brief The C++ "std" namespace, where the standard library resides. LazyDeclPtr StdNamespace; /// \brief The C++ "std::bad_alloc" class, which is defined by the C++ /// standard library. LazyDeclPtr StdBadAlloc; /// \brief The C++ "std::initializer_list" template, which is defined in /// \. ClassTemplateDecl *StdInitializerList; /// \brief The C++ "type_info" declaration, which is defined in \. RecordDecl *CXXTypeInfoDecl; /// \brief The MSVC "_GUID" struct, which is defined in MSVC header files. RecordDecl *MSVCGuidDecl; /// \brief Caches identifiers/selectors for NSFoundation APIs. std::unique_ptr NSAPIObj; /// \brief The declaration of the Objective-C NSNumber class. ObjCInterfaceDecl *NSNumberDecl; /// \brief The declaration of the Objective-C NSValue class. ObjCInterfaceDecl *NSValueDecl; /// \brief Pointer to NSNumber type (NSNumber *). QualType NSNumberPointer; /// \brief Pointer to NSValue type (NSValue *). QualType NSValuePointer; /// \brief The Objective-C NSNumber methods used to create NSNumber literals. ObjCMethodDecl *NSNumberLiteralMethods[NSAPI::NumNSNumberLiteralMethods]; /// \brief The declaration of the Objective-C NSString class. ObjCInterfaceDecl *NSStringDecl; /// \brief Pointer to NSString type (NSString *). QualType NSStringPointer; /// \brief The declaration of the stringWithUTF8String: method. ObjCMethodDecl *StringWithUTF8StringMethod; /// \brief The declaration of the valueWithBytes:objCType: method. ObjCMethodDecl *ValueWithBytesObjCTypeMethod; /// \brief The declaration of the Objective-C NSArray class. ObjCInterfaceDecl *NSArrayDecl; /// \brief The declaration of the arrayWithObjects:count: method. ObjCMethodDecl *ArrayWithObjectsMethod; /// \brief The declaration of the Objective-C NSDictionary class. ObjCInterfaceDecl *NSDictionaryDecl; /// \brief The declaration of the dictionaryWithObjects:forKeys:count: method. ObjCMethodDecl *DictionaryWithObjectsMethod; /// \brief id type. QualType QIDNSCopying; /// \brief will hold 'respondsToSelector:' Selector RespondsToSelectorSel; /// \brief counter for internal MS Asm label names. unsigned MSAsmLabelNameCounter; /// A flag to remember whether the implicit forms of operator new and delete /// have been declared. bool GlobalNewDeleteDeclared; /// A flag to indicate that we're in a context that permits abstract /// references to fields. This is really a bool AllowAbstractFieldReference; /// \brief Describes how the expressions currently being parsed are /// evaluated at run-time, if at all. enum ExpressionEvaluationContext { /// \brief The current expression and its subexpressions occur within an /// unevaluated operand (C++11 [expr]p7), such as the subexpression of /// \c sizeof, where the type of the expression may be significant but /// no code will be generated to evaluate the value of the expression at /// run time. Unevaluated, /// \brief The current expression occurs within a discarded statement. /// This behaves largely similarly to an unevaluated operand in preventing /// definitions from being required, but not in other ways. DiscardedStatement, /// \brief The current expression occurs within an unevaluated /// operand that unconditionally permits abstract references to /// fields, such as a SIZE operator in MS-style inline assembly. UnevaluatedAbstract, /// \brief The current context is "potentially evaluated" in C++11 terms, /// but the expression is evaluated at compile-time (like the values of /// cases in a switch statement). ConstantEvaluated, /// \brief The current expression is potentially evaluated at run time, /// which means that code may be generated to evaluate the value of the /// expression at run time. PotentiallyEvaluated, /// \brief The current expression is potentially evaluated, but any /// declarations referenced inside that expression are only used if /// in fact the current expression is used. /// /// This value is used when parsing default function arguments, for which /// we would like to provide diagnostics (e.g., passing non-POD arguments /// through varargs) but do not want to mark declarations as "referenced" /// until the default argument is used. PotentiallyEvaluatedIfUsed }; /// \brief Data structure used to record current or nested /// expression evaluation contexts. struct ExpressionEvaluationContextRecord { /// \brief The expression evaluation context. ExpressionEvaluationContext Context; /// \brief Whether the enclosing context needed a cleanup. CleanupInfo ParentCleanup; /// \brief Whether we are in a decltype expression. bool IsDecltype; /// \brief The number of active cleanup objects when we entered /// this expression evaluation context. unsigned NumCleanupObjects; /// \brief The number of typos encountered during this expression evaluation /// context (i.e. the number of TypoExprs created). unsigned NumTypos; llvm::SmallPtrSet SavedMaybeODRUseExprs; /// \brief The lambdas that are present within this context, if it /// is indeed an unevaluated context. SmallVector Lambdas; /// \brief The declaration that provides context for lambda expressions /// and block literals if the normal declaration context does not /// suffice, e.g., in a default function argument. Decl *ManglingContextDecl; /// \brief The context information used to mangle lambda expressions /// and block literals within this context. /// /// This mangling information is allocated lazily, since most contexts /// do not have lambda expressions or block literals. IntrusiveRefCntPtr MangleNumbering; /// \brief If we are processing a decltype type, a set of call expressions /// for which we have deferred checking the completeness of the return type. SmallVector DelayedDecltypeCalls; /// \brief If we are processing a decltype type, a set of temporary binding /// expressions for which we have deferred checking the destructor. SmallVector DelayedDecltypeBinds; ExpressionEvaluationContextRecord(ExpressionEvaluationContext Context, unsigned NumCleanupObjects, CleanupInfo ParentCleanup, Decl *ManglingContextDecl, bool IsDecltype) : Context(Context), ParentCleanup(ParentCleanup), IsDecltype(IsDecltype), NumCleanupObjects(NumCleanupObjects), NumTypos(0), ManglingContextDecl(ManglingContextDecl), MangleNumbering() { } /// \brief Retrieve the mangling numbering context, used to consistently /// number constructs like lambdas for mangling. MangleNumberingContext &getMangleNumberingContext(ASTContext &Ctx); bool isUnevaluated() const { return Context == Unevaluated || Context == UnevaluatedAbstract; } }; /// A stack of expression evaluation contexts. SmallVector ExprEvalContexts; /// \brief Compute the mangling number context for a lambda expression or /// block literal. /// /// \param DC - The DeclContext containing the lambda expression or /// block literal. /// \param[out] ManglingContextDecl - Returns the ManglingContextDecl /// associated with the context, if relevant. MangleNumberingContext *getCurrentMangleNumberContext( const DeclContext *DC, Decl *&ManglingContextDecl); /// SpecialMemberOverloadResult - The overloading result for a special member /// function. /// /// This is basically a wrapper around PointerIntPair. The lowest bits of the /// integer are used to determine whether overload resolution succeeded. class SpecialMemberOverloadResult : public llvm::FastFoldingSetNode { public: enum Kind { NoMemberOrDeleted, Ambiguous, Success }; private: llvm::PointerIntPair Pair; public: SpecialMemberOverloadResult(const llvm::FoldingSetNodeID &ID) : FastFoldingSetNode(ID) {} CXXMethodDecl *getMethod() const { return Pair.getPointer(); } void setMethod(CXXMethodDecl *MD) { Pair.setPointer(MD); } Kind getKind() const { return static_cast(Pair.getInt()); } void setKind(Kind K) { Pair.setInt(K); } }; /// \brief A cache of special member function overload resolution results /// for C++ records. llvm::FoldingSet SpecialMemberCache; /// \brief A cache of the flags available in enumerations with the flag_bits /// attribute. mutable llvm::DenseMap FlagBitsCache; /// \brief The kind of translation unit we are processing. /// /// When we're processing a complete translation unit, Sema will perform /// end-of-translation-unit semantic tasks (such as creating /// initializers for tentative definitions in C) once parsing has /// completed. Modules and precompiled headers perform different kinds of /// checks. TranslationUnitKind TUKind; llvm::BumpPtrAllocator BumpAlloc; /// \brief The number of SFINAE diagnostics that have been trapped. unsigned NumSFINAEErrors; typedef llvm::DenseMap> UnparsedDefaultArgInstantiationsMap; /// \brief A mapping from parameters with unparsed default arguments to the /// set of instantiations of each parameter. /// /// This mapping is a temporary data structure used when parsing /// nested class templates or nested classes of class templates, /// where we might end up instantiating an inner class before the /// default arguments of its methods have been parsed. UnparsedDefaultArgInstantiationsMap UnparsedDefaultArgInstantiations; // Contains the locations of the beginning of unparsed default // argument locations. llvm::DenseMap UnparsedDefaultArgLocs; /// UndefinedInternals - all the used, undefined objects which require a /// definition in this translation unit. llvm::MapVector UndefinedButUsed; /// Obtain a sorted list of functions that are undefined but ODR-used. void getUndefinedButUsed( SmallVectorImpl > &Undefined); /// Retrieves list of suspicious delete-expressions that will be checked at /// the end of translation unit. const llvm::MapVector & getMismatchingDeleteExpressions() const; typedef std::pair GlobalMethods; typedef llvm::DenseMap GlobalMethodPool; /// Method Pool - allows efficient lookup when typechecking messages to "id". /// We need to maintain a list, since selectors can have differing signatures /// across classes. In Cocoa, this happens to be extremely uncommon (only 1% /// of selectors are "overloaded"). /// At the head of the list it is recorded whether there were 0, 1, or >= 2 /// methods inside categories with a particular selector. GlobalMethodPool MethodPool; /// Method selectors used in a \@selector expression. Used for implementation /// of -Wselector. llvm::MapVector ReferencedSelectors; /// Kinds of C++ special members. enum CXXSpecialMember { CXXDefaultConstructor, CXXCopyConstructor, CXXMoveConstructor, CXXCopyAssignment, CXXMoveAssignment, CXXDestructor, CXXInvalid }; typedef std::pair SpecialMemberDecl; /// The C++ special members which we are currently in the process of /// declaring. If this process recursively triggers the declaration of the /// same special member, we should act as if it is not yet declared. llvm::SmallSet SpecialMembersBeingDeclared; void ReadMethodPool(Selector Sel); void updateOutOfDateSelector(Selector Sel); /// Private Helper predicate to check for 'self'. bool isSelfExpr(Expr *RExpr); bool isSelfExpr(Expr *RExpr, const ObjCMethodDecl *Method); /// \brief Cause the active diagnostic on the DiagosticsEngine to be /// emitted. This is closely coupled to the SemaDiagnosticBuilder class and /// should not be used elsewhere. void EmitCurrentDiagnostic(unsigned DiagID); /// Records and restores the FP_CONTRACT state on entry/exit of compound /// statements. class FPContractStateRAII { public: FPContractStateRAII(Sema& S) : S(S), OldFPContractState(S.FPFeatures.fp_contract) {} ~FPContractStateRAII() { S.FPFeatures.fp_contract = OldFPContractState; } private: Sema& S; bool OldFPContractState : 1; }; void addImplicitTypedef(StringRef Name, QualType T); public: Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind = TU_Complete, CodeCompleteConsumer *CompletionConsumer = nullptr); ~Sema(); /// \brief Perform initialization that occurs after the parser has been /// initialized but before it parses anything. void Initialize(); const LangOptions &getLangOpts() const { return LangOpts; } OpenCLOptions &getOpenCLOptions() { return OpenCLFeatures; } FPOptions &getFPOptions() { return FPFeatures; } DiagnosticsEngine &getDiagnostics() const { return Diags; } SourceManager &getSourceManager() const { return SourceMgr; } Preprocessor &getPreprocessor() const { return PP; } ASTContext &getASTContext() const { return Context; } ASTConsumer &getASTConsumer() const { return Consumer; } ASTMutationListener *getASTMutationListener() const; ExternalSemaSource* getExternalSource() const { return ExternalSource; } ///\brief Registers an external source. If an external source already exists, /// creates a multiplex external source and appends to it. /// ///\param[in] E - A non-null external sema source. /// void addExternalSource(ExternalSemaSource *E); void PrintStats() const; /// \brief Helper class that creates diagnostics with optional /// template instantiation stacks. /// /// This class provides a wrapper around the basic DiagnosticBuilder /// class that emits diagnostics. SemaDiagnosticBuilder is /// responsible for emitting the diagnostic (as DiagnosticBuilder /// does) and, if the diagnostic comes from inside a template /// instantiation, printing the template instantiation stack as /// well. class SemaDiagnosticBuilder : public DiagnosticBuilder { Sema &SemaRef; unsigned DiagID; public: SemaDiagnosticBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) { } // This is a cunning lie. DiagnosticBuilder actually performs move // construction in its copy constructor (but due to varied uses, it's not // possible to conveniently express this as actual move construction). So // the default copy ctor here is fine, because the base class disables the // source anyway, so the user-defined ~SemaDiagnosticBuilder is a safe no-op // in that case anwyay. SemaDiagnosticBuilder(const SemaDiagnosticBuilder&) = default; ~SemaDiagnosticBuilder() { // If we aren't active, there is nothing to do. if (!isActive()) return; // Otherwise, we need to emit the diagnostic. First flush the underlying // DiagnosticBuilder data, and clear the diagnostic builder itself so it // won't emit the diagnostic in its own destructor. // // This seems wasteful, in that as written the DiagnosticBuilder dtor will // do its own needless checks to see if the diagnostic needs to be // emitted. However, because we take care to ensure that the builder // objects never escape, a sufficiently smart compiler will be able to // eliminate that code. FlushCounts(); Clear(); // Dispatch to Sema to emit the diagnostic. SemaRef.EmitCurrentDiagnostic(DiagID); } /// Teach operator<< to produce an object of the correct type. template friend const SemaDiagnosticBuilder &operator<<( const SemaDiagnosticBuilder &Diag, const T &Value) { const DiagnosticBuilder &BaseDiag = Diag; BaseDiag << Value; return Diag; } }; /// \brief Emit a diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) { DiagnosticBuilder DB = Diags.Report(Loc, DiagID); return SemaDiagnosticBuilder(DB, *this, DiagID); } /// \brief Emit a partial diagnostic. SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic& PD); /// \brief Build a partial diagnostic. PartialDiagnostic PDiag(unsigned DiagID = 0); // in SemaInternal.h bool findMacroSpelling(SourceLocation &loc, StringRef name); /// \brief Get a string to suggest for zero-initialization of a type. std::string getFixItZeroInitializerForType(QualType T, SourceLocation Loc) const; std::string getFixItZeroLiteralForType(QualType T, SourceLocation Loc) const; /// \brief Calls \c Lexer::getLocForEndOfToken() SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0); /// \brief Retrieve the module loader associated with the preprocessor. ModuleLoader &getModuleLoader() const; void emitAndClearUnusedLocalTypedefWarnings(); void ActOnEndOfTranslationUnit(); void CheckDelegatingCtorCycles(); Scope *getScopeForContext(DeclContext *Ctx); void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); sema::LambdaScopeInfo *PushLambdaScope(); /// \brief This is used to inform Sema what the current TemplateParameterDepth /// is during Parsing. Currently it is used to pass on the depth /// when parsing generic lambda 'auto' parameters. void RecordParsingTemplateParameterDepth(unsigned Depth); void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP = nullptr, const Decl *D = nullptr, const BlockExpr *blkExpr = nullptr); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.back(); } sema::FunctionScopeInfo *getEnclosingFunction() const { if (FunctionScopes.empty()) return nullptr; for (int e = FunctionScopes.size()-1; e >= 0; --e) { if (isa(FunctionScopes[e])) continue; return FunctionScopes[e]; } return nullptr; } template void recordUseOfEvaluatedWeak(const ExprT *E, bool IsRead=true) { if (!isUnevaluatedContext()) getCurFunction()->recordUseOfWeak(E, IsRead); } void PushCompoundScope(); void PopCompoundScope(); sema::CompoundScopeInfo &getCurCompoundScope() const; bool hasAnyUnrecoverableErrorsInThisFunction() const; /// \brief Retrieve the current block, if any. sema::BlockScopeInfo *getCurBlock(); /// Retrieve the current lambda scope info, if any. /// \param IgnoreCapturedRegions true if should find the top-most lambda scope /// info ignoring all inner captured regions scope infos. sema::LambdaScopeInfo *getCurLambda(bool IgnoreCapturedRegions = false); /// \brief Retrieve the current generic lambda info, if any. sema::LambdaScopeInfo *getCurGenericLambda(); /// \brief Retrieve the current captured region, if any. sema::CapturedRegionScopeInfo *getCurCapturedRegion(); /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVectorImpl &WeakTopLevelDecls() { return WeakTopLevelDecl; } void ActOnComment(SourceRange Comment); //===--------------------------------------------------------------------===// // Type Analysis / Processing: SemaType.cpp. // QualType BuildQualifiedType(QualType T, SourceLocation Loc, Qualifiers Qs, const DeclSpec *DS = nullptr); QualType BuildQualifiedType(QualType T, SourceLocation Loc, unsigned CVRA, const DeclSpec *DS = nullptr); QualType BuildPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildReferenceType(QualType T, bool LValueRef, SourceLocation Loc, DeclarationName Entity); QualType BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Expr *ArraySize, unsigned Quals, SourceRange Brackets, DeclarationName Entity); QualType BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc); bool CheckFunctionReturnType(QualType T, SourceLocation Loc); /// \brief Build a function type. /// /// This routine checks the function type according to C++ rules and /// under the assumption that the result type and parameter types have /// just been instantiated from a template. It therefore duplicates /// some of the behavior of GetTypeForDeclarator, but in a much /// simpler form that is only suitable for this narrow use case. /// /// \param T The return type of the function. /// /// \param ParamTypes The parameter types of the function. This array /// will be modified to account for adjustments to the types of the /// function parameters. /// /// \param Loc The location of the entity whose type involves this /// function type or, if there is no such entity, the location of the /// type that will have function type. /// /// \param Entity The name of the entity that involves the function /// type, if known. /// /// \param EPI Extra information about the function type. Usually this will /// be taken from an existing function with the same prototype. /// /// \returns A suitable function type, if there are no errors. The /// unqualified type will always be a FunctionProtoType. /// Otherwise, returns a NULL type. QualType BuildFunctionType(QualType T, MutableArrayRef ParamTypes, SourceLocation Loc, DeclarationName Entity, const FunctionProtoType::ExtProtoInfo &EPI); QualType BuildMemberPointerType(QualType T, QualType Class, SourceLocation Loc, DeclarationName Entity); QualType BuildBlockPointerType(QualType T, SourceLocation Loc, DeclarationName Entity); QualType BuildParenType(QualType T); QualType BuildAtomicType(QualType T, SourceLocation Loc); QualType BuildPipeType(QualType T, SourceLocation Loc); TypeSourceInfo *GetTypeForDeclarator(Declarator &D, Scope *S); TypeSourceInfo *GetTypeForDeclaratorCast(Declarator &D, QualType FromTy); TypeSourceInfo *GetTypeSourceInfoForDeclarator(Declarator &D, QualType T, TypeSourceInfo *ReturnTypeInfo); /// \brief Package the given type and TSI into a ParsedType. ParsedType CreateParsedType(QualType T, TypeSourceInfo *TInfo); DeclarationNameInfo GetNameForDeclarator(Declarator &D); DeclarationNameInfo GetNameFromUnqualifiedId(const UnqualifiedId &Name); static QualType GetTypeFromParser(ParsedType Ty, TypeSourceInfo **TInfo = nullptr); CanThrowResult canThrow(const Expr *E); const FunctionProtoType *ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT); void UpdateExceptionSpec(FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI); bool CheckSpecifiedExceptionType(QualType &T, SourceRange Range); bool CheckDistantExceptionSpec(QualType T); bool CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New); bool CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc); bool CheckEquivalentExceptionSpec( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc, bool *MissingExceptionSpecification = nullptr, bool *MissingEmptyExceptionSpecification = nullptr, bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); bool CheckExceptionSpecSubset( const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Superset, SourceLocation SuperLoc, const FunctionProtoType *Subset, SourceLocation SubLoc); bool CheckParamExceptionSpec(const PartialDiagnostic & NoteID, const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc); TypeResult ActOnTypeName(Scope *S, Declarator &D); /// \brief The parser has parsed the context-sensitive type 'instancetype' /// in an Objective-C message declaration. Return the appropriate type. ParsedType ActOnObjCInstanceType(SourceLocation Loc); /// \brief Abstract class used to diagnose incomplete types. struct TypeDiagnoser { TypeDiagnoser() {} virtual void diagnose(Sema &S, SourceLocation Loc, QualType T) = 0; virtual ~TypeDiagnoser() {} }; static int getPrintable(int I) { return I; } static unsigned getPrintable(unsigned I) { return I; } static bool getPrintable(bool B) { return B; } static const char * getPrintable(const char *S) { return S; } static StringRef getPrintable(StringRef S) { return S; } static const std::string &getPrintable(const std::string &S) { return S; } static const IdentifierInfo *getPrintable(const IdentifierInfo *II) { return II; } static DeclarationName getPrintable(DeclarationName N) { return N; } static QualType getPrintable(QualType T) { return T; } static SourceRange getPrintable(SourceRange R) { return R; } static SourceRange getPrintable(SourceLocation L) { return L; } static SourceRange getPrintable(const Expr *E) { return E->getSourceRange(); } static SourceRange getPrintable(TypeLoc TL) { return TL.getSourceRange();} template class BoundTypeDiagnoser : public TypeDiagnoser { unsigned DiagID; std::tuple Args; template void emit(const SemaDiagnosticBuilder &DB, llvm::index_sequence) const { // Apply all tuple elements to the builder in order. bool Dummy[] = {false, (DB << getPrintable(std::get(Args)))...}; (void)Dummy; } public: BoundTypeDiagnoser(unsigned DiagID, const Ts &...Args) : TypeDiagnoser(), DiagID(DiagID), Args(Args...) { assert(DiagID != 0 && "no diagnostic for type diagnoser"); } void diagnose(Sema &S, SourceLocation Loc, QualType T) override { const SemaDiagnosticBuilder &DB = S.Diag(Loc, DiagID); emit(DB, llvm::index_sequence_for()); DB << T; } }; private: bool RequireCompleteTypeImpl(SourceLocation Loc, QualType T, TypeDiagnoser *Diagnoser); VisibleModuleSet VisibleModules; llvm::SmallVector VisibleModulesStack; Module *CachedFakeTopLevelModule; public: /// \brief Get the module owning an entity. Module *getOwningModule(Decl *Entity); /// \brief Make a merged definition of an existing hidden definition \p ND /// visible at the specified location. void makeMergedDefinitionVisible(NamedDecl *ND, SourceLocation Loc); bool isModuleVisible(Module *M) { return VisibleModules.isVisible(M); } /// Determine whether a declaration is visible to name lookup. bool isVisible(const NamedDecl *D) { return !D->isHidden() || isVisibleSlow(D); } /// Determine whether any declaration of an entity is visible. bool hasVisibleDeclaration(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr) { return isVisible(D) || hasVisibleDeclarationSlow(D, Modules); } bool hasVisibleDeclarationSlow(const NamedDecl *D, llvm::SmallVectorImpl *Modules); bool hasVisibleMergedDefinition(NamedDecl *Def); /// Determine if \p D has a visible definition. If not, suggest a declaration /// that should be made visible to expose the definition. bool hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, bool OnlyNeedComplete = false); bool hasVisibleDefinition(const NamedDecl *D) { NamedDecl *Hidden; return hasVisibleDefinition(const_cast(D), &Hidden); } /// Determine if the template parameter \p D has a visible default argument. bool hasVisibleDefaultArgument(const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if there is a visible declaration of \p D that is a member /// specialization declaration (as opposed to an instantiated declaration). bool hasVisibleMemberSpecialization( const NamedDecl *D, llvm::SmallVectorImpl *Modules = nullptr); /// Determine if \p A and \p B are equivalent internal linkage declarations /// from different modules, and thus an ambiguity error can be downgraded to /// an extension warning. bool isEquivalentInternalLinkageDeclaration(const NamedDecl *A, const NamedDecl *B); void diagnoseEquivalentInternalLinkageDeclarations( SourceLocation Loc, const NamedDecl *D, ArrayRef Equiv); bool isCompleteType(SourceLocation Loc, QualType T) { return !RequireCompleteTypeImpl(Loc, T, nullptr); } bool RequireCompleteType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireCompleteType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteType(Loc, T, Diagnoser); } void completeExprArrayBound(Expr *E); bool RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser); bool RequireCompleteExprType(Expr *E, unsigned DiagID); template bool RequireCompleteExprType(Expr *E, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireCompleteExprType(E, Diagnoser); } bool RequireLiteralType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID); template bool RequireLiteralType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireLiteralType(Loc, T, Diagnoser); } QualType getElaboratedType(ElaboratedTypeKeyword Keyword, const CXXScopeSpec &SS, QualType T); QualType BuildTypeofExprType(Expr *E, SourceLocation Loc); /// If AsUnevaluated is false, E is treated as though it were an evaluated /// context, such as when building a type for decltype(auto). QualType BuildDecltypeType(Expr *E, SourceLocation Loc, bool AsUnevaluated = true); QualType BuildUnaryTransformType(QualType BaseType, UnaryTransformType::UTTKind UKind, SourceLocation Loc); //===--------------------------------------------------------------------===// // Symbol table / Decl tracking callbacks: SemaDecl.cpp. // struct SkipBodyInfo { SkipBodyInfo() : ShouldSkip(false), Previous(nullptr) {} bool ShouldSkip; NamedDecl *Previous; }; /// List of decls defined in a function prototype. This contains EnumConstants /// that incorrectly end up in translation unit scope because there is no /// function to pin them on. ActOnFunctionDeclarator reads this list and patches /// them into the FunctionDecl. std::vector DeclsInPrototypeScope; DeclGroupPtrTy ConvertDeclToDeclGroup(Decl *Ptr, Decl *OwnedType = nullptr); void DiagnoseUseOfUnimplementedSelectors(); bool isSimpleTypeSpecifier(tok::TokenKind Kind) const; ParsedType getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec *SS = nullptr, bool isClassName = false, bool HasTrailingDot = false, ParsedType ObjectType = nullptr, bool IsCtorOrDtorName = false, bool WantNontrivialTypeSourceInfo = false, IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); void DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, bool AllowClassTemplates = false); /// Attempt to behave like MSVC in situations where lookup of an unqualified /// type name has failed in a dependent context. In these situations, we /// automatically form a DependentTypeName that will retry lookup in a related /// scope during instantiation. ParsedType ActOnMSVCUnknownTypeName(const IdentifierInfo &II, SourceLocation NameLoc, bool IsTemplateTypeArg); /// \brief Describes the result of the name lookup and resolution performed /// by \c ClassifyName(). enum NameClassificationKind { NC_Unknown, NC_Error, NC_Keyword, NC_Type, NC_Expression, NC_NestedNameSpecifier, NC_TypeTemplate, NC_VarTemplate, NC_FunctionTemplate }; class NameClassification { NameClassificationKind Kind; ExprResult Expr; TemplateName Template; ParsedType Type; const IdentifierInfo *Keyword; explicit NameClassification(NameClassificationKind Kind) : Kind(Kind) {} public: NameClassification(ExprResult Expr) : Kind(NC_Expression), Expr(Expr) {} NameClassification(ParsedType Type) : Kind(NC_Type), Type(Type) {} NameClassification(const IdentifierInfo *Keyword) : Kind(NC_Keyword), Keyword(Keyword) { } static NameClassification Error() { return NameClassification(NC_Error); } static NameClassification Unknown() { return NameClassification(NC_Unknown); } static NameClassification NestedNameSpecifier() { return NameClassification(NC_NestedNameSpecifier); } static NameClassification TypeTemplate(TemplateName Name) { NameClassification Result(NC_TypeTemplate); Result.Template = Name; return Result; } static NameClassification VarTemplate(TemplateName Name) { NameClassification Result(NC_VarTemplate); Result.Template = Name; return Result; } static NameClassification FunctionTemplate(TemplateName Name) { NameClassification Result(NC_FunctionTemplate); Result.Template = Name; return Result; } NameClassificationKind getKind() const { return Kind; } ParsedType getType() const { assert(Kind == NC_Type); return Type; } ExprResult getExpression() const { assert(Kind == NC_Expression); return Expr; } TemplateName getTemplateName() const { assert(Kind == NC_TypeTemplate || Kind == NC_FunctionTemplate || Kind == NC_VarTemplate); return Template; } TemplateNameKind getTemplateNameKind() const { switch (Kind) { case NC_TypeTemplate: return TNK_Type_template; case NC_FunctionTemplate: return TNK_Function_template; case NC_VarTemplate: return TNK_Var_template; default: llvm_unreachable("unsupported name classification."); } } }; /// \brief Perform name lookup on the given name, classifying it based on /// the results of name lookup and the following token. /// /// This routine is used by the parser to resolve identifiers and help direct /// parsing. When the identifier cannot be found, this routine will attempt /// to correct the typo and classify based on the resulting name. /// /// \param S The scope in which we're performing name lookup. /// /// \param SS The nested-name-specifier that precedes the name. /// /// \param Name The identifier. If typo correction finds an alternative name, /// this pointer parameter will be updated accordingly. /// /// \param NameLoc The location of the identifier. /// /// \param NextToken The token following the identifier. Used to help /// disambiguate the name. /// /// \param IsAddressOfOperand True if this name is the operand of a unary /// address of ('&') expression, assuming it is classified as an /// expression. /// /// \param CCC The correction callback, if typo correction is desired. NameClassification ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, const Token &NextToken, bool IsAddressOfOperand, std::unique_ptr CCC = nullptr); Decl *ActOnDeclarator(Scope *S, Declarator &D); NamedDecl *HandleDeclarator(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParameterLists); void RegisterLocallyScopedExternCDecl(NamedDecl *ND, Scope *S); bool DiagnoseClassNameShadow(DeclContext *DC, DeclarationNameInfo Info); bool diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, DeclarationName Name, SourceLocation Loc); void diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation FallbackLoc, SourceLocation ConstQualLoc = SourceLocation(), SourceLocation VolatileQualLoc = SourceLocation(), SourceLocation RestrictQualLoc = SourceLocation(), SourceLocation AtomicQualLoc = SourceLocation(), SourceLocation UnalignedQualLoc = SourceLocation()); static bool adjustContextForLocalExternDecl(DeclContext *&DC); void DiagnoseFunctionSpecifiers(const DeclSpec &DS); void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); void CheckShadow(Scope *S, VarDecl *D); /// Warn if 'E', which is an expression that is about to be modified, refers /// to a shadowing declaration. void CheckShadowingDeclModification(Expr *E, SourceLocation Loc); private: /// Map of current shadowing declarations to shadowed declarations. Warn if /// it looks like the user is trying to modify the shadowing declaration. llvm::DenseMap ShadowingDecls; public: void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); void handleTagNumbering(const TagDecl *Tag, Scope *TagScope); void setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD); void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous); NamedDecl* ActOnTypedefNameDecl(Scope* S, DeclContext* DC, TypedefNameDecl *D, LookupResult &Previous, bool &Redeclaration); NamedDecl *ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope); // Returns true if the variable declaration is a redeclaration bool CheckVariableDeclaration(VarDecl *NewVD, LookupResult &Previous); void CheckVariableDeclarationType(VarDecl *NewVD); void CheckCompleteVariableDeclaration(VarDecl *var); void MaybeSuggestAddingStaticToDecl(const FunctionDecl *D); NamedDecl* ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, bool &AddToScope); bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD); bool CheckConstexprFunctionDecl(const FunctionDecl *FD); bool CheckConstexprFunctionBody(const FunctionDecl *FD, Stmt *Body); void DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD); void FindHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); void NoteHiddenVirtualMethods(CXXMethodDecl *MD, SmallVectorImpl &OverloadedMethods); // Returns true if the function declaration is a redeclaration bool CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, LookupResult &Previous, bool IsExplicitSpecialization); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); Decl *ActOnParamDeclarator(Scope *S, Declarator &D); ParmVarDecl *BuildParmVarDeclForTypedef(DeclContext *DC, SourceLocation Loc, QualType T); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, SourceLocation NameLoc, IdentifierInfo *Name, QualType T, TypeSourceInfo *TSInfo, StorageClass SC); void ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, Expr *defarg); void ActOnParamUnparsedDefaultArgument(Decl *param, SourceLocation EqualLoc, SourceLocation ArgLoc); void ActOnParamDefaultArgumentError(Decl *param, SourceLocation EqualLoc); bool SetParamDefaultArgument(ParmVarDecl *Param, Expr *DefaultArg, SourceLocation EqualLoc); void AddInitializerToDecl(Decl *dcl, Expr *init, bool DirectInit, bool TypeMayContainAuto); void ActOnUninitializedDecl(Decl *dcl, bool TypeMayContainAuto); void ActOnInitializerError(Decl *Dcl); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); void ActOnCXXForRangeDecl(Decl *D); StmtResult ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, IdentifierInfo *Ident, ParsedAttributes &Attrs, SourceLocation AttrEnd); void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); void FinalizeDeclaration(Decl *D); DeclGroupPtrTy FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, ArrayRef Group); DeclGroupPtrTy BuildDeclaratorGroup(MutableArrayRef Group, bool TypeMayContainAuto = true); /// Should be called on all declarations that might have attached /// documentation comments. void ActOnDocumentableDecl(Decl *D); void ActOnDocumentableDecls(ArrayRef Group); void ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, SourceLocation LocAfterDecls); void CheckForFunctionRedefinition( FunctionDecl *FD, const FunctionDecl *EffectiveDefinition = nullptr, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParamLists, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnStartOfFunctionDef(Scope *S, Decl *D, SkipBodyInfo *SkipBody = nullptr); void ActOnStartOfObjCMethodDef(Scope *S, Decl *D); bool isObjCMethodDecl(Decl *D) { return D && isa(D); } /// \brief Determine whether we can delay parsing the body of a function or /// function template until it is used, assuming we don't care about emitting /// code for that function. /// /// This will be \c false if we may need the body of the function in the /// middle of parsing an expression (where it's impractical to switch to /// parsing a different function), for instance, if it's constexpr in C++11 /// or has an 'auto' return type in C++14. These cases are essentially bugs. bool canDelayFunctionBody(const Declarator &D); /// \brief Determine whether we can skip parsing the body of a function /// definition, assuming we don't care about analyzing its body or emitting /// code for that function. /// /// This will be \c false only if we may need the body of the function in /// order to parse the rest of the program (for instance, if it is /// \c constexpr in C++11 or has an 'auto' return type in C++14). bool canSkipFunctionBody(Decl *D); void computeNRVO(Stmt *Body, sema::FunctionScopeInfo *Scope); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body); Decl *ActOnFinishFunctionBody(Decl *Decl, Stmt *Body, bool IsInstantiation); Decl *ActOnSkippedFunctionBody(Decl *Decl); void ActOnFinishInlineFunctionDef(FunctionDecl *D); /// ActOnFinishDelayedAttribute - Invoked when we have finished parsing an /// attribute for which parsing is delayed. void ActOnFinishDelayedAttribute(Scope *S, Decl *D, ParsedAttributes &Attrs); /// \brief Diagnose any unused parameters in the given sequence of /// ParmVarDecl pointers. void DiagnoseUnusedParameters(ArrayRef Parameters); /// \brief Diagnose whether the size of parameters or return value of a /// function or obj-c method definition is pass-by-value and larger than a /// specified threshold. void DiagnoseSizeOfParametersAndReturnValue(ArrayRef Parameters, QualType ReturnTy, NamedDecl *D); void DiagnoseInvalidJumps(Stmt *Body); Decl *ActOnFileScopeAsmDecl(Expr *expr, SourceLocation AsmLoc, SourceLocation RParenLoc); /// \brief Handle a C++11 empty-declaration and attribute-declaration. Decl *ActOnEmptyDeclaration(Scope *S, AttributeList *AttrList, SourceLocation SemiLoc); /// \brief The parser has processed a module import declaration. /// /// \param AtLoc The location of the '@' symbol, if any. /// /// \param ImportLoc The location of the 'import' keyword. /// /// \param Path The module access path. DeclResult ActOnModuleImport(SourceLocation AtLoc, SourceLocation ImportLoc, ModuleIdPath Path); /// \brief The parser has processed a module import translated from a /// #include or similar preprocessing directive. void ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod); /// \brief The parsed has entered a submodule. void ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod); /// \brief The parser has left a submodule. void ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod); /// \brief Check if module import may be found in the current context, /// emit error if not. void diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc); /// \brief Create an implicit import of the given module at the given /// source location, for error recovery, if possible. /// /// This routine is typically used when an entity found by name lookup /// is actually hidden within a module that we know about but the user /// has forgotten to import. void createImplicitModuleImportForErrorRecovery(SourceLocation Loc, Module *Mod); /// Kinds of missing import. Note, the values of these enumerators correspond /// to %select values in diagnostics. enum class MissingImportKind { Declaration, Definition, DefaultArgument, ExplicitSpecialization, PartialSpecialization }; /// \brief Diagnose that the specified declaration needs to be visible but /// isn't, and suggest a module import that would resolve the problem. void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, MissingImportKind MIK, bool Recover = true); void diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef Modules, MissingImportKind MIK, bool Recover); /// \brief We've found a use of a templated declaration that would trigger an /// implicit instantiation. Check that any relevant explicit specializations /// and partial specializations are visible, and diagnose if not. void checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// \brief We've found a use of a template specialization that would select a /// partial specialization. Check that the partial specialization is visible, /// and diagnose if not. void checkPartialSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec); /// \brief Retrieve a suitable printing policy. PrintingPolicy getPrintingPolicy() const { return getPrintingPolicy(Context, PP); } /// \brief Retrieve a suitable printing policy. static PrintingPolicy getPrintingPolicy(const ASTContext &Ctx, const Preprocessor &PP); /// Scope actions. void ActOnPopScope(SourceLocation Loc, Scope *S); void ActOnTranslationUnitScope(Scope *S); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, RecordDecl *&AnonRecord); Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, MultiTemplateParamsArg TemplateParams, bool IsExplicitInstantiation, RecordDecl *&AnonRecord); Decl *BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, AccessSpecifier AS, RecordDecl *Record, const PrintingPolicy &Policy); Decl *BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, RecordDecl *Record); bool isAcceptableTagRedeclaration(const TagDecl *Previous, TagTypeKind NewTag, bool isDefinition, SourceLocation NewTagLoc, const IdentifierInfo *Name); enum TagUseKind { TUK_Reference, // Reference to a tag: 'struct foo *X;' TUK_Declaration, // Fwd decl of a tag: 'struct foo;' TUK_Definition, // Definition of a tag: 'struct foo { int X; } Y;' TUK_Friend // Friend declaration: 'friend struct foo;' }; Decl *ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, AccessSpecifier AS, SourceLocation ModulePrivateLoc, MultiTemplateParamsArg TemplateParameterLists, bool &OwnedDecl, bool &IsDependent, SourceLocation ScopedEnumKWLoc, bool ScopedEnumUsesClassTag, TypeResult UnderlyingType, bool IsTypeSpecifier, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, unsigned TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, MultiTemplateParamsArg TempParamLists); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, SmallVectorImpl &Decls); Decl *ActOnField(Scope *S, Decl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth); FieldDecl *HandleField(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS); MSPropertyDecl *HandleMSProperty(Scope *S, RecordDecl *TagD, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, InClassInitStyle InitStyle, AccessSpecifier AS, AttributeList *MSPropertyAttr); FieldDecl *CheckFieldDecl(DeclarationName Name, QualType T, TypeSourceInfo *TInfo, RecordDecl *Record, SourceLocation Loc, bool Mutable, Expr *BitfieldWidth, InClassInitStyle InitStyle, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D = nullptr); bool CheckNontrivialField(FieldDecl *FD); void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, bool Diagnose = false); CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD); void ActOnLastBitfield(SourceLocation DeclStart, SmallVectorImpl &AllIvarDecls); Decl *ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitfieldWidth, tok::ObjCKeywordKind visibility); // This is used for both record definitions and ObjC interface declarations. void ActOnFields(Scope* S, SourceLocation RecLoc, Decl *TagDecl, ArrayRef Fields, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); /// ActOnTagStartDefinition - Invoked when we have entered the /// scope of a tag's definition (e.g., for an enumeration, class, /// struct, or union). void ActOnTagStartDefinition(Scope *S, Decl *TagDecl); typedef void *SkippedDefinitionContext; /// \brief Invoked when we enter a tag definition that we're skipping. SkippedDefinitionContext ActOnTagStartSkippedDefinition(Scope *S, Decl *TD); Decl *ActOnObjCContainerStartDefinition(Decl *IDecl); /// ActOnStartCXXMemberDeclarations - Invoked when we have parsed a /// C++ record definition's base-specifiers clause and are starting its /// member declarations. void ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagDecl, SourceLocation FinalLoc, bool IsFinalSpelledSealed, SourceLocation LBraceLoc); /// ActOnTagFinishDefinition - Invoked once we have finished parsing /// the definition of a tag (enumeration, class, struct, or union). void ActOnTagFinishDefinition(Scope *S, Decl *TagDecl, SourceRange BraceRange); void ActOnTagFinishSkippedDefinition(SkippedDefinitionContext Context); void ActOnObjCContainerFinishDefinition(); /// \brief Invoked when we must temporarily exit the objective-c container /// scope for parsing/looking-up C constructs. /// /// Must be followed by a call to \see ActOnObjCReenterContainerContext void ActOnObjCTemporaryExitContainerContext(DeclContext *DC); void ActOnObjCReenterContainerContext(DeclContext *DC); /// ActOnTagDefinitionError - Invoked when there was an unrecoverable /// error parsing the definition of a tag. void ActOnTagDefinitionError(Scope *S, Decl *TagDecl); EnumConstantDecl *CheckEnumConstant(EnumDecl *Enum, EnumConstantDecl *LastEnumConst, SourceLocation IdLoc, IdentifierInfo *Id, Expr *val); bool CheckEnumUnderlyingType(TypeSourceInfo *TI); bool CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, QualType EnumUnderlyingTy, bool EnumUnderlyingIsImplicit, const EnumDecl *Prev); /// Determine whether the body of an anonymous enumeration should be skipped. /// \param II The name of the first enumerator. SkipBodyInfo shouldSkipAnonEnumBody(Scope *S, IdentifierInfo *II, SourceLocation IILoc); Decl *ActOnEnumConstant(Scope *S, Decl *EnumDecl, Decl *LastEnumConstant, SourceLocation IdLoc, IdentifierInfo *Id, AttributeList *Attrs, SourceLocation EqualLoc, Expr *Val); void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, Decl *EnumDecl, ArrayRef Elements, Scope *S, AttributeList *Attr); DeclContext *getContainingDC(DeclContext *DC); /// Set the current declaration context until it gets popped. void PushDeclContext(Scope *S, DeclContext *DC); void PopDeclContext(); /// EnterDeclaratorContext - Used when we must lookup names in the context /// of a declarator's nested name specifier. void EnterDeclaratorContext(Scope *S, DeclContext *DC); void ExitDeclaratorContext(Scope *S); /// Push the parameters of D, which must be a function, into scope. void ActOnReenterFunctionContext(Scope* S, Decl* D); void ActOnExitFunctionContext(); DeclContext *getFunctionLevelDeclContext(); /// getCurFunctionDecl - If inside of a function body, this returns a pointer /// to the function decl for the function being parsed. If we're currently /// in a 'block', this returns the containing context. FunctionDecl *getCurFunctionDecl(); /// getCurMethodDecl - If inside of a method body, this returns a pointer to /// the method decl for the method being parsed. If we're currently /// in a 'block', this returns the containing context. ObjCMethodDecl *getCurMethodDecl(); /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method /// or C function we're in, otherwise return null. If we're currently /// in a 'block', this returns the containing context. NamedDecl *getCurFunctionOrMethodDecl(); /// Add this decl to the scope shadowed decl chains. void PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext = true); /// \brief Make the given externally-produced declaration visible at the /// top level scope. /// /// \param D The externally-produced declaration to push. /// /// \param Name The name of the externally-produced declaration. void pushExternalDeclIntoScope(NamedDecl *D, DeclarationName Name); /// isDeclInScope - If 'Ctx' is a function/method, isDeclInScope returns true /// if 'D' is in Scope 'S', otherwise 'S' is ignored and isDeclInScope returns /// true if 'D' belongs to the given declaration context. /// /// \param AllowInlineNamespace If \c true, allow the declaration to be in the /// enclosing namespace set of the context, rather than contained /// directly within it. bool isDeclInScope(NamedDecl *D, DeclContext *Ctx, Scope *S = nullptr, bool AllowInlineNamespace = false); /// Finds the scope corresponding to the given decl context, if it /// happens to be an enclosing scope. Otherwise return NULL. static Scope *getScopeForDeclContext(Scope *S, DeclContext *DC); /// Subroutines of ActOnDeclarator(). TypedefDecl *ParseTypedefDecl(Scope *S, Declarator &D, QualType T, TypeSourceInfo *TInfo); bool isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New); /// \brief Describes the kind of merge to perform for availability /// attributes (including "deprecated", "unavailable", and "availability"). enum AvailabilityMergeKind { /// \brief Don't merge availability attributes at all. AMK_None, /// \brief Merge availability attributes for a redeclaration, which requires /// an exact match. AMK_Redeclaration, /// \brief Merge availability attributes for an override, which requires /// an exact match or a weakening of constraints. AMK_Override, /// \brief Merge availability attributes for an implementation of /// a protocol requirement. AMK_ProtocolImplementation, }; /// Attribute merging methods. Return true if a new attribute was added. AvailabilityAttr *mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK, unsigned AttrSpellingListIndex); TypeVisibilityAttr *mergeTypeVisibilityAttr(Decl *D, SourceRange Range, TypeVisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex); VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range, VisibilityAttr::VisibilityType Vis, unsigned AttrSpellingListIndex); DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); MSInheritanceAttr * mergeMSInheritanceAttr(Decl *D, SourceRange Range, bool BestCase, unsigned AttrSpellingListIndex, MSInheritanceAttr::Spelling SemanticSpelling); FormatAttr *mergeFormatAttr(Decl *D, SourceRange Range, IdentifierInfo *Format, int FormatIdx, int FirstArg, unsigned AttrSpellingListIndex); SectionAttr *mergeSectionAttr(Decl *D, SourceRange Range, StringRef Name, unsigned AttrSpellingListIndex); AlwaysInlineAttr *mergeAlwaysInlineAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); MinSizeAttr *mergeMinSizeAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex); InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); CommonAttr *mergeCommonAttr(Decl *D, SourceRange Range, IdentifierInfo *Ident, unsigned AttrSpellingListIndex); void mergeDeclAttributes(NamedDecl *New, Decl *Old, AvailabilityMergeKind AMK = AMK_Redeclaration); void MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, LookupResult &OldDecls); bool MergeFunctionDecl(FunctionDecl *New, NamedDecl *&Old, Scope *S, bool MergeTypeWithOld); bool MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, Scope *S, bool MergeTypeWithOld); void mergeObjCMethodDecls(ObjCMethodDecl *New, ObjCMethodDecl *Old); void MergeVarDecl(VarDecl *New, LookupResult &Previous); void MergeVarDeclTypes(VarDecl *New, VarDecl *Old, bool MergeTypeWithOld); void MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old); bool MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S); // AssignmentAction - This is used by all the assignment diagnostic functions // to represent what is actually causing the operation enum AssignmentAction { AA_Assigning, AA_Passing, AA_Returning, AA_Converting, AA_Initializing, AA_Sending, AA_Casting, AA_Passing_CFAudited }; /// C++ Overloading. enum OverloadKind { /// This is a legitimate overload: the existing declarations are /// functions or function templates with different signatures. Ovl_Overload, /// This is not an overload because the signature exactly matches /// an existing declaration. Ovl_Match, /// This is not an overload because the lookup results contain a /// non-function. Ovl_NonFunction }; OverloadKind CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &OldDecls, NamedDecl *&OldDecl, bool IsForUsingDecl); bool IsOverload(FunctionDecl *New, FunctionDecl *Old, bool IsForUsingDecl, bool ConsiderCudaAttrs = true); /// \brief Checks availability of the function depending on the current /// function context.Inside an unavailable function,unavailability is ignored. /// /// \returns true if \p FD is unavailable and current context is inside /// an available function, false otherwise. bool isFunctionConsideredUnavailable(FunctionDecl *FD); ImplicitConversionSequence TryImplicitConversion(Expr *From, QualType ToType, bool SuppressUserConversions, bool AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion); bool IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType); bool IsFloatingPointPromotion(QualType FromType, QualType ToType); bool IsComplexPromotion(QualType FromType, QualType ToType); bool IsPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType, bool &IncompatibleObjC); bool isObjCWritebackConversion(QualType FromType, QualType ToType, QualType &ConvertedType); bool IsBlockPointerConversion(QualType FromType, QualType ToType, QualType& ConvertedType); bool FunctionParamTypesAreEqual(const FunctionProtoType *OldType, const FunctionProtoType *NewType, unsigned *ArgPos = nullptr); void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); void maybeExtendBlockObject(ExprResult &E); CastKind PrepareCastToObjCObjectPointer(ExprResult &E); bool CheckPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath& BasePath, bool IgnoreBaseAccess, bool Diagnose = true); bool IsMemberPointerConversion(Expr *From, QualType FromType, QualType ToType, bool InOverloadResolution, QualType &ConvertedType); bool CheckMemberPointerConversion(Expr *From, QualType ToType, CastKind &Kind, CXXCastPath &BasePath, bool IgnoreBaseAccess); bool IsQualificationConversion(QualType FromType, QualType ToType, bool CStyle, bool &ObjCLifetimeConversion); bool IsNoReturnConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); bool isSameOrCompatibleFunctionType(CanQualType Param, CanQualType Arg); ExprResult PerformMoveOrCopyInitialization(const InitializedEntity &Entity, const VarDecl *NRVOCandidate, QualType ResultType, Expr *Value, bool AllowNRVO = true); bool CanPerformCopyInitialization(const InitializedEntity &Entity, ExprResult Init); ExprResult PerformCopyInitialization(const InitializedEntity &Entity, SourceLocation EqualLoc, ExprResult Init, bool TopLevelOfInitList = false, bool AllowExplicit = false); ExprResult PerformObjectArgumentInitialization(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, CXXMethodDecl *Method); ExprResult PerformContextuallyConvertToBool(Expr *From); ExprResult PerformContextuallyConvertToObjCPointer(Expr *From); /// Contexts in which a converted constant expression is required. enum CCEKind { CCEK_CaseValue, ///< Expression in a case label. CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. CCEK_ConstexprIf ///< Condition in a constexpr if statement. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, APValue &Value, CCEKind CCE); /// \brief Abstract base class used to perform a contextual implicit /// conversion from an expression to any type passing a filter. class ContextualImplicitConverter { public: bool Suppress; bool SuppressConversion; ContextualImplicitConverter(bool Suppress = false, bool SuppressConversion = false) : Suppress(Suppress), SuppressConversion(SuppressConversion) {} /// \brief Determine whether the specified type is a valid destination type /// for this conversion. virtual bool match(QualType T) = 0; /// \brief Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the expression has incomplete class type. virtual SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a diagnostic when the only matching conversion function /// is explicit. virtual SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; /// \brief Emits a note for the explicit conversion function. virtual SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when there are multiple possible conversion /// functions. virtual SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) = 0; /// \brief Emits a note for one of the candidate conversions. virtual SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) = 0; /// \brief Emits a diagnostic when we picked a conversion function /// (for cases when we are not allowed to pick a conversion function). virtual SemaDiagnosticBuilder diagnoseConversion( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) = 0; virtual ~ContextualImplicitConverter() {} }; class ICEConvertDiagnoser : public ContextualImplicitConverter { bool AllowScopedEnumerations; public: ICEConvertDiagnoser(bool AllowScopedEnumerations, bool Suppress, bool SuppressConversion) : ContextualImplicitConverter(Suppress, SuppressConversion), AllowScopedEnumerations(AllowScopedEnumerations) {} /// Match an integral or (possibly scoped) enumeration type. bool match(QualType T) override; SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return diagnoseNotInt(S, Loc, T); } /// \brief Emits a diagnostic complaining that the expression does not have /// integral or enumeration type. virtual SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) = 0; }; /// Perform a contextual implicit conversion. ExprResult PerformContextualImplicitConversion( SourceLocation Loc, Expr *FromE, ContextualImplicitConverter &Converter); enum ObjCSubscriptKind { OS_Array, OS_Dictionary, OS_Error }; ObjCSubscriptKind CheckSubscriptingKind(Expr *FromE); // Note that LK_String is intentionally after the other literals, as // this is used for diagnostics logic. enum ObjCLiteralKind { LK_Array, LK_Dictionary, LK_Numeric, LK_Boxed, LK_String, LK_Block, LK_None }; ObjCLiteralKind CheckLiteralKind(Expr *FromE); ExprResult PerformObjectMemberConversion(Expr *From, NestedNameSpecifier *Qualifier, NamedDecl *FoundDecl, NamedDecl *Member); // Members have to be NamespaceDecl* or TranslationUnitDecl*. // TODO: make this is a typesafe union. typedef llvm::SmallSetVector AssociatedNamespaceSet; typedef llvm::SmallSetVector AssociatedClassSet; void AddOverloadCandidate(FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = false); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, ArrayRef Args, OverloadCandidateSet &CandidateSet, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddMethodCandidate(DeclAccessPair FoundDecl, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversion = false); void AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false); void AddConversionCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet& CandidateSet, bool AllowObjCConversionOnExplicit); void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, const FunctionProtoType *Proto, Expr *Object, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddMemberOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet, SourceRange OpRange = SourceRange()); void AddBuiltinCandidate(QualType ResultTy, QualType *ParamTys, ArrayRef Args, OverloadCandidateSet& CandidateSet, bool IsAssignmentOperator = false, unsigned NumContextualBoolArguments = 0); void AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, SourceLocation OpLoc, ArrayRef Args, OverloadCandidateSet& CandidateSet); void AddArgumentDependentLookupCandidates(DeclarationName Name, SourceLocation Loc, ArrayRef Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, bool PartialOverloading = false); // Emit as a 'note' the specific overload candidate void NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, QualType DestType = QualType(), bool TakingAddress = false); // Emit as a series of 'note's all template and non-templates identified by // the expression Expr void NoteAllOverloadCandidates(Expr *E, QualType DestType = QualType(), bool TakingAddress = false); /// Check the enable_if expressions on the given function. Returns the first /// failing attribute, or NULL if they were all successful. EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef Args, bool MissingImplicitThis = false); /// Returns whether the given function's address can be taken or not, /// optionally emitting a diagnostic if the address can't be taken. /// /// Returns false if taking the address of the function is illegal. bool checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, bool Complain = false, SourceLocation Loc = SourceLocation()); // [PossiblyAFunctionType] --> [Return] // NonFunctionType --> NonFunctionType // R (A) --> R(A) // R (*)(A) --> R (A) // R (&)(A) --> R (A) // R (S::*)(A) --> R (A) QualType ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType); FunctionDecl * ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, QualType TargetType, bool Complain, DeclAccessPair &Found, bool *pHadMultipleCandidates = nullptr); FunctionDecl * resolveAddressOfOnlyViableOverloadCandidate(Expr *E, DeclAccessPair &FoundResult); bool resolveAndFixAddressOfOnlyViableOverloadCandidate(ExprResult &SrcExpr); FunctionDecl * ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, bool Complain = false, DeclAccessPair *Found = nullptr); bool ResolveAndFixSingleFunctionTemplateSpecialization( ExprResult &SrcExpr, bool DoFunctionPointerConverion = false, bool Complain = false, SourceRange OpRangeForComplaining = SourceRange(), QualType DestTypeForComplaining = QualType(), unsigned DiagIDForComplaining = 0); Expr *FixOverloadedFunctionReference(Expr *E, DeclAccessPair FoundDecl, FunctionDecl *Fn); ExprResult FixOverloadedFunctionReference(ExprResult, DeclAccessPair FoundDecl, FunctionDecl *Fn); void AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool PartialOverloading = false); // An enum used to represent the different possible results of building a // range-based for loop. enum ForRangeStatus { FRS_Success, FRS_NoViableFunction, FRS_DiagnosticIssued }; ForRangeStatus BuildForRangeBeginEndCall(SourceLocation Loc, SourceLocation RangeLoc, const DeclarationNameInfo &NameInfo, LookupResult &MemberLookup, OverloadCandidateSet *CandidateSet, Expr *Range, ExprResult *CallExpr); ExprResult BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig, bool AllowTypoCorrection=true, bool CalleesAddressIsTaken=false); bool buildOverloadedCallSet(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, MultiExprArg Args, SourceLocation RParenLoc, OverloadCandidateSet *CandidateSet, ExprResult *Result); ExprResult CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *input); ExprResult CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS); ExprResult CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, Expr *Base,Expr *Idx); ExprResult BuildCallToMemberFunction(Scope *S, Expr *MemExpr, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildCallToObjectOfClassType(Scope *S, Expr *Object, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc); ExprResult BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool *NoArrowOperatorFound = nullptr); /// CheckCallReturnType - Checks that a call expression's return type is /// complete. Returns true on failure. The location passed in is the location /// that best represents the call. bool CheckCallReturnType(QualType ReturnType, SourceLocation Loc, CallExpr *CE, FunctionDecl *FD); /// Helpers for dealing with blocks and functions. bool CheckParmsForFunctionDef(ArrayRef Parameters, bool CheckParameterNames); void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); Scope *getNonFieldDeclScope(Scope *S); /// \name Name lookup /// /// These routines provide name lookup that is used during semantic /// analysis to resolve the various kinds of names (identifiers, /// overloaded operator names, constructor names, etc.) into zero or /// more declarations within a particular scope. The major entry /// points are LookupName, which performs unqualified name lookup, /// and LookupQualifiedName, which performs qualified name lookup. /// /// All name lookup is performed based on some specific criteria, /// which specify what names will be visible to name lookup and how /// far name lookup should work. These criteria are important both /// for capturing language semantics (certain lookups will ignore /// certain names, for example) and for performance, since name /// lookup is often a bottleneck in the compilation of C++. Name /// lookup criteria is specified via the LookupCriteria enumeration. /// /// The results of name lookup can vary based on the kind of name /// lookup performed, the current language, and the translation /// unit. In C, for example, name lookup will either return nothing /// (no entity found) or a single declaration. In C++, name lookup /// can additionally refer to a set of overloaded functions or /// result in an ambiguity. All of the possible results of name /// lookup are captured by the LookupResult class, which provides /// the ability to distinguish among them. //@{ /// @brief Describes the kind of name lookup to perform. enum LookupNameKind { /// Ordinary name lookup, which finds ordinary names (functions, /// variables, typedefs, etc.) in C and most kinds of names /// (functions, variables, members, types, etc.) in C++. LookupOrdinaryName = 0, /// Tag name lookup, which finds the names of enums, classes, /// structs, and unions. LookupTagName, /// Label name lookup. LookupLabel, /// Member name lookup, which finds the names of /// class/struct/union members. LookupMemberName, /// Look up of an operator name (e.g., operator+) for use with /// operator overloading. This lookup is similar to ordinary name /// lookup, but will ignore any declarations that are class members. LookupOperatorName, /// Look up of a name that precedes the '::' scope resolution /// operator in C++. This lookup completely ignores operator, object, /// function, and enumerator names (C++ [basic.lookup.qual]p1). LookupNestedNameSpecifierName, /// Look up a namespace name within a C++ using directive or /// namespace alias definition, ignoring non-namespace names (C++ /// [basic.lookup.udir]p1). LookupNamespaceName, /// Look up all declarations in a scope with the given name, /// including resolved using declarations. This is appropriate /// for checking redeclarations for a using declaration. LookupUsingDeclName, /// Look up an ordinary name that is going to be redeclared as a /// name with linkage. This lookup ignores any declarations that /// are outside of the current scope unless they have linkage. See /// C99 6.2.2p4-5 and C++ [basic.link]p6. LookupRedeclarationWithLinkage, /// Look up a friend of a local class. This lookup does not look /// outside the innermost non-class scope. See C++11 [class.friend]p11. LookupLocalFriendName, /// Look up the name of an Objective-C protocol. LookupObjCProtocolName, /// Look up implicit 'self' parameter of an objective-c method. LookupObjCImplicitSelfParam, /// \brief Look up the name of an OpenMP user-defined reduction operation. LookupOMPReductionName, /// \brief Look up any declaration with any name. LookupAnyName }; /// \brief Specifies whether (or how) name lookup is being performed for a /// redeclaration (vs. a reference). enum RedeclarationKind { /// \brief The lookup is a reference to this name that is not for the /// purpose of redeclaring the name. NotForRedeclaration = 0, /// \brief The lookup results will be used for redeclaration of a name, /// if an entity by that name already exists. ForRedeclaration }; /// \brief The possible outcomes of name lookup for a literal operator. enum LiteralOperatorLookupResult { /// \brief The lookup resulted in an error. LOLR_Error, /// \brief The lookup found a single 'cooked' literal operator, which /// expects a normal literal to be built and passed to it. LOLR_Cooked, /// \brief The lookup found a single 'raw' literal operator, which expects /// a string literal containing the spelling of the literal token. LOLR_Raw, /// \brief The lookup found an overload set of literal operator templates, /// which expect the characters of the spelling of the literal token to be /// passed as a non-type template argument pack. LOLR_Template, /// \brief The lookup found an overload set of literal operator templates, /// which expect the character type and characters of the spelling of the /// string literal token to be passed as template arguments. LOLR_StringTemplate }; SpecialMemberOverloadResult *LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); typedef std::function TypoDiagnosticGenerator; typedef std::function TypoRecoveryCallback; private: bool CppLookupName(LookupResult &R, Scope *S); struct TypoExprState { std::unique_ptr Consumer; TypoDiagnosticGenerator DiagHandler; TypoRecoveryCallback RecoveryHandler; TypoExprState(); TypoExprState(TypoExprState&& other) LLVM_NOEXCEPT; TypoExprState& operator=(TypoExprState&& other) LLVM_NOEXCEPT; }; /// \brief The set of unhandled TypoExprs and their associated state. llvm::MapVector DelayedTypos; /// \brief Creates a new TypoExpr AST node. TypoExpr *createDelayedTypo(std::unique_ptr TCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC); // \brief The set of known/encountered (unique, canonicalized) NamespaceDecls. // // The boolean value will be true to indicate that the namespace was loaded // from an AST/PCH file, or false otherwise. llvm::MapVector KnownNamespaces; /// \brief Whether we have already loaded known namespaces from an extenal /// source. bool LoadedExternalKnownNamespaces; /// \brief Helper for CorrectTypo and CorrectTypoDelayed used to create and /// populate a new TypoCorrectionConsumer. Returns nullptr if typo correction /// should be skipped entirely. std::unique_ptr makeTypoCorrectionConsumer(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, DeclContext *MemberContext, bool EnteringContext, const ObjCObjectPointerType *OPT, bool ErrorRecovery); public: const TypoExprState &getTypoExprState(TypoExpr *TE) const; /// \brief Clears the state of the given TypoExpr. void clearDelayedTypo(TypoExpr *TE); /// \brief Look up a name, looking for a single declaration. Return /// null if the results were absent, ambiguous, or overloaded. /// /// It is preferable to use the elaborated form and explicitly handle /// ambiguity and overloaded. NamedDecl *LookupSingleName(Scope *S, DeclarationName Name, SourceLocation Loc, LookupNameKind NameKind, RedeclarationKind Redecl = NotForRedeclaration); bool LookupName(LookupResult &R, Scope *S, bool AllowBuiltinCreation = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, bool InUnqualifiedLookup = false); bool LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, CXXScopeSpec &SS); bool LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS, bool AllowBuiltinCreation = false, bool EnteringContext = false); ObjCProtocolDecl *LookupProtocol(IdentifierInfo *II, SourceLocation IdLoc, RedeclarationKind Redecl = NotForRedeclaration); bool LookupInSuper(LookupResult &R, CXXRecordDecl *Class); void LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, QualType T1, QualType T2, UnresolvedSetImpl &Functions); void addOverloadedOperatorToUnresolvedSet(UnresolvedSetImpl &Functions, DeclAccessPair Operator, QualType T1, QualType T2); LabelDecl *LookupOrCreateLabel(IdentifierInfo *II, SourceLocation IdentLoc, SourceLocation GnuLabelLoc = SourceLocation()); DeclContextLookupResult LookupConstructors(CXXRecordDecl *Class); CXXConstructorDecl *LookupDefaultConstructor(CXXRecordDecl *Class); CXXConstructorDecl *LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupCopyingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXConstructorDecl *LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals); CXXMethodDecl *LookupMovingAssignment(CXXRecordDecl *Class, unsigned Quals, bool RValueThis, unsigned ThisQuals); CXXDestructorDecl *LookupDestructor(CXXRecordDecl *Class); bool checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Id); LiteralOperatorLookupResult LookupLiteralOperator(Scope *S, LookupResult &R, ArrayRef ArgTys, bool AllowRaw, bool AllowTemplate, bool AllowStringTemplate); bool isKnownName(StringRef name); void ArgumentDependentLookup(DeclarationName Name, SourceLocation Loc, ArrayRef Args, ADLResult &Functions); void LookupVisibleDecls(Scope *S, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true); void LookupVisibleDecls(DeclContext *Ctx, LookupNameKind Kind, VisibleDeclConsumer &Consumer, bool IncludeGlobalScope = true); enum CorrectTypoKind { CTK_NonError, // CorrectTypo used in a non error recovery situation. CTK_ErrorRecovery // CorrectTypo used in normal error recovery. }; TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr, bool RecordFailure = true); TypoExpr *CorrectTypoDelayed(const DeclarationNameInfo &Typo, Sema::LookupNameKind LookupKind, Scope *S, CXXScopeSpec *SS, std::unique_ptr CCC, TypoDiagnosticGenerator TDG, TypoRecoveryCallback TRC, CorrectTypoKind Mode, DeclContext *MemberContext = nullptr, bool EnteringContext = false, const ObjCObjectPointerType *OPT = nullptr); /// \brief Process any TypoExprs in the given Expr and its children, /// generating diagnostics as appropriate and returning a new Expr if there /// were typos that were all successfully corrected and ExprError if one or /// more typos could not be corrected. /// /// \param E The Expr to check for TypoExprs. /// /// \param InitDecl A VarDecl to avoid because the Expr being corrected is its /// initializer. /// /// \param Filter A function applied to a newly rebuilt Expr to determine if /// it is an acceptable/usable result from a single combination of typo /// corrections. As long as the filter returns ExprError, different /// combinations of corrections will be tried until all are exhausted. ExprResult CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }); ExprResult CorrectDelayedTyposInExpr(Expr *E, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(E, nullptr, Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, VarDecl *InitDecl = nullptr, llvm::function_ref Filter = [](Expr *E) -> ExprResult { return E; }) { return ER.isInvalid() ? ER : CorrectDelayedTyposInExpr(ER.get(), Filter); } ExprResult CorrectDelayedTyposInExpr(ExprResult ER, llvm::function_ref Filter) { return CorrectDelayedTyposInExpr(ER, nullptr, Filter); } void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, bool ErrorRecovery = true); void diagnoseTypo(const TypoCorrection &Correction, const PartialDiagnostic &TypoDiag, const PartialDiagnostic &PrevNote, bool ErrorRecovery = true); void FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, ArrayRef Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, bool ConsiderLinkage, bool AllowInlineNamespace); void DiagnoseAmbiguousLookup(LookupResult &Result); //@} ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); NamedDecl *LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, Scope *S, bool ForRedeclaration, SourceLocation Loc); NamedDecl *ImplicitlyDefineFunction(SourceLocation Loc, IdentifierInfo &II, Scope *S); void AddKnownFunctionAttributes(FunctionDecl *FD); // More parsing and symbol table subroutines. void ProcessPragmaWeak(Scope *S, Decl *D); // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const AttributeList *AttrList); void checkUnusedDeclAttributes(Declarator &D); /// Determine if type T is a valid subject for a nonnull and similar /// attributes. By default, we look through references (the behavior used by /// nonnull), but if the second parameter is true, then we treat a reference /// type as valid. bool isValidPointerAttrType(QualType T, bool RefOkay = false); bool CheckRegparmAttr(const AttributeList &attr, unsigned &value); bool CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, const FunctionDecl *FD = nullptr); bool CheckNoReturnAttr(const AttributeList &attr); bool checkStringLiteralArgumentAttr(const AttributeList &Attr, unsigned ArgNum, StringRef &Str, SourceLocation *ArgLocation = nullptr); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); void checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceAttr::Spelling SemanticSpelling); void CheckAlignasUnderalignment(Decl *D); /// Adjust the calling convention of a method to be the ABI default if it /// wasn't specified explicitly. This handles method types formed from /// function type typedefs and typename template arguments. void adjustMemberFunctionCC(QualType &T, bool IsStatic, bool IsCtorOrDtor, SourceLocation Loc); // Check if there is an explicit attribute, but only look through parens. // The intent is to look for an attribute on the current declarator, but not // one that came from a typedef. bool hasExplicitCallingConv(QualType &T); /// Get the outermost AttributedType node that sets a calling convention. /// Valid types should not have multiple attributes with different CCs. const AttributedType *getCallingConvAttributedType(QualType T) const; /// Check whether a nullability type specifier can be added to the given /// type. /// /// \param type The type to which the nullability specifier will be /// added. On success, this type will be updated appropriately. /// /// \param nullability The nullability specifier to add. /// /// \param nullabilityLoc The location of the nullability specifier. /// /// \param isContextSensitive Whether this nullability specifier was /// written as a context-sensitive keyword (in an Objective-C /// method) or an Objective-C property attribute, rather than as an /// underscored type specifier. /// /// \returns true if nullability cannot be applied, false otherwise. bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, SourceLocation nullabilityLoc, bool isContextSensitive); /// \brief Stmt attributes - this routine is the top level dispatcher. StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs, SourceRange Range); void WarnConflictingTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); void CheckConflictingOverridingMethod(ObjCMethodDecl *Method, ObjCMethodDecl *Overridden, bool IsProtocolMethodDecl); /// WarnExactTypedMethods - This routine issues a warning if method /// implementation declaration matches exactly that of its declaration. void WarnExactTypedMethods(ObjCMethodDecl *Method, ObjCMethodDecl *MethodDecl, bool IsProtocolMethodDecl); typedef llvm::SmallPtrSet SelectorSet; typedef llvm::DenseMap ProtocolsMethodsMap; /// CheckImplementationIvars - This routine checks if the instance variables /// listed in the implelementation match those listed in the interface. void CheckImplementationIvars(ObjCImplementationDecl *ImpDecl, ObjCIvarDecl **Fields, unsigned nIvars, SourceLocation Loc); /// ImplMethodsVsClassMethods - This is main routine to warn if any method /// remains unimplemented in the class or category \@implementation. void ImplMethodsVsClassMethods(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool IncompleteImpl = false); /// DiagnoseUnimplementedProperties - This routine warns on those properties /// which must be implemented by this implementation. void DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, bool SynthesizeProperties); /// Diagnose any null-resettable synthesized setters. void diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl); /// DefaultSynthesizeProperties - This routine default synthesizes all /// properties which must be synthesized in the class's \@implementation. void DefaultSynthesizeProperties (Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl); void DefaultSynthesizeProperties(Scope *S, Decl *D); /// IvarBacksCurrentMethodAccessor - This routine returns 'true' if 'IV' is /// an ivar synthesized for 'Method' and 'Method' is a property accessor /// declared in class 'IFace'. bool IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, ObjCMethodDecl *Method, ObjCIvarDecl *IV); /// DiagnoseUnusedBackingIvarInAccessor - Issue an 'unused' warning if ivar which /// backs the property is not used in the property's accessor. void DiagnoseUnusedBackingIvarInAccessor(Scope *S, const ObjCImplementationDecl *ImplD); /// GetIvarBackingPropertyAccessor - If method is a property setter/getter and /// it property has a backing ivar, returns this ivar; otherwise, returns NULL. /// It also returns ivar's property on success. ObjCIvarDecl *GetIvarBackingPropertyAccessor(const ObjCMethodDecl *Method, const ObjCPropertyDecl *&PDecl) const; /// Called by ActOnProperty to handle \@property declarations in /// class extensions. ObjCPropertyDecl *HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isReadWrite, unsigned &Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind); /// Called by ActOnProperty and HandlePropertyInClassExtension to /// handle creating the ObjcPropertyDecl for a category or \@interface. ObjCPropertyDecl *CreatePropertyDecl(Scope *S, ObjCContainerDecl *CDecl, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, Selector GetterSel, Selector SetterSel, const bool isReadWrite, const unsigned Attributes, const unsigned AttributesAsWritten, QualType T, TypeSourceInfo *TSI, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); /// AtomicPropertySetterGetterRules - This routine enforces the rule (via /// warning) when atomic property has one but not the other user-declared /// setter or getter. void AtomicPropertySetterGetterRules(ObjCImplDecl* IMPDecl, ObjCInterfaceDecl* IDecl); void DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D); void DiagnoseMissingDesignatedInitOverrides( const ObjCImplementationDecl *ImplD, const ObjCInterfaceDecl *IFD); void DiagnoseDuplicateIvars(ObjCInterfaceDecl *ID, ObjCInterfaceDecl *SID); enum MethodMatchStrategy { MMS_loose, MMS_strict }; /// MatchTwoMethodDeclarations - Checks if two methods' type match and returns /// true, or false, accordingly. bool MatchTwoMethodDeclarations(const ObjCMethodDecl *Method, const ObjCMethodDecl *PrevMethod, MethodMatchStrategy strategy = MMS_strict); /// MatchAllMethodDeclarations - Check methods declaraed in interface or /// or protocol against those declared in their implementations. void MatchAllMethodDeclarations(const SelectorSet &InsMap, const SelectorSet &ClsMap, SelectorSet &InsMapSeen, SelectorSet &ClsMapSeen, ObjCImplDecl* IMPDecl, ObjCContainerDecl* IDecl, bool &IncompleteImpl, bool ImmediateClass, bool WarnCategoryMethodImpl=false); /// CheckCategoryVsClassMethodMatches - Checks that methods implemented in /// category matches with those implemented in its primary class and /// warns each time an exact match is found. void CheckCategoryVsClassMethodMatches(ObjCCategoryImplDecl *CatIMP); /// \brief Add the given method to the list of globally-known methods. void addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method); private: /// AddMethodToGlobalPool - Add an instance or factory method to the global /// pool. See descriptoin of AddInstanceMethodToGlobalPool. void AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance); /// LookupMethodInGlobalPool - Returns the instance or factory method and /// optionally warns if there are multiple signatures. ObjCMethodDecl *LookupMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass, bool instance); public: /// \brief - Returns instance or factory methods in global method pool for /// given selector. It checks the desired kind first, if none is found, and /// parameter checkTheOther is set, it then checks the other kind. If no such /// method or only one method is found, function returns false; otherwise, it /// returns true. bool CollectMultipleMethodsInGlobalPool(Selector Sel, SmallVectorImpl& Methods, bool InstanceFirst, bool CheckTheOther, const ObjCObjectType *TypeBound = nullptr); bool AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, bool receiverIdOrClass, SmallVectorImpl& Methods); void DiagnoseMultipleMethodInGlobalPool(SmallVectorImpl &Methods, Selector Sel, SourceRange R, bool receiverIdOrClass); private: /// \brief - Returns a selector which best matches given argument list or /// nullptr if none could be found ObjCMethodDecl *SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, SmallVectorImpl& Methods); /// \brief Record the typo correction failure and return an empty correction. TypoCorrection FailedCorrection(IdentifierInfo *Typo, SourceLocation TypoLoc, bool RecordFailure = true) { if (RecordFailure) TypoCorrectionFailures[Typo].insert(TypoLoc); return TypoCorrection(); } public: /// AddInstanceMethodToGlobalPool - All instance methods in a translation /// unit are added to a global pool. This allows us to efficiently associate /// a selector with a method declaraation for purposes of typechecking /// messages sent to "id" (where the class of the object is unknown). void AddInstanceMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/true); } /// AddFactoryMethodToGlobalPool - Same as above, but for factory methods. void AddFactoryMethodToGlobalPool(ObjCMethodDecl *Method, bool impl=false) { AddMethodToGlobalPool(Method, impl, /*instance*/false); } /// AddAnyMethodToGlobalPool - Add any method, instance or factory to global /// pool. void AddAnyMethodToGlobalPool(Decl *D); /// LookupInstanceMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupInstanceMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/true); } /// LookupFactoryMethodInGlobalPool - Returns the method and warns if /// there are multiple signatures. ObjCMethodDecl *LookupFactoryMethodInGlobalPool(Selector Sel, SourceRange R, bool receiverIdOrClass=false) { return LookupMethodInGlobalPool(Sel, R, receiverIdOrClass, /*instance*/false); } const ObjCMethodDecl *SelectorsForTypoCorrection(Selector Sel, QualType ObjectType=QualType()); /// LookupImplementedMethodInGlobalPool - Returns the method which has an /// implementation. ObjCMethodDecl *LookupImplementedMethodInGlobalPool(Selector Sel); /// CollectIvarsToConstructOrDestruct - Collect those ivars which require /// initialization. void CollectIvarsToConstructOrDestruct(ObjCInterfaceDecl *OI, SmallVectorImpl &Ivars); //===--------------------------------------------------------------------===// // Statement Parsing Callbacks: SemaStmt.cpp. public: class FullExprArg { public: FullExprArg() : E(nullptr) { } FullExprArg(Sema &actions) : E(nullptr) { } ExprResult release() { return E; } Expr *get() const { return E; } Expr *operator->() { return E; } private: // FIXME: No need to make the entire Sema class a friend when it's just // Sema::MakeFullExpr that needs access to the constructor below. friend class Sema; explicit FullExprArg(Expr *expr) : E(expr) {} Expr *E; }; FullExprArg MakeFullExpr(Expr *Arg) { return MakeFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation()); } FullExprArg MakeFullExpr(Expr *Arg, SourceLocation CC) { return FullExprArg(ActOnFinishFullExpr(Arg, CC).get()); } FullExprArg MakeFullDiscardedValueExpr(Expr *Arg) { ExprResult FE = ActOnFinishFullExpr(Arg, Arg ? Arg->getExprLoc() : SourceLocation(), /*DiscardedValue*/ true); return FullExprArg(FE.get()); } StmtResult ActOnExprStmt(ExprResult Arg); StmtResult ActOnExprStmtError(); StmtResult ActOnNullStmt(SourceLocation SemiLoc, bool HasLeadingEmptyMacro = false); void ActOnStartOfCompoundStmt(); void ActOnFinishOfCompoundStmt(); StmtResult ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef Elts, bool isStmtExpr); /// \brief A RAII object to enter scope of a compound statement. class CompoundScopeRAII { public: CompoundScopeRAII(Sema &S): S(S) { S.ActOnStartOfCompoundStmt(); } ~CompoundScopeRAII() { S.ActOnFinishOfCompoundStmt(); } private: Sema &S; }; /// An RAII helper that pops function a function scope on exit. struct FunctionScopeRAII { Sema &S; bool Active; FunctionScopeRAII(Sema &S) : S(S), Active(true) {} ~FunctionScopeRAII() { if (Active) S.PopFunctionScopeInfo(); } void disable() { Active = false; } }; StmtResult ActOnDeclStmt(DeclGroupPtrTy Decl, SourceLocation StartLoc, SourceLocation EndLoc); void ActOnForEachDeclStmt(DeclGroupPtrTy Decl); StmtResult ActOnForEachLValueExpr(Expr *E); StmtResult ActOnCaseStmt(SourceLocation CaseLoc, Expr *LHSVal, SourceLocation DotDotDotLoc, Expr *RHSVal, SourceLocation ColonLoc); void ActOnCaseStmtBody(Stmt *CaseStmt, Stmt *SubStmt); StmtResult ActOnDefaultStmt(SourceLocation DefaultLoc, SourceLocation ColonLoc, Stmt *SubStmt, Scope *CurScope); StmtResult ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, SourceLocation ColonLoc, Stmt *SubStmt); StmtResult ActOnAttributedStmt(SourceLocation AttrLoc, ArrayRef Attrs, Stmt *SubStmt); class ConditionResult; StmtResult ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, ConditionResult Cond, Stmt *ThenVal, SourceLocation ElseLoc, Stmt *ElseVal); StmtResult ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Stmt *InitStmt, ConditionResult Cond); StmtResult ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, Stmt *Body); StmtResult ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, Stmt *Body); StmtResult ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, SourceLocation WhileLoc, SourceLocation CondLParen, Expr *Cond, SourceLocation CondRParen); StmtResult ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, Stmt *First, ConditionResult Second, FullExprArg Third, SourceLocation RParenLoc, Stmt *Body); ExprResult CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection); StmtResult ActOnObjCForCollectionStmt(SourceLocation ForColLoc, Stmt *First, Expr *collection, SourceLocation RParenLoc); StmtResult FinishObjCForCollectionStmt(Stmt *ForCollection, Stmt *Body); enum BuildForRangeKind { /// Initial building of a for-range statement. BFRK_Build, /// Instantiation or recovery rebuild of a for-range statement. Don't /// attempt any typo-correction. BFRK_Rebuild, /// Determining whether a for-range statement could be built. Avoid any /// unnecessary or irreversible actions. BFRK_Check }; StmtResult ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *LoopVar, SourceLocation ColonLoc, Expr *Collection, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind); StmtResult FinishCXXForRangeStmt(Stmt *ForRange, Stmt *Body); StmtResult ActOnGotoStmt(SourceLocation GotoLoc, SourceLocation LabelLoc, LabelDecl *TheDecl); StmtResult ActOnIndirectGotoStmt(SourceLocation GotoLoc, SourceLocation StarLoc, Expr *DestExp); StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, unsigned NumParams); typedef std::pair CapturedParamNameType; void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, CapturedRegionKind Kind, ArrayRef Params); StmtResult ActOnCapturedRegionEnd(Stmt *S); void ActOnCapturedRegionError(); RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc, unsigned NumParams); VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, bool AllowParamOrMoveConstructible); bool isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, bool AllowParamOrMoveConstructible); StmtResult ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope); StmtResult BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp); StmtResult ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, MultiExprArg Constraints, MultiExprArg Exprs, Expr *AsmString, MultiExprArg Clobbers, SourceLocation RParenLoc); ExprResult LookupInlineAsmIdentifier(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, llvm::InlineAsmIdentifierInfo &Info, bool IsUnevaluatedContext); bool LookupInlineAsmField(StringRef Base, StringRef Member, unsigned &Offset, SourceLocation AsmLoc); ExprResult LookupInlineAsmVarDeclField(Expr *RefExpr, StringRef Member, llvm::InlineAsmIdentifierInfo &Info, SourceLocation AsmLoc); StmtResult ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, ArrayRef AsmToks, StringRef AsmString, unsigned NumOutputs, unsigned NumInputs, ArrayRef Constraints, ArrayRef Clobbers, ArrayRef Exprs, SourceLocation EndLoc); LabelDecl *GetOrCreateMSAsmLabel(StringRef ExternalLabelName, SourceLocation Location, bool AlwaysCreate); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); StmtResult ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, Stmt *Body); StmtResult ActOnObjCAtFinallyStmt(SourceLocation AtLoc, Stmt *Body); StmtResult ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, MultiStmtArg Catch, Stmt *Finally); StmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw); StmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, Scope *CurScope); ExprResult ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand); StmtResult ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, Expr *SynchExpr, Stmt *SynchBody); StmtResult ActOnObjCAutoreleasePoolStmt(SourceLocation AtLoc, Stmt *Body); VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); StmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, Decl *ExDecl, Stmt *HandlerBlock); StmtResult ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, ArrayRef Handlers); StmtResult ActOnSEHTryBlock(bool IsCXXTry, // try (true) or __try (false) ? SourceLocation TryLoc, Stmt *TryBlock, Stmt *Handler); StmtResult ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, Stmt *Block); void ActOnStartSEHFinallyBlock(); void ActOnAbortSEHFinallyBlock(); StmtResult ActOnFinishSEHFinallyBlock(SourceLocation Loc, Stmt *Block); StmtResult ActOnSEHLeaveStmt(SourceLocation Loc, Scope *CurScope); void DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock); bool ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const; /// \brief If it's a file scoped decl that must warn if not used, keep track /// of it. void MarkUnusedFileScopedDecl(const DeclaratorDecl *D); /// DiagnoseUnusedExprResult - If the statement passed in is an expression /// whose result is unused, warn. void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedNestedTypedefs(const RecordDecl *D); void DiagnoseUnusedDecl(const NamedDecl *ND); /// Emit \p DiagID if statement located on \p StmtLoc has a suspicious null /// statement as a \p Body, and it is located on the same line. /// /// This helps prevent bugs due to typos, such as: /// if (condition); /// do_stuff(); void DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, unsigned DiagID); /// Warn if a for/while loop statement \p S, which is followed by /// \p PossibleBody, has a suspicious null statement as a body. void DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody); /// Warn if a value is moved to itself. void DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc); /// \brief Warn if we're implicitly casting from a _Nullable pointer type to a /// _Nonnull one. void diagnoseNullableToNonnullConversion(QualType DstType, QualType SrcType, SourceLocation Loc); ParsingDeclState PushParsingDeclaration(sema::DelayedDiagnosticPool &pool) { return DelayedDiagnostics.push(pool); } void PopParsingDeclaration(ParsingDeclState state, Decl *decl); typedef ProcessingContextState ParsingClassState; ParsingClassState PushParsingClass() { return DelayedDiagnostics.pushUndelayed(); } void PopParsingClass(ParsingClassState state) { DelayedDiagnostics.popUndelayed(state); } void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial }; void EmitAvailabilityWarning(AvailabilityDiagnostic AD, NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess); bool makeUnavailableInSystemHeader(SourceLocation loc, UnavailableAttr::ImplicitReason reason); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. bool CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid); bool DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass=nullptr, bool ObjCPropertyAccess=false); void NoteDeletedFunction(FunctionDecl *FD); void NoteDeletedInheritingConstructor(CXXConstructorDecl *CD); std::string getDeletedOrUnavailableSuffix(const FunctionDecl *FD); bool DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *PD, ObjCMethodDecl *Getter, SourceLocation Loc); void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc, ArrayRef Args); void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false); enum ReuseLambdaContextDecl_t { ReuseLambdaContextDecl }; void PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, ReuseLambdaContextDecl_t, bool IsDecltype = false); void PopExpressionEvaluationContext(); void DiscardCleanupsInEvaluationContext(); ExprResult TransformToPotentiallyEvaluated(Expr *E); ExprResult HandleExprEvaluationContextForTypeof(Expr *E); ExprResult ActOnConstantExpression(ExprResult Res); // Functions for marking a declaration referenced. These functions also // contain the relevant logic for marking if a reference to a function or // variable is an odr-use (in the C++11 sense). There are separate variants // for expressions referring to a decl; these exist because odr-use marking // needs to be delayed for some constant variables when we build one of the // named expressions. // // MightBeOdrUse indicates whether the use could possibly be an odr-use, and // should usually be true. This only needs to be set to false if the lack of // odr-use cannot be determined from the current context (for instance, // because the name denotes a virtual function and was written without an // explicit nested-name-specifier). void MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool MightBeOdrUse); void MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, bool MightBeOdrUse = true); void MarkVariableReferenced(SourceLocation Loc, VarDecl *Var); void MarkDeclRefReferenced(DeclRefExpr *E); void MarkMemberReferenced(MemberExpr *E); void UpdateMarkingForLValueToRValue(Expr *E); void CleanupVarDeclMarking(); enum TryCaptureKind { TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef }; /// \brief Try to capture the given variable. /// /// \param Var The variable to capture. /// /// \param Loc The location at which the capture occurs. /// /// \param Kind The kind of capture, which may be implicit (for either a /// block or a lambda), or explicit by-value or by-reference (for a lambda). /// /// \param EllipsisLoc The location of the ellipsis, if one is provided in /// an explicit lambda capture. /// /// \param BuildAndDiagnose Whether we are actually supposed to add the /// captures or diagnose errors. If false, this routine merely check whether /// the capture can occur without performing the capture itself or complaining /// if the variable cannot be captured. /// /// \param CaptureType Will be set to the type of the field used to capture /// this variable in the innermost block or lambda. Only valid when the /// variable can be captured. /// /// \param DeclRefType Will be set to the type of a reference to the capture /// from within the current scope. Only valid when the variable can be /// captured. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// variables that may or may not be used in certain specializations of /// a nested generic lambda. /// /// \returns true if an error occurred (i.e., the variable cannot be /// captured) and false if the capture succeeded. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind, SourceLocation EllipsisLoc, bool BuildAndDiagnose, QualType &CaptureType, QualType &DeclRefType, const unsigned *const FunctionScopeIndexToStopAt); /// \brief Try to capture the given variable. bool tryCaptureVariable(VarDecl *Var, SourceLocation Loc, TryCaptureKind Kind = TryCapture_Implicit, SourceLocation EllipsisLoc = SourceLocation()); /// \brief Checks if the variable must be captured. bool NeedToCaptureVariable(VarDecl *Var, SourceLocation Loc); /// \brief Given a variable, determine the type that a reference to that /// variable will have in the given scope. QualType getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc); void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T); void MarkDeclarationsReferencedInExpr(Expr *E, bool SkipLocalVariables = false); /// \brief Try to recover by turning the given expression into a /// call. Returns true if recovery was attempted or an error was /// emitted; this may also leave the ExprResult invalid. bool tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain = false, bool (*IsPlausibleResult)(QualType) = nullptr); /// \brief Figure out if an expression could be turned into a call. bool tryExprAsCall(Expr &E, QualType &ZeroArgCallReturnTy, UnresolvedSetImpl &NonTemplateOverloads); /// \brief Conditionally issue a diagnostic based on the current /// evaluation context. /// /// \param Statement If Statement is non-null, delay reporting the /// diagnostic until the function body is parsed, and then do a basic /// reachability analysis to determine if the statement is reachable. /// If it is unreachable, the diagnostic will not be emitted. bool DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, const PartialDiagnostic &PD); // Primary Expressions. SourceRange getExprRange(Expr *E) const; ExprResult ActOnIdExpression( Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Id, bool HasTrailingLParen, bool IsAddressOfOperand, std::unique_ptr CCC = nullptr, bool IsInlineAsmIdentifier = false, Token *KeywordReplacement = nullptr); void DecomposeUnqualifiedId(const UnqualifiedId &Id, TemplateArgumentListInfo &Buffer, DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *&TemplateArgs); bool DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, std::unique_ptr CCC, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr, ArrayRef Args = None, TypoExpr **Out = nullptr); ExprResult LookupInObjCMethod(LookupResult &LookUp, Scope *S, IdentifierInfo *II, bool AllowBuiltinCreation=false); ExprResult ActOnDependentIdExpression(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, bool isAddressOfOperand, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, SourceLocation Loc, const CXXScopeSpec *SS = nullptr); ExprResult BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS = nullptr, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr); ExprResult BuildAnonymousStructUnionMemberReference( const CXXScopeSpec &SS, SourceLocation nameLoc, IndirectFieldDecl *indirectField, DeclAccessPair FoundDecl = DeclAccessPair::make(nullptr, AS_none), Expr *baseObjectExpr = nullptr, SourceLocation opLoc = SourceLocation()); ExprResult BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S); ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, bool IsDefiniteInstance, const Scope *S); bool UseArgumentDependentLookup(const CXXScopeSpec &SS, const LookupResult &R, bool HasTrailingLParen); ExprResult BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, bool IsAddressOfOperand, const Scope *S, TypeSourceInfo **RecoveryTSI = nullptr); ExprResult BuildDependentDeclRefExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, bool AcceptInvalidDecl = false); ExprResult BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD = nullptr, const TemplateArgumentListInfo *TemplateArgs = nullptr, bool AcceptInvalidDecl = false); ExprResult BuildLiteralOperatorCall(LookupResult &R, DeclarationNameInfo &SuffixInfo, ArrayRef Args, SourceLocation LitEndLoc, TemplateArgumentListInfo *ExplicitTemplateArgs = nullptr); ExprResult BuildPredefinedExpr(SourceLocation Loc, PredefinedExpr::IdentType IT); ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnCharacterConstant(const Token &Tok, Scope *UDLScope = nullptr); ExprResult ActOnParenExpr(SourceLocation L, SourceLocation R, Expr *E); ExprResult ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val); /// ActOnStringLiteral - The specified tokens were lexed as pasted string /// fragments (e.g. "foo" "bar" L"baz"). ExprResult ActOnStringLiteral(ArrayRef StringToks, Scope *UDLScope = nullptr); ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef ArgTypes, ArrayRef ArgExprs); ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc, SourceLocation DefaultLoc, SourceLocation RParenLoc, Expr *ControllingExpr, ArrayRef Types, ArrayRef Exprs); // Binary/Unary Operators. 'Tok' is the token for the operator. ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *InputExpr); ExprResult BuildUnaryOp(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opc, Expr *Input); ExprResult ActOnUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Op, Expr *Input); QualType CheckAddressOfOperand(ExprResult &Operand, SourceLocation OpLoc); ExprResult CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, SourceRange R); ExprResult CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, UnaryExprOrTypeTrait ExprKind, bool IsType, void *TyOrEx, SourceRange ArgRange); ExprResult CheckPlaceholderExpr(Expr *E); bool CheckVecStepExpr(Expr *E); bool CheckUnaryExprOrTypeTraitOperand(Expr *E, UnaryExprOrTypeTrait ExprKind); bool CheckUnaryExprOrTypeTraitOperand(QualType ExprType, SourceLocation OpLoc, SourceRange ExprRange, UnaryExprOrTypeTrait ExprKind); ExprResult ActOnSizeofParameterPackExpr(Scope *S, SourceLocation OpLoc, IdentifierInfo &Name, SourceLocation NameLoc, SourceLocation RParenLoc); ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc, tok::TokenKind Kind, Expr *Input); ExprResult ActOnArraySubscriptExpr(Scope *S, Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *Idx, SourceLocation RLoc); ExprResult ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, SourceLocation ColonLoc, Expr *Length, SourceLocation RBLoc); // This struct is for use by ActOnMemberAccess to allow // BuildMemberReferenceExpr to be able to reinvoke ActOnMemberAccess after // changing the access operator from a '.' to a '->' (to see if that is the // change needed to fix an error about an unknown member, e.g. when the class // defines a custom operator->). struct ActOnMemberAccessExtraArgs { Scope *S; UnqualifiedId &Id; Decl *ObjCImpDecl; }; ExprResult BuildMemberReferenceExpr( Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult BuildMemberReferenceExpr(Expr *Base, QualType BaseType, SourceLocation OpLoc, bool IsArrow, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, LookupResult &R, const TemplateArgumentListInfo *TemplateArgs, const Scope *S, bool SuppressQualifierCheck = false, ActOnMemberAccessExtraArgs *ExtraArgs = nullptr); ExprResult PerformMemberExprBaseConversion(Expr *Base, bool IsArrow); bool CheckQualifiedMemberReference(Expr *BaseExpr, QualType BaseType, const CXXScopeSpec &SS, const LookupResult &R); ExprResult ActOnDependentMemberExpr(Expr *Base, QualType BaseType, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, NamedDecl *FirstQualifierInScope, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); ExprResult ActOnMemberAccessExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Member, Decl *ObjCImpDecl); void ActOnDefaultCtorInitializers(Decl *CDtorDecl); bool ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, FunctionDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation RParenLoc, bool ExecConfig = false); void CheckStaticArrayArgument(SourceLocation CallLoc, ParmVarDecl *Param, const Expr *ArgExpr); /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. ExprResult ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig = nullptr, bool IsExecConfig = false); ExprResult BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation LParenLoc, ArrayRef Arg, SourceLocation RParenLoc, Expr *Config = nullptr, bool IsExecConfig = false); ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc); ExprResult ActOnCastExpr(Scope *S, SourceLocation LParenLoc, Declarator &D, ParsedType &Ty, SourceLocation RParenLoc, Expr *CastExpr); ExprResult BuildCStyleCastExpr(SourceLocation LParenLoc, TypeSourceInfo *Ty, SourceLocation RParenLoc, Expr *Op); CastKind PrepareScalarCast(ExprResult &src, QualType destType); /// \brief Build an altivec or OpenCL literal. ExprResult BuildVectorLiteral(SourceLocation LParenLoc, SourceLocation RParenLoc, Expr *E, TypeSourceInfo *TInfo); ExprResult MaybeConvertParenListExprToParenExpr(Scope *S, Expr *ME); ExprResult ActOnCompoundLiteral(SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc, Expr *InitExpr); ExprResult BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceLocation RParenLoc, Expr *LiteralExpr); ExprResult ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc); ExprResult ActOnDesignatedInitializer(Designation &Desig, SourceLocation Loc, bool GNUSyntax, ExprResult Init); private: static BinaryOperatorKind ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind); public: ExprResult ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, Expr *LHSExpr, Expr *RHSExpr); ExprResult BuildBinOp(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); ExprResult CreateBuiltinBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, Expr *LHSExpr, Expr *RHSExpr); void DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc); /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult ActOnConditionalOp(SourceLocation QuestionLoc, SourceLocation ColonLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr); /// ActOnAddrLabel - Parse the GNU address of label extension: "&&foo". ExprResult ActOnAddrLabel(SourceLocation OpLoc, SourceLocation LabLoc, LabelDecl *TheDecl); void ActOnStartStmtExpr(); ExprResult ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, SourceLocation RPLoc); // "({..})" void ActOnStmtExprError(); // __builtin_offsetof(type, identifier(.identifier|[expr])*) struct OffsetOfComponent { SourceLocation LocStart, LocEnd; bool isBrackets; // true if [expr], false if .ident union { IdentifierInfo *IdentInfo; Expr *E; } U; }; /// __builtin_offsetof(type, a.b[123][456].c) ExprResult BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, TypeSourceInfo *TInfo, ArrayRef Components, SourceLocation RParenLoc); ExprResult ActOnBuiltinOffsetOf(Scope *S, SourceLocation BuiltinLoc, SourceLocation TypeLoc, ParsedType ParsedArgTy, ArrayRef Components, SourceLocation RParenLoc); // __builtin_choose_expr(constExpr, expr1, expr2) ExprResult ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *CondExpr, Expr *LHSExpr, Expr *RHSExpr, SourceLocation RPLoc); // __builtin_va_arg(expr, type) ExprResult ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, SourceLocation RPLoc); ExprResult BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *E, TypeSourceInfo *TInfo, SourceLocation RPLoc); // __null ExprResult ActOnGNUNullExpr(SourceLocation TokenLoc); bool CheckCaseExpression(Expr *E); /// \brief Describes the result of an "if-exists" condition check. enum IfExistsResult { /// \brief The symbol exists. IER_Exists, /// \brief The symbol does not exist. IER_DoesNotExist, /// \brief The name is a dependent name, so the results will differ /// from one instantiation to the next. IER_Dependent, /// \brief An error occurred. IER_Error }; IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo); IfExistsResult CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name); StmtResult BuildMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, NestedNameSpecifierLoc QualifierLoc, DeclarationNameInfo NameInfo, Stmt *Nested); StmtResult ActOnMSDependentExistsStmt(SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name, Stmt *Nested); //===------------------------- "Block" Extension ------------------------===// /// ActOnBlockStart - This callback is invoked when a block literal is /// started. void ActOnBlockStart(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockArguments - This callback allows processing of block arguments. /// If there are no arguments, this is still invoked. void ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, Scope *CurScope); /// ActOnBlockError - If there is an error parsing a block, this callback /// is invoked to pop the information about the block from the action impl. void ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope); /// ActOnBlockStmtExpr - This is called when the body of a block statement /// literal was successfully completed. ^(int x){...} ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope); //===---------------------------- Clang Extensions ----------------------===// /// __builtin_convertvector(...) ExprResult ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- OpenCL Features -----------------------===// /// __builtin_astype(...) ExprResult ActOnAsTypeExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation BuiltinLoc, SourceLocation RParenLoc); //===---------------------------- C++ Features --------------------------===// // Act on C++ namespaces Decl *ActOnStartNamespaceDef(Scope *S, SourceLocation InlineLoc, SourceLocation NamespaceLoc, SourceLocation IdentLoc, IdentifierInfo *Ident, SourceLocation LBrace, AttributeList *AttrList, UsingDirectiveDecl * &UsingDecl); void ActOnFinishNamespaceDef(Decl *Dcl, SourceLocation RBrace); NamespaceDecl *getStdNamespace() const; NamespaceDecl *getOrCreateStdNamespace(); CXXRecordDecl *getStdBadAlloc() const; /// \brief Tests whether Ty is an instance of std::initializer_list and, if /// it is and Element is not NULL, assigns the element type to Element. bool isStdInitializerList(QualType Ty, QualType *Element); /// \brief Looks for the std::initializer_list template and instantiates it /// with Element, or emits an error if it's not found. /// /// \returns The instantiated template, or null on error. QualType BuildStdInitializerList(QualType Element, SourceLocation Loc); /// \brief Determine whether Ctor is an initializer-list constructor, as /// defined in [dcl.init.list]p2. bool isInitListConstructor(const CXXConstructorDecl *Ctor); Decl *ActOnUsingDirective(Scope *CurScope, SourceLocation UsingLoc, SourceLocation NamespcLoc, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *NamespcName, AttributeList *AttrList); void PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir); Decl *ActOnNamespaceAliasDef(Scope *CurScope, SourceLocation NamespaceLoc, SourceLocation AliasLoc, IdentifierInfo *Alias, CXXScopeSpec &SS, SourceLocation IdentLoc, IdentifierInfo *Ident); void HideUsingShadowDecl(Scope *S, UsingShadowDecl *Shadow); bool CheckUsingShadowDecl(UsingDecl *UD, NamedDecl *Target, const LookupResult &PreviousDecls, UsingShadowDecl *&PrevShadow); UsingShadowDecl *BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Target, UsingShadowDecl *PrevDecl); bool CheckUsingDeclRedeclaration(SourceLocation UsingLoc, bool HasTypenameKeyword, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Previous); bool CheckUsingDeclQualifier(SourceLocation UsingLoc, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc); NamedDecl *BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, AttributeList *AttrList, bool IsInstantiation, bool HasTypenameKeyword, SourceLocation TypenameLoc); bool CheckInheritingConstructorUsingDecl(UsingDecl *UD); /// Given a derived-class using shadow declaration for a constructor and the /// correspnding base class constructor, find or create the implicit /// synthesized derived class constructor to use for this initialization. CXXConstructorDecl * findInheritingConstructor(SourceLocation Loc, CXXConstructorDecl *BaseCtor, ConstructorUsingShadowDecl *DerivedShadow); Decl *ActOnUsingDeclaration(Scope *CurScope, AccessSpecifier AS, bool HasUsingKeyword, SourceLocation UsingLoc, CXXScopeSpec &SS, UnqualifiedId &Name, AttributeList *AttrList, bool HasTypenameKeyword, SourceLocation TypenameLoc); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, AttributeList *AttrList, TypeResult Type, Decl *DeclFromDeclSpec); /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. /// /// \param ConstructKind - a CXXConstructExpr::ConstructionKind ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); /// Build a CXXConstructExpr whose constructor has already been resolved if /// it denotes an inherited constructor. ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); // FIXME: Can we remove this and have the above BuildCXXConstructExpr check if // the constructor can be elidable? ExprResult BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, bool Elidable, MultiExprArg Exprs, bool HadMultipleCandidates, bool IsListInitialization, bool IsStdInitListInitialization, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange); ExprResult BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field); /// BuildCXXDefaultArgExpr - Creates a CXXDefaultArgExpr, instantiating /// the default expr if needed. ExprResult BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param); /// FinalizeVarWithDestructor - Prepare for calling destructor on the /// constructed variable. void FinalizeVarWithDestructor(VarDecl *VD, const RecordType *DeclInitType); /// \brief Helper class that collects exception specifications for /// implicitly-declared special member functions. class ImplicitExceptionSpecification { // Pointer to allow copying Sema *Self; // We order exception specifications thus: // noexcept is the most restrictive, but is only used in C++11. // throw() comes next. // Then a throw(collected exceptions) // Finally no specification, which is expressed as noexcept(false). // throw(...) is used instead if any called function uses it. ExceptionSpecificationType ComputedEST; llvm::SmallPtrSet ExceptionsSeen; SmallVector Exceptions; void ClearExceptions() { ExceptionsSeen.clear(); Exceptions.clear(); } public: explicit ImplicitExceptionSpecification(Sema &Self) : Self(&Self), ComputedEST(EST_BasicNoexcept) { if (!Self.getLangOpts().CPlusPlus11) ComputedEST = EST_DynamicNone; } /// \brief Get the computed exception specification type. ExceptionSpecificationType getExceptionSpecType() const { assert(ComputedEST != EST_ComputedNoexcept && "noexcept(expr) should not be a possible result"); return ComputedEST; } /// \brief The number of exceptions in the exception specification. unsigned size() const { return Exceptions.size(); } /// \brief The set of exceptions in the exception specification. const QualType *data() const { return Exceptions.data(); } /// \brief Integrate another called method into the collected data. void CalledDecl(SourceLocation CallLoc, const CXXMethodDecl *Method); /// \brief Integrate an invoked expression into the collected data. void CalledExpr(Expr *E); /// \brief Overwrite an EPI's exception specification with this /// computed exception specification. FunctionProtoType::ExceptionSpecInfo getExceptionSpec() const { FunctionProtoType::ExceptionSpecInfo ESI; ESI.Type = getExceptionSpecType(); if (ESI.Type == EST_Dynamic) { ESI.Exceptions = Exceptions; } else if (ESI.Type == EST_None) { /// C++11 [except.spec]p14: /// The exception-specification is noexcept(false) if the set of /// potential exceptions of the special member function contains "any" ESI.Type = EST_ComputedNoexcept; ESI.NoexceptExpr = Self->ActOnCXXBoolLiteral(SourceLocation(), tok::kw_false).get(); } return ESI; } }; /// \brief Determine what sort of exception specification a defaulted /// copy constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// default constructor of a class will have, and whether the parameter /// will be const. ImplicitExceptionSpecification ComputeDefaultedCopyCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defautled /// copy assignment operator of a class will have, and whether the /// parameter will be const. ImplicitExceptionSpecification ComputeDefaultedCopyAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// constructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveCtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted move /// assignment operator of a class will have. ImplicitExceptionSpecification ComputeDefaultedMoveAssignmentExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification a defaulted /// destructor of a class will have. ImplicitExceptionSpecification ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD); /// \brief Determine what sort of exception specification an inheriting /// constructor of a class will have. ImplicitExceptionSpecification ComputeInheritingCtorExceptionSpec(SourceLocation Loc, CXXConstructorDecl *CD); /// \brief Evaluate the implicit exception specification for a defaulted /// special member function. void EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD); /// \brief Check the given exception-specification and update the /// exception specification information with the results. void checkExceptionSpecification(bool IsTopLevel, ExceptionSpecificationType EST, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr, SmallVectorImpl &Exceptions, FunctionProtoType::ExceptionSpecInfo &ESI); /// \brief Determine if we're in a case where we need to (incorrectly) eagerly /// parse an exception specification to work around a libstdc++ bug. bool isLibstdcxxEagerExceptionSpecHack(const Declarator &D); /// \brief Add an exception-specification to the given member function /// (or member function template). The exception-specification was parsed /// after the method itself was declared. void actOnDelayedExceptionSpecification(Decl *Method, ExceptionSpecificationType EST, SourceRange SpecificationRange, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); class InheritedConstructorInfo; /// \brief Determine if a special member function should have a deleted /// definition when it is defaulted. bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); /// \brief Declare the implicit default constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// default constructor will be added. /// /// \returns The implicitly-declared default constructor. CXXConstructorDecl *DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl); /// DefineImplicitDefaultConstructor - Checks for feasibility of /// defining this constructor as the default constructor. void DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit destructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// destructor will be added. /// /// \returns The implicitly-declared destructor. CXXDestructorDecl *DeclareImplicitDestructor(CXXRecordDecl *ClassDecl); /// DefineImplicitDestructor - Checks for feasibility of /// defining this destructor as the default destructor. void DefineImplicitDestructor(SourceLocation CurrentLocation, CXXDestructorDecl *Destructor); /// \brief Build an exception spec for destructors that don't have one. /// /// C++11 says that user-defined destructors with no exception spec get one /// that looks as if the destructor was implicitly declared. void AdjustDestructorExceptionSpec(CXXRecordDecl *ClassDecl, CXXDestructorDecl *Destructor); /// \brief Define the specified inheriting constructor. void DefineInheritingConstructor(SourceLocation UseLoc, CXXConstructorDecl *Constructor); /// \brief Declare the implicit copy constructor for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy constructor will be added. /// /// \returns The implicitly-declared copy constructor. CXXConstructorDecl *DeclareImplicitCopyConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitCopyConstructor - Checks for feasibility of /// defining this constructor as the copy constructor. void DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit move constructor for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move constructor will be added. /// /// \returns The implicitly-declared move constructor, or NULL if it wasn't /// declared. CXXConstructorDecl *DeclareImplicitMoveConstructor(CXXRecordDecl *ClassDecl); /// DefineImplicitMoveConstructor - Checks for feasibility of /// defining this constructor as the move constructor. void DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXConstructorDecl *Constructor); /// \brief Declare the implicit copy assignment operator for the given class. /// /// \param ClassDecl The class declaration into which the implicit /// copy assignment operator will be added. /// /// \returns The implicitly-declared copy assignment operator. CXXMethodDecl *DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl); /// \brief Defines an implicitly-declared copy assignment operator. void DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// \brief Declare the implicit move assignment operator for the given class. /// /// \param ClassDecl The Class declaration into which the implicit /// move assignment operator will be added. /// /// \returns The implicitly-declared move assignment operator, or NULL if it /// wasn't declared. CXXMethodDecl *DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl); /// \brief Defines an implicitly-declared move assignment operator. void DefineImplicitMoveAssignment(SourceLocation CurrentLocation, CXXMethodDecl *MethodDecl); /// \brief Force the declaration of any implicitly-declared members of this /// class. void ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class); /// \brief Check a completed declaration of an implicit special member. void CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD); /// \brief Determine whether the given function is an implicitly-deleted /// special member function. bool isImplicitlyDeleted(FunctionDecl *FD); /// \brief Check whether 'this' shows up in the type of a static member /// function after the (naturally empty) cv-qualifier-seq would be. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionType(CXXMethodDecl *Method); /// \brief Whether this' shows up in the exception specification of a static /// member function. bool checkThisInStaticMemberFunctionExceptionSpec(CXXMethodDecl *Method); /// \brief Check whether 'this' shows up in the attributes of the given /// static member function. /// /// \returns true if an error occurred. bool checkThisInStaticMemberFunctionAttributes(CXXMethodDecl *Method); /// MaybeBindToTemporary - If the passed in expression has a record type with /// a non-trivial destructor, this will return CXXBindTemporaryExpr. Otherwise /// it simply returns the passed in expression. ExprResult MaybeBindToTemporary(Expr *E); bool CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, SmallVectorImpl &ConvertedArgs, bool AllowExplicit = false, bool IsListInitialization = false); ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name); ParsedType getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); ParsedType getDestructorType(const DeclSpec& DS, ParsedType ObjectType); // Checks that reinterpret casts don't have undefined behavior. void CheckCompatibleReinterpretCast(QualType SrcType, QualType DestType, bool IsDereference, SourceRange Range); /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. ExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, SourceLocation RAngleBracketLoc, SourceLocation LParenLoc, Expr *E, SourceLocation RParenLoc); ExprResult BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, TypeSourceInfo *Ty, Expr *E, SourceRange AngleBrackets, SourceRange Parens); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXTypeid - Parse typeid( something ). ExprResult ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc); ExprResult BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *Operand, SourceLocation RParenLoc); /// ActOnCXXUuidof - Parse __uuidof( something ). ExprResult ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc); /// \brief Handle a C++1z fold-expression: ( expr op ... op expr ). ExprResult ActOnCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, tok::TokenKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildCXXFoldExpr(SourceLocation LParenLoc, Expr *LHS, BinaryOperatorKind Operator, SourceLocation EllipsisLoc, Expr *RHS, SourceLocation RParenLoc); ExprResult BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator); //// ActOnCXXThis - Parse 'this' pointer. ExprResult ActOnCXXThis(SourceLocation loc); /// \brief Try to retrieve the type of the 'this' pointer. /// /// \returns The type of 'this', if possible. Otherwise, returns a NULL type. QualType getCurrentThisType(); /// \brief When non-NULL, the C++ 'this' expression is allowed despite the /// current context not being a non-static member function. In such cases, /// this provides the type used for 'this'. QualType CXXThisTypeOverride; /// \brief RAII object used to temporarily allow the C++ 'this' expression /// to be used, with the given qualifiers on the current class type. class CXXThisScopeRAII { Sema &S; QualType OldCXXThisTypeOverride; bool Enabled; public: /// \brief Introduce a new scope where 'this' may be allowed (when enabled), /// using the given declaration (which is either a class template or a /// class) along with the given qualifiers. /// along with the qualifiers placed on '*this'. CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, bool Enabled = true); ~CXXThisScopeRAII(); }; /// \brief Make sure the value of 'this' is actually available in the current /// context, if it is a potentially evaluated context. /// /// \param Loc The location at which the capture of 'this' occurs. /// /// \param Explicit Whether 'this' is explicitly captured in a lambda /// capture list. /// /// \param FunctionScopeIndexToStopAt If non-null, it points to the index /// of the FunctionScopeInfo stack beyond which we do not attempt to capture. /// This is useful when enclosing lambdas must speculatively capture /// 'this' that may or may not be used in certain specializations of /// a nested generic lambda (depending on whether the name resolves to /// a non-static member function or a static function). /// \return returns 'true' if failed, 'false' if success. bool CheckCXXThisCapture(SourceLocation Loc, bool Explicit = false, bool BuildAndDiagnose = true, const unsigned *const FunctionScopeIndexToStopAt = nullptr, bool ByCopy = false); /// \brief Determine whether the given type is the type of *this that is used /// outside of the body of a member function for a type that is currently /// being defined. bool isThisOutsideMemberFunctionBody(QualType BaseType); /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); /// ActOnObjCBoolLiteral - Parse {__objc_yes,__objc_no} literals. ExprResult ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind); ExprResult ActOnObjCAvailabilityCheckExpr(llvm::ArrayRef AvailSpecs, SourceLocation AtLoc, SourceLocation RParen); /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult ActOnCXXNullPtrLiteral(SourceLocation Loc); //// ActOnCXXThrow - Parse throw expressions. ExprResult ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *expr); ExprResult BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope); bool CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ThrowTy, Expr *E); /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc); ExprResult BuildCXXTypeConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc); /// ActOnCXXNew - Parsed a C++ 'new' expression. ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer); ExprResult BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceRange DirectInitRange, Expr *Initializer, bool TypeMayContainAuto = true); bool CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R); bool FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool UseGlobal, QualType AllocType, bool IsArray, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete); bool FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, MultiExprArg Args, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator, bool Diagnose = true); void DeclareGlobalNewDelete(); void DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, QualType Param1, QualType Param2 = QualType()); bool FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose = true); FunctionDecl *FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, DeclarationName Name); /// ActOnCXXDelete - Parsed a C++ 'delete' expression ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *Operand); void CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc); ExprResult ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation LParen, Expr *Operand, SourceLocation RParen); ExprResult BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen); /// \brief Parsed one of the type trait support pseudo-functions. ExprResult ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); ExprResult BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc); /// ActOnArrayTypeTrait - Parsed one of the bianry type trait support /// pseudo-functions. ExprResult ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType LhsTy, Expr *DimExpr, SourceLocation RParen); ExprResult BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr *DimExpr, SourceLocation RParen); /// ActOnExpressionTrait - Parsed one of the unary type trait support /// pseudo-functions. ExprResult ActOnExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult BuildExpressionTrait(ExpressionTrait OET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen); ExprResult ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor); ExprResult BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeType, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName); ExprResult ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS); /// MaybeCreateExprWithCleanups - If the current full-expression /// requires any cleanups, surround it with a ExprWithCleanups node. /// Otherwise, just returns the passed-in expression. Expr *MaybeCreateExprWithCleanups(Expr *SubExpr); Stmt *MaybeCreateStmtWithCleanups(Stmt *SubStmt); ExprResult MaybeCreateExprWithCleanups(ExprResult SubExpr); MaterializeTemporaryExpr * CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, bool BoundToLvalueReference); ExprResult ActOnFinishFullExpr(Expr *Expr) { return ActOnFinishFullExpr(Expr, Expr ? Expr->getExprLoc() : SourceLocation()); } ExprResult ActOnFinishFullExpr(Expr *Expr, SourceLocation CC, bool DiscardedValue = false, bool IsConstexpr = false, bool IsLambdaInitCaptureInitializer = false); StmtResult ActOnFinishFullStmt(Stmt *Stmt); // Marks SS invalid if it represents an incomplete type. bool RequireCompleteDeclContext(CXXScopeSpec &SS, DeclContext *DC); DeclContext *computeDeclContext(QualType T); DeclContext *computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext = false); bool isDependentScopeSpecifier(const CXXScopeSpec &SS); CXXRecordDecl *getCurrentInstantiationOf(NestedNameSpecifier *NNS); /// \brief The parser has parsed a global nested-name-specifier '::'. /// /// \param CCLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXGlobalScopeSpecifier(SourceLocation CCLoc, CXXScopeSpec &SS); /// \brief The parser has parsed a '__super' nested-name-specifier. /// /// \param SuperLoc The location of the '__super' keyword. /// /// \param ColonColonLoc The location of the '::'. /// /// \param SS The nested-name-specifier, which will be updated in-place /// to reflect the parsed nested-name-specifier. /// /// \returns true if an error occurred, false otherwise. bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc, SourceLocation ColonColonLoc, CXXScopeSpec &SS); bool isAcceptableNestedNameSpecifier(const NamedDecl *SD, bool *CanCorrect = nullptr); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation IdLoc, IdentifierInfo &II, ParsedType ObjectType); bool BuildCXXNestedNameSpecifier(Scope *S, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation CCLoc, QualType ObjectType, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon = nullptr); /// \brief The parser has parsed a nested-name-specifier 'identifier::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param Identifier The identifier preceding the '::'. /// /// \param IdentifierLoc The location of the identifier. /// /// \param CCLoc The location of the '::'. /// /// \param ObjectType The type of the object, if we're parsing /// nested-name-specifier in a member access expression. /// /// \param EnteringContext Whether we're entering the context nominated by /// this nested-name-specifier. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param ErrorRecoveryLookup If true, then this method is called to improve /// error recovery. In this case do not emit error message. /// /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':' /// are allowed. The bool value pointed by this parameter is set to 'true' /// if the identifier is treated as if it was followed by ':', not '::'. /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation CCLoc, ParsedType ObjectType, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup = false, bool *IsCorrectedToColon = nullptr); ExprResult ActOnDecltypeExpression(Expr *E); bool ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, const DeclSpec &DS, SourceLocation ColonColonLoc); bool IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, IdentifierInfo &Identifier, SourceLocation IdentifierLoc, SourceLocation ColonLoc, ParsedType ObjectType, bool EnteringContext); /// \brief The parser has parsed a nested-name-specifier /// 'template[opt] template-name < template-args >::'. /// /// \param S The scope in which this nested-name-specifier occurs. /// /// \param SS The nested-name-specifier, which is both an input /// parameter (the nested-name-specifier before this type) and an /// output parameter (containing the full nested-name-specifier, /// including this new type). /// /// \param TemplateKWLoc the location of the 'template' keyword, if any. /// \param TemplateName the template name. /// \param TemplateNameLoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). /// \param CCLoc The location of the '::'. /// /// \param EnteringContext Whether we're entering the context of the /// nested-name-specifier. /// /// /// \returns true if an error occurred, false otherwise. bool ActOnCXXNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateName, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, SourceLocation CCLoc, bool EnteringContext); /// \brief Given a C++ nested-name-specifier, produce an annotation value /// that the parser can use later to reconstruct the given /// nested-name-specifier. /// /// \param SS A nested-name-specifier. /// /// \returns A pointer containing all of the information in the /// nested-name-specifier \p SS. void *SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS); /// \brief Given an annotation pointer for a nested-name-specifier, restore /// the nested-name-specifier structure. /// /// \param Annotation The annotation pointer, produced by /// \c SaveNestedNameSpecifierAnnotation(). /// /// \param AnnotationRange The source range corresponding to the annotation. /// /// \param SS The nested-name-specifier that will be updated with the contents /// of the annotation pointer. void RestoreNestedNameSpecifierAnnotation(void *Annotation, SourceRange AnnotationRange, CXXScopeSpec &SS); bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclaratorScope - Called when a C++ scope specifier (global /// scope or nested-name-specifier) is parsed, part of a declarator-id. /// After this method is called, according to [C++ 3.4.3p3], names should be /// looked up in the declarator-id's scope, until the declarator is parsed and /// ActOnCXXExitDeclaratorScope is called. /// The 'SS' should be a non-empty valid CXXScopeSpec. bool ActOnCXXEnterDeclaratorScope(Scope *S, CXXScopeSpec &SS); /// ActOnCXXExitDeclaratorScope - Called when a declarator that previously /// invoked ActOnCXXEnterDeclaratorScope(), is finished. 'SS' is the same /// CXXScopeSpec that was passed to ActOnCXXEnterDeclaratorScope as well. /// Used to indicate that names should revert to being looked up in the /// defining scope. void ActOnCXXExitDeclaratorScope(Scope *S, const CXXScopeSpec &SS); /// ActOnCXXEnterDeclInitializer - Invoked when we are about to parse an /// initializer for the declaration 'Dcl'. /// After this method is called, according to [C++ 3.4.1p13], if 'Dcl' is a /// static data member of class X, names should be looked up in the scope of /// class X. void ActOnCXXEnterDeclInitializer(Scope *S, Decl *Dcl); /// ActOnCXXExitDeclInitializer - Invoked after we are finished parsing an /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); /// \brief Create a new lambda closure type. CXXRecordDecl *createLambdaClosureType(SourceRange IntroducerRange, TypeSourceInfo *Info, bool KnownDependent, LambdaCaptureDefault CaptureDefault); /// \brief Start the definition of a lambda expression. CXXMethodDecl *startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodType, SourceLocation EndLoc, ArrayRef Params); /// \brief Endow the lambda scope info with the relevant properties. void buildLambdaScope(sema::LambdaScopeInfo *LSI, CXXMethodDecl *CallOperator, SourceRange IntroducerRange, LambdaCaptureDefault CaptureDefault, SourceLocation CaptureDefaultLoc, bool ExplicitParams, bool ExplicitResultType, bool Mutable); /// \brief Perform initialization analysis of the init-capture and perform /// any implicit conversions such as an lvalue-to-rvalue conversion if /// not being used to initialize a reference. ParsedType actOnLambdaInitCaptureInitialization( SourceLocation Loc, bool ByRef, IdentifierInfo *Id, LambdaCaptureInitKind InitKind, Expr *&Init) { return ParsedType::make(buildLambdaInitCaptureInitialization( Loc, ByRef, Id, InitKind != LambdaCaptureInitKind::CopyInit, Init)); } QualType buildLambdaInitCaptureInitialization(SourceLocation Loc, bool ByRef, IdentifierInfo *Id, bool DirectInit, Expr *&Init); /// \brief Create a dummy variable within the declcontext of the lambda's /// call operator, for name lookup purposes for a lambda init capture. /// /// CodeGen handles emission of lambda captures, ignoring these dummy /// variables appropriately. VarDecl *createLambdaInitCaptureVarDecl(SourceLocation Loc, QualType InitCaptureType, IdentifierInfo *Id, unsigned InitStyle, Expr *Init); /// \brief Build the implicit field for an init-capture. FieldDecl *buildInitCaptureField(sema::LambdaScopeInfo *LSI, VarDecl *Var); /// \brief Note that we have finished the explicit captures for the /// given lambda. void finishLambdaExplicitCaptures(sema::LambdaScopeInfo *LSI); /// \brief Introduce the lambda parameters into scope. void addLambdaParameters(CXXMethodDecl *CallOperator, Scope *CurScope); /// \brief Deduce a block or lambda's return type based on the return /// statements present in the body. void deduceClosureReturnType(sema::CapturingScopeInfo &CSI); /// ActOnStartOfLambdaDefinition - This is called just before we start /// parsing the body of a lambda; it analyzes the explicit captures and /// arguments, and sets up various data-structures for the body of the /// lambda. void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback /// is invoked to pop the information about the lambda. void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, bool IsInstantiation = false); /// ActOnLambdaExpr - This is called when the body of a lambda expression /// was successfully completed. ExprResult ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, Scope *CurScope); /// \brief Complete a lambda-expression having processed and attached the /// lambda body. ExprResult BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, sema::LambdaScopeInfo *LSI); /// \brief Define the "body" of the conversion from a lambda object to a /// function pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToFunctionPointerConversion( SourceLocation CurrentLoc, CXXConversionDecl *Conv); /// \brief Define the "body" of the conversion from a lambda object to a /// block pointer. /// /// This routine doesn't actually define a sensible body; rather, it fills /// in the initialization expression needed to copy the lambda object into /// the block, and IR generation actually generates the real body of the /// block pointer conversion. void DefineImplicitLambdaToBlockPointerConversion(SourceLocation CurrentLoc, CXXConversionDecl *Conv); ExprResult BuildBlockForLambdaConversion(SourceLocation CurrentLocation, SourceLocation ConvLocation, CXXConversionDecl *Conv, Expr *Src); // ParseObjCStringLiteral - Parse Objective-C string literals. ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs, ArrayRef Strings); ExprResult BuildObjCStringLiteral(SourceLocation AtLoc, StringLiteral *S); /// BuildObjCNumericLiteral - builds an ObjCBoxedExpr AST node for the /// numeric literal expression. Type of the expression will be "NSNumber *" /// or "id" if NSNumber is unavailable. ExprResult BuildObjCNumericLiteral(SourceLocation AtLoc, Expr *Number); ExprResult ActOnObjCBoolLiteral(SourceLocation AtLoc, SourceLocation ValueLoc, bool Value); ExprResult BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements); /// BuildObjCBoxedExpr - builds an ObjCBoxedExpr AST node for the /// '@' prefixed parenthesized expression. The type of the expression will /// either be "NSNumber *", "NSString *" or "NSValue *" depending on the type /// of ValueType, which is allowed to be a built-in numeric type, "char *", /// "const char *" or C structure with attribute 'objc_boxable'. ExprResult BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr); ExprResult BuildObjCSubscriptExpression(SourceLocation RB, Expr *BaseExpr, Expr *IndexExpr, ObjCMethodDecl *getterMethod, ObjCMethodDecl *setterMethod); ExprResult BuildObjCDictionaryLiteral(SourceRange SR, MutableArrayRef Elements); ExprResult BuildObjCEncodeExpression(SourceLocation AtLoc, TypeSourceInfo *EncodedTypeInfo, SourceLocation RParenLoc); ExprResult BuildCXXMemberCallExpr(Expr *Exp, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates); ExprResult ParseObjCEncodeExpression(SourceLocation AtLoc, SourceLocation EncodeLoc, SourceLocation LParenLoc, ParsedType Ty, SourceLocation RParenLoc); /// ParseObjCSelectorExpression - Build selector expression for \@selector ExprResult ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, SourceLocation LParenLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors); /// ParseObjCProtocolExpression - Build protocol expression for \@protocol ExprResult ParseObjCProtocolExpression(IdentifierInfo * ProtocolName, SourceLocation AtLoc, SourceLocation ProtoLoc, SourceLocation LParenLoc, SourceLocation ProtoIdLoc, SourceLocation RParenLoc); //===--------------------------------------------------------------------===// // C++ Declarations // Decl *ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Expr *LangStr, SourceLocation LBraceLoc); Decl *ActOnFinishLinkageSpecification(Scope *S, Decl *LinkageSpec, SourceLocation RBraceLoc); //===--------------------------------------------------------------------===// // C++ Classes // bool isCurrentClassName(const IdentifierInfo &II, Scope *S, const CXXScopeSpec *SS = nullptr); bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS); bool ActOnAccessSpecifier(AccessSpecifier Access, SourceLocation ASLoc, SourceLocation ColonLoc, AttributeList *Attrs = nullptr); NamedDecl *ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, MultiTemplateParamsArg TemplateParameterLists, Expr *BitfieldWidth, const VirtSpecifiers &VS, InClassInitStyle InitStyle); void ActOnStartCXXInClassMemberInitializer(); void ActOnFinishCXXInClassMemberInitializer(Decl *VarDecl, SourceLocation EqualLoc, Expr *Init); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, SourceLocation LParenLoc, ArrayRef Args, SourceLocation RParenLoc, SourceLocation EllipsisLoc); MemInitResult ActOnMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *InitList, SourceLocation EllipsisLoc); MemInitResult BuildMemInitializer(Decl *ConstructorD, Scope *S, CXXScopeSpec &SS, IdentifierInfo *MemberOrBase, ParsedType TemplateTypeTy, const DeclSpec &DS, SourceLocation IdLoc, Expr *Init, SourceLocation EllipsisLoc); MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc); MemInitResult BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, Expr *Init, CXXRecordDecl *ClassDecl, SourceLocation EllipsisLoc); MemInitResult BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, CXXRecordDecl *ClassDecl); bool SetDelegatingInitializer(CXXConstructorDecl *Constructor, CXXCtorInitializer *Initializer); bool SetCtorInitializers(CXXConstructorDecl *Constructor, bool AnyErrors, ArrayRef Initializers = None); void SetIvarInitializers(ObjCImplementationDecl *ObjCImplementation); /// MarkBaseAndMemberDestructorsReferenced - Given a record decl, /// mark all the non-trivial destructors of its members and bases as /// referenced. void MarkBaseAndMemberDestructorsReferenced(SourceLocation Loc, CXXRecordDecl *Record); /// \brief The list of classes whose vtables have been used within /// this translation unit, and the source locations at which the /// first use occurred. typedef std::pair VTableUse; /// \brief The list of vtables that are required but have not yet been /// materialized. SmallVector VTableUses; /// \brief The set of classes whose vtables have been used within /// this translation unit, and a bit that will be true if the vtable is /// required to be emitted (otherwise, it should be emitted only if needed /// by code generation). llvm::DenseMap VTablesUsed; /// \brief Load any externally-stored vtable uses. void LoadExternalVTableUses(); /// \brief Note that the vtable for the given class was used at the /// given location. void MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, bool DefinitionRequired = false); /// \brief Mark the exception specifications of all virtual member functions /// in the given class as needed. void MarkVirtualMemberExceptionSpecsNeeded(SourceLocation Loc, const CXXRecordDecl *RD); /// MarkVirtualMembersReferenced - Will mark all members of the given /// CXXRecordDecl referenced. void MarkVirtualMembersReferenced(SourceLocation Loc, const CXXRecordDecl *RD); /// \brief Define all of the vtables that have been used in this /// translation unit and reference any virtual members used by those /// vtables. /// /// \returns true if any work was done, false otherwise. bool DefineUsedVTables(); void AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl); void ActOnMemInitializers(Decl *ConstructorDecl, SourceLocation ColonLoc, ArrayRef MemInits, bool AnyErrors); /// \brief Check class-level dllimport/dllexport attribute. The caller must /// ensure that referenceDLLExportedClassMethods is called some point later /// when all outer classes of Class are complete. void checkClassLevelDLLAttribute(CXXRecordDecl *Class); void referenceDLLExportedClassMethods(); void propagateDLLAttrToBaseClassTemplate( CXXRecordDecl *Class, Attr *ClassAttr, ClassTemplateSpecializationDecl *BaseTemplateSpec, SourceLocation BaseLoc); void CheckCompletedCXXClass(CXXRecordDecl *Record); void ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, Decl *TagDecl, SourceLocation LBrac, SourceLocation RBrac, AttributeList *AttrList); void ActOnFinishCXXMemberDecls(); void ActOnFinishCXXNonNestedClass(Decl *D); void ActOnReenterCXXMethodParameter(Scope *S, ParmVarDecl *Param); unsigned ActOnReenterTemplateScope(Scope *S, Decl *Template); void ActOnStartDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnStartDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnDelayedCXXMethodParameter(Scope *S, Decl *Param); void ActOnFinishDelayedMemberDeclarations(Scope *S, Decl *Record); void ActOnFinishDelayedCXXMethodDeclaration(Scope *S, Decl *Method); void ActOnFinishDelayedMemberInitializers(Decl *Record); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, CachedTokens &Toks); void UnmarkAsLateParsedTemplate(FunctionDecl *FD); bool IsInsideALocalClassWithinATemplateFunction(); Decl *ActOnStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, Expr *AssertMessageExpr, SourceLocation RParenLoc); Decl *BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, Expr *AssertExpr, StringLiteral *AssertMessageExpr, SourceLocation RParenLoc, bool Failed); FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo); Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, MultiTemplateParamsArg TemplateParams); NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D, MultiTemplateParamsArg TemplateParams); QualType CheckConstructorDeclarator(Declarator &D, QualType R, StorageClass& SC); void CheckConstructor(CXXConstructorDecl *Constructor); QualType CheckDestructorDeclarator(Declarator &D, QualType R, StorageClass& SC); bool CheckDestructor(CXXDestructorDecl *Destructor); void CheckConversionDeclarator(Declarator &D, QualType &R, StorageClass& SC); Decl *ActOnConversionDeclarator(CXXConversionDecl *Conversion); void CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD); void CheckExplicitlyDefaultedMemberExceptionSpec(CXXMethodDecl *MD, const FunctionProtoType *T); void CheckDelayedMemberExceptionSpecs(); //===--------------------------------------------------------------------===// // C++ Derived Classes // /// ActOnBaseSpecifier - Parsed a base specifier CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, ParsedAttributes &Attrs, bool Virtual, AccessSpecifier Access, ParsedType basetype, SourceLocation BaseLoc, SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, MutableArrayRef Bases); void ActOnBaseSpecifiers(Decl *ClassDecl, MutableArrayRef Bases); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base); bool IsDerivedFrom(SourceLocation Loc, QualType Derived, QualType Base, CXXBasePaths &Paths); // FIXME: I don't like this name. void BuildBasePathArray(const CXXBasePaths &Paths, CXXCastPath &BasePath); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, SourceLocation Loc, SourceRange Range, CXXCastPath *BasePath = nullptr, bool IgnoreAccess = false); bool CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, unsigned AmbigiousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, bool IgnoreAccess = false); std::string getAmbiguousPathsDisplayString(CXXBasePaths &Paths); bool CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionReturnType - Checks whether the return types are /// covariant, according to C++ [class.virtual]p5. bool CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old); /// CheckOverridingFunctionExceptionSpec - Checks whether the exception /// spec is a subset of base spec. bool CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, const CXXMethodDecl *Old); bool CheckPureMethod(CXXMethodDecl *Method, SourceRange InitRange); /// CheckOverrideControl - Check C++11 override control semantics. void CheckOverrideControl(NamedDecl *D); /// DiagnoseAbsenceOfOverrideControl - Diagnose if 'override' keyword was /// not used in the declaration of an overriding method. void DiagnoseAbsenceOfOverrideControl(NamedDecl *D); /// CheckForFunctionMarkedFinal - Checks whether a virtual member function /// overrides a virtual member function marked 'final', according to /// C++11 [class.virtual]p4. bool CheckIfOverriddenFunctionIsMarkedFinal(const CXXMethodDecl *New, const CXXMethodDecl *Old); //===--------------------------------------------------------------------===// // C++ Access Control // enum AccessResult { AR_accessible, AR_inaccessible, AR_dependent, AR_delayed }; bool SetMemberAccessSpecifier(NamedDecl *MemberDecl, NamedDecl *PrevMemberDecl, AccessSpecifier LexicalAS); AccessResult CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, DeclAccessPair FoundDecl); AccessResult CheckUnresolvedLookupAccess(UnresolvedLookupExpr *E, DeclAccessPair FoundDecl); AccessResult CheckAllocationAccess(SourceLocation OperatorLoc, SourceRange PlacementRange, CXXRecordDecl *NamingClass, DeclAccessPair FoundDecl, bool Diagnose = true); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, bool IsCopyBindingRefToTemp = false); AccessResult CheckConstructorAccess(SourceLocation Loc, CXXConstructorDecl *D, DeclAccessPair FoundDecl, const InitializedEntity &Entity, const PartialDiagnostic &PDiag); AccessResult CheckDestructorAccess(SourceLocation Loc, CXXDestructorDecl *Dtor, const PartialDiagnostic &PDiag, QualType objectType = QualType()); AccessResult CheckFriendAccess(NamedDecl *D); AccessResult CheckMemberAccess(SourceLocation UseLoc, CXXRecordDecl *NamingClass, DeclAccessPair Found); AccessResult CheckMemberOperatorAccess(SourceLocation Loc, Expr *ObjectExpr, Expr *ArgExpr, DeclAccessPair FoundDecl); AccessResult CheckAddressOfMemberAccess(Expr *OvlExpr, DeclAccessPair FoundDecl); AccessResult CheckBaseClassAccess(SourceLocation AccessLoc, QualType Base, QualType Derived, const CXXBasePath &Path, unsigned DiagID, bool ForceCheck = false, bool ForceUnprivileged = false); void CheckLookupAccess(const LookupResult &R); bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx); bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, AccessSpecifier access, QualType objectType); void HandleDependentAccessCheck(const DependentDiagnostic &DD, const MultiLevelTemplateArgumentList &TemplateArgs); void PerformDependentDiagnostics(const DeclContext *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); void HandleDelayedAccessCheck(sema::DelayedDiagnostic &DD, Decl *Ctx); /// \brief When true, access checking violations are treated as SFINAE /// failures rather than hard errors. bool AccessCheckingSFINAE; enum AbstractDiagSelID { AbstractNone = -1, AbstractReturnType, AbstractParamType, AbstractVariableType, AbstractFieldType, AbstractIvarType, AbstractSynthesizedIvarType, AbstractArrayType }; bool isAbstractType(SourceLocation Loc, QualType T); bool RequireNonAbstractType(SourceLocation Loc, QualType T, TypeDiagnoser &Diagnoser); template bool RequireNonAbstractType(SourceLocation Loc, QualType T, unsigned DiagID, const Ts &...Args) { BoundTypeDiagnoser Diagnoser(DiagID, Args...); return RequireNonAbstractType(Loc, T, Diagnoser); } void DiagnoseAbstractType(const CXXRecordDecl *RD); //===--------------------------------------------------------------------===// // C++ Overloaded Operators [C++ 13.5] // bool CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl); bool CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl); //===--------------------------------------------------------------------===// // C++ Templates [C++ 14] // void FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); bool hasAnyAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates = true); void LookupTemplateName(LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization); TemplateNameKind isTemplateName(Scope *S, CXXScopeSpec &SS, bool hasTemplateKeyword, UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template, bool &MemberOfUnknownSpecialization); bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, SourceLocation IILoc, Scope *S, const CXXScopeSpec *SS, TemplateTy &SuggestedTemplate, TemplateNameKind &SuggestedKind); void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl); TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl); Decl *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation EllipsisLoc, SourceLocation KeyLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedType DefaultArg); QualType CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc); Decl *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position, SourceLocation EqualLoc, Expr *DefaultArg); Decl *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); TemplateParameterList * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef Params, SourceLocation RAngleLoc, Expr *RequiresClause); /// \brief The context in which we are checking a template parameter list. enum TemplateParamListContext { TPC_ClassTemplate, TPC_VarTemplate, TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendClassTemplate, TPC_FriendFunctionTemplate, TPC_FriendFunctionTemplateDefinition, TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, TemplateParameterList *OldParams, TemplateParamListContext TPC); TemplateParameterList *MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef ParamLists, bool IsFriend, bool &IsExplicitSpecialization, bool &Invalid); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr, TemplateParameterList *TemplateParams, AccessSpecifier AS, SourceLocation ModulePrivateLoc, SourceLocation FriendLoc, unsigned NumOuterTemplateParamLists, TemplateParameterList **OuterTemplateParamLists, SkipBodyInfo *SkipBody = nullptr); void translateTemplateArguments(const ASTTemplateArgsPtr &In, TemplateArgumentListInfo &Out); void NoteAllFoundTemplates(TemplateName Name); QualType CheckTemplateIdType(TemplateName Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs); TypeResult ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false); /// \brief Parsed an elaborated-type-specifier that refers to a template-id, /// such as \c class T::template apply. TypeResult ActOnTagTemplateIdType(TagUseKind TUK, TypeSpecifierType TagSpec, SourceLocation TagLoc, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, TemplateTy TemplateD, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc); DeclResult ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, bool IsPartialSpecialization); DeclResult CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation TemplateNameLoc, const TemplateArgumentListInfo &TemplateArgs); ExprResult CheckVarTemplateId(const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, VarTemplateDecl *Template, SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, bool RequiresADL, const TemplateArgumentListInfo *TemplateArgs); ExprResult BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, const TemplateArgumentListInfo *TemplateArgs); TemplateNameKind ActOnDependentTemplateName(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &Name, ParsedType ObjectType, bool EnteringContext, TemplateTy &Template); DeclResult ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody = nullptr); Decl *ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D); bool CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, TemplateSpecializationKind NewTSK, NamedDecl *PrevDecl, TemplateSpecializationKind PrevTSK, SourceLocation PrevPtOfInstantiation, bool &SuppressNew); bool CheckDependentFunctionTemplateSpecialization(FunctionDecl *FD, const TemplateArgumentListInfo &ExplicitTemplateArgs, LookupResult &Previous); bool CheckFunctionTemplateSpecialization(FunctionDecl *FD, TemplateArgumentListInfo *ExplicitTemplateArgs, LookupResult &Previous); bool CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, const CXXScopeSpec &SS, TemplateTy Template, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, AttributeList *Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, unsigned TagSpec, SourceLocation KWLoc, CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, AttributeList *Attr); DeclResult ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, SourceLocation TemplateLoc, Declarator &D); TemplateArgumentLoc SubstDefaultTemplateArgumentIfAvailable(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, Decl *Param, SmallVectorImpl &Converted, bool &HasDefaultArg); /// \brief Specifies the context in which a particular template /// argument is being checked. enum CheckTemplateArgumentKind { /// \brief The template argument was specified in the code or was /// instantiated with some deduced template arguments. CTAK_Specified, /// \brief The template argument was deduced via template argument /// deduction. CTAK_Deduced, /// \brief The template argument was deduced from an array bound /// via template argument deduction. CTAK_DeducedFromArrayBound }; bool CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &Arg, NamedDecl *Template, SourceLocation TemplateLoc, SourceLocation RAngleLoc, unsigned ArgumentPackIndex, SmallVectorImpl &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); /// \brief Check that the given template arguments can be be provided to /// the given template, converting the arguments along the way. /// /// \param Template The template to which the template arguments are being /// provided. /// /// \param TemplateLoc The location of the template name in the source. /// /// \param TemplateArgs The list of template arguments. If the template is /// a template template parameter, this function may extend the set of /// template arguments to also include substituted, defaulted template /// arguments. /// /// \param PartialTemplateArgs True if the list of template arguments is /// intentionally partial, e.g., because we're checking just the initial /// set of template arguments. /// /// \param Converted Will receive the converted, canonicalized template /// arguments. /// /// \returns true if an error occurred, false otherwise. bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl &Converted); bool CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg, SmallVectorImpl &Converted); bool CheckTemplateArgument(TemplateTypeParmDecl *Param, TypeSourceInfo *Arg); ExprResult CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *Arg, TemplateArgument &Converted, CheckTemplateArgumentKind CTAK = CTAK_Specified); bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, TemplateArgumentLoc &Arg, unsigned ArgumentPackIndex); ExprResult BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc); ExprResult BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, SourceLocation Loc); /// \brief Enumeration describing how template parameter lists are compared /// for equality. enum TemplateParameterListEqualKind { /// \brief We are matching the template parameter lists of two templates /// that might be redeclarations. /// /// \code /// template struct X; /// template struct X; /// \endcode TPL_TemplateMatch, /// \brief We are matching the template parameter lists of two template /// template parameters as part of matching the template parameter lists /// of two templates that might be redeclarations. /// /// \code /// template class TT> struct X; /// template class Other> struct X; /// \endcode TPL_TemplateTemplateParmMatch, /// \brief We are matching the template parameter lists of a template /// template argument against the template parameter lists of a template /// template parameter. /// /// \code /// template class Metafun> struct X; /// template struct integer_c; /// X xic; /// \endcode TPL_TemplateTemplateArgumentMatch }; bool TemplateParameterListsAreEqual(TemplateParameterList *New, TemplateParameterList *Old, bool Complain, TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc = SourceLocation()); bool CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams); /// \brief Called when the parser has parsed a C++ typename /// specifier, e.g., "typename T::type". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param II the identifier we're retrieving (e.g., 'type' in the example). /// \param IdLoc the location of the identifier. TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc); /// \brief Called when the parser has parsed a C++ typename /// specifier that ends in a template-id, e.g., /// "typename MetaFun::template apply". /// /// \param S The scope in which this typename type occurs. /// \param TypenameLoc the location of the 'typename' keyword /// \param SS the nested-name-specifier following the typename (e.g., 'T::'). /// \param TemplateLoc the location of the 'template' keyword, if any. /// \param TemplateName The template name. /// \param TemplateNameLoc The location of the template name. /// \param LAngleLoc The location of the opening angle bracket ('<'). /// \param TemplateArgs The template arguments. /// \param RAngleLoc The location of the closing angle bracket ('>'). TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, TemplateTy TemplateName, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); QualType CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc); TypeSourceInfo *RebuildTypeInCurrentInstantiation(TypeSourceInfo *T, SourceLocation Loc, DeclarationName Name); bool RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS); ExprResult RebuildExprInCurrentInstantiation(Expr *E); bool RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgumentList &Args); std::string getTemplateArgumentBindingsText(const TemplateParameterList *Params, const TemplateArgument *Args, unsigned NumArgs); //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// /// Determine whether an unexpanded parameter pack might be permitted in this /// location. Useful for error recovery. bool isUnexpandedParameterPackPermitted(); /// \brief The context in which an unexpanded parameter pack is /// being diagnosed. /// /// Note that the values of this enumeration line up with the first /// argument to the \c err_unexpanded_parameter_pack diagnostic. enum UnexpandedParameterPackContext { /// \brief An arbitrary expression. UPPC_Expression = 0, /// \brief The base type of a class type. UPPC_BaseType, /// \brief The type of an arbitrary declaration. UPPC_DeclarationType, /// \brief The type of a data member. UPPC_DataMemberType, /// \brief The size of a bit-field. UPPC_BitFieldWidth, /// \brief The expression in a static assertion. UPPC_StaticAssertExpression, /// \brief The fixed underlying type of an enumeration. UPPC_FixedUnderlyingType, /// \brief The enumerator value. UPPC_EnumeratorValue, /// \brief A using declaration. UPPC_UsingDeclaration, /// \brief A friend declaration. UPPC_FriendDeclaration, /// \brief A declaration qualifier. UPPC_DeclarationQualifier, /// \brief An initializer. UPPC_Initializer, /// \brief A default argument. UPPC_DefaultArgument, /// \brief The type of a non-type template parameter. UPPC_NonTypeTemplateParameterType, /// \brief The type of an exception. UPPC_ExceptionType, /// \brief Partial specialization. UPPC_PartialSpecialization, /// \brief Microsoft __if_exists. UPPC_IfExists, /// \brief Microsoft __if_not_exists. UPPC_IfNotExists, /// \brief Lambda expression. UPPC_Lambda, /// \brief Block expression, UPPC_Block }; /// \brief Diagnose unexpanded parameter packs. /// /// \param Loc The location at which we should emit the diagnostic. /// /// \param UPPC The context in which we are diagnosing unexpanded /// parameter packs. /// /// \param Unexpanded the set of unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc, UnexpandedParameterPackContext UPPC, ArrayRef Unexpanded); /// \brief If the given type contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The source location where a diagnostc should be emitted. /// /// \param T The type that is being checked for unexpanded parameter /// packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TypeSourceInfo *T, UnexpandedParameterPackContext UPPC); /// \brief If the given expression contains an unexpanded parameter /// pack, diagnose the error. /// /// \param E The expression that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(Expr *E, UnexpandedParameterPackContext UPPC = UPPC_Expression); /// \brief If the given nested-name-specifier contains an unexpanded /// parameter pack, diagnose the error. /// /// \param SS The nested-name-specifier that is being checked for /// unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS, UnexpandedParameterPackContext UPPC); /// \brief If the given name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param NameInfo The name (with source location information) that /// is being checked for unexpanded parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo, UnexpandedParameterPackContext UPPC); /// \brief If the given template name contains an unexpanded parameter pack, /// diagnose the error. /// /// \param Loc The location of the template name. /// /// \param Template The template name that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(SourceLocation Loc, TemplateName Template, UnexpandedParameterPackContext UPPC); /// \brief If the given template argument contains an unexpanded parameter /// pack, diagnose the error. /// /// \param Arg The template argument that is being checked for unexpanded /// parameter packs. /// /// \returns true if an error occurred, false otherwise. bool DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg, UnexpandedParameterPackContext UPPC); /// \brief Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgument Arg, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// template argument. /// /// \param Arg The template argument that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// type. /// /// \param T The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(QualType T, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// type. /// /// \param TL The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// nested-name-specifier. /// /// \param SS The nested-name-specifier that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(CXXScopeSpec &SS, SmallVectorImpl &Unexpanded); /// \brief Collect the set of unexpanded parameter packs within the given /// name. /// /// \param NameInfo The name that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, SmallVectorImpl &Unexpanded); /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// /// \param Arg The template argument preceding the ellipsis, which /// may already be invalid. /// /// \param EllipsisLoc The location of the ellipsis. ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc); /// \brief Invoked when parsing a type followed by an ellipsis, which /// creates a pack expansion. /// /// \param Type The type preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); /// \brief Construct a pack expansion type from the pattern of the pack /// expansion. TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Construct a pack expansion type from the pattern of the pack /// expansion. QualType CheckPackExpansion(QualType Pattern, SourceRange PatternRange, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc); /// \brief Invoked when parsing an expression followed by an ellipsis, which /// creates a pack expansion. /// /// \param Pattern The expression preceding the ellipsis, which will become /// the pattern of the pack expansion. /// /// \param EllipsisLoc The location of the ellipsis. ExprResult CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc, Optional NumExpansions); /// \brief Determine whether we could expand a pack expansion with the /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// /// \param EllipsisLoc The location of the ellipsis that identifies the /// pack expansion. /// /// \param PatternRange The source range that covers the entire pattern of /// the pack expansion. /// /// \param Unexpanded The set of unexpanded parameter packs within the /// pattern. /// /// \param ShouldExpand Will be set to \c true if the transformer should /// expand the corresponding pack expansions into separate arguments. When /// set, \c NumExpansions must also be set. /// /// \param RetainExpansion Whether the caller should add an unexpanded /// pack expansion after all of the expanded arguments. This is used /// when extending explicitly-specified template argument packs per /// C++0x [temp.arg.explicit]p9. /// /// \param NumExpansions The number of separate arguments that will be in /// the expanded form of the corresponding pack expansion. This is both an /// input and an output parameter, which can be set by the caller if the /// number of expansions is known a priori (e.g., due to a prior substitution) /// and will be set by the callee when the number of expansions is known. /// The callee must set this value when \c ShouldExpand is \c true; it may /// set this value in other cases. /// /// \returns true if an error occurred (e.g., because the parameter packs /// are to be instantiated with arguments of different lengths), false /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) /// must be set. bool CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef Unexpanded, const MultiLevelTemplateArgumentList &TemplateArgs, bool &ShouldExpand, bool &RetainExpansion, Optional &NumExpansions); /// \brief Determine the number of arguments in the given pack expansion /// type. /// /// This routine assumes that the number of arguments in the expansion is /// consistent across all of the unexpanded parameter packs in its pattern. /// /// Returns an empty Optional if the type can't be expanded. Optional getNumArgumentsInExpansion(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs); /// \brief Determine whether the given declarator contains any unexpanded /// parameter packs. /// /// This routine is used by the parser to disambiguate function declarators /// with an ellipsis prior to the ')', e.g., /// /// \code /// void f(T...); /// \endcode /// /// To determine whether we have an (unnamed) function parameter pack or /// a variadic function. /// /// \returns true if the declarator contains any unexpanded parameter packs, /// false otherwise. bool containsUnexpandedParameterPacks(Declarator &D); /// \brief Returns the pattern of the pack expansion for a template argument. /// /// \param OrigLoc The template argument to expand. /// /// \param Ellipsis Will be set to the location of the ellipsis. /// /// \param NumExpansions Will be set to the number of expansions that will /// be generated from this pack expansion, if known a priori. TemplateArgumentLoc getTemplateArgumentPackExpansionPattern( TemplateArgumentLoc OrigLoc, SourceLocation &Ellipsis, Optional &NumExpansions) const; //===--------------------------------------------------------------------===// // C++ Template Argument Deduction (C++ [temp.deduct]) //===--------------------------------------------------------------------===// QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType); /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of /// template argument deduction, as returned from /// DeduceTemplateArguments(). The separate TemplateDeductionInfo /// structure provides additional information about the results of /// template argument deduction, e.g., the deduced template argument /// list (if successful) or the specific template parameters or /// deduced arguments that were involved in the failure. enum TemplateDeductionResult { /// \brief Template argument deduction was successful. TDK_Success = 0, /// \brief The declaration was invalid; do nothing. TDK_Invalid, /// \brief Template argument deduction exceeded the maximum template /// instantiation depth (which has already been diagnosed). TDK_InstantiationDepth, /// \brief Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, /// \brief Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, /// \brief Template argument deduction failed due to inconsistent /// cv-qualifiers on a template parameter type that would /// otherwise be deduced, e.g., we tried to deduce T in "const T" /// but were given a non-const "X". TDK_Underqualified, /// \brief Substitution of the deduced template argument values /// resulted in an error. TDK_SubstitutionFailure, /// \brief After substituting deduced template arguments, a dependent /// parameter type did not match the corresponding argument. TDK_DeducedMismatch, /// \brief A non-depnedent component of the parameter did not match the /// corresponding component of the argument. TDK_NonDeducedMismatch, /// \brief When performing template argument deduction for a function /// template, there were too many call arguments. TDK_TooManyArguments, /// \brief When performing template argument deduction for a function /// template, there were too few call arguments. TDK_TooFewArguments, /// \brief The explicitly-specified template arguments were not valid /// template arguments for the given template. TDK_InvalidExplicitArguments, /// \brief The arguments included an overloaded function name that could /// not be resolved to a suitable function. TDK_FailedOverloadResolution, /// \brief Deduction failed; that's all we know. TDK_MiscellaneousDeductionFailure }; TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, sema::TemplateDeductionInfo &Info); TemplateDeductionResult SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, SmallVectorImpl &Deduced, SmallVectorImpl &ParamTypes, QualType *FunctionType, sema::TemplateDeductionInfo &Info); /// brief A function argument from which we performed template argument // deduction for a call. struct OriginalCallArg { OriginalCallArg(QualType OriginalParamType, unsigned ArgIdx, QualType OriginalArgType) : OriginalParamType(OriginalParamType), ArgIdx(ArgIdx), OriginalArgType(OriginalArgType) { } QualType OriginalParamType; unsigned ArgIdx; QualType OriginalArgType; }; TemplateDeductionResult FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, SmallVectorImpl const *OriginalCallArgs = nullptr, bool PartialOverloading = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool PartialOverloading = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool InOverloadResolution = false); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, sema::TemplateDeductionInfo &Info); TemplateDeductionResult DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, FunctionDecl *&Specialization, sema::TemplateDeductionInfo &Info, bool InOverloadResolution = false); /// \brief Substitute Replacement for \p auto in \p TypeWithAuto QualType SubstAutoType(QualType TypeWithAuto, QualType Replacement); /// \brief Substitute Replacement for auto in TypeWithAuto TypeSourceInfo* SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType Replacement); /// \brief Result type of DeduceAutoType. enum DeduceAutoResult { DAR_Succeeded, DAR_Failed, DAR_FailedAlreadyDiagnosed }; DeduceAutoResult DeduceAutoType(TypeSourceInfo *AutoType, Expr *&Initializer, QualType &Result); DeduceAutoResult DeduceAutoType(TypeLoc AutoTypeLoc, Expr *&Initializer, QualType &Result); void DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init); bool DeduceReturnType(FunctionDecl *FD, SourceLocation Loc, bool Diagnose = true); QualType deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, SourceRange Range, bool DirectInit, Expr *Init); TypeLoc getReturnTypeLoc(FunctionDecl *FD) const; bool DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, SourceLocation Loc, const PartialDiagnostic &NoneDiag, const PartialDiagnostic &AmbigDiag, const PartialDiagnostic &CandidateDiag, bool Complain = true, QualType TargetType = QualType()); ClassTemplatePartialSpecializationDecl * getMoreSpecializedPartialSpecialization( ClassTemplatePartialSpecializationDecl *PS1, ClassTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc); void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used); void MarkDeducedTemplateParameters( const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced) { return MarkDeducedTemplateParameters(Context, FunctionTemplate, Deduced); } static void MarkDeducedTemplateParameters(ASTContext &Ctx, const FunctionTemplateDecl *FunctionTemplate, llvm::SmallBitVector &Deduced); //===--------------------------------------------------------------------===// // C++ Template Instantiation // MultiLevelTemplateArgumentList getTemplateInstantiationArgs(NamedDecl *D, const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr); /// \brief A template instantiation that is currently in progress. struct ActiveTemplateInstantiation { /// \brief The kind of template instantiation we are performing enum InstantiationKind { /// We are instantiating a template declaration. The entity is /// the declaration we're instantiating (e.g., a CXXRecordDecl). TemplateInstantiation, /// We are instantiating a default argument for a template /// parameter. The Entity is the template parameter whose argument is /// being instantiated, the Template is the template, and the /// TemplateArgs/NumTemplateArguments provide the template arguments as /// specified. DefaultTemplateArgumentInstantiation, /// We are instantiating a default argument for a function. /// The Entity is the ParmVarDecl, and TemplateArgs/NumTemplateArgs /// provides the template arguments as specified. DefaultFunctionArgumentInstantiation, /// We are substituting explicit template arguments provided for /// a function template. The entity is a FunctionTemplateDecl. ExplicitTemplateArgumentSubstitution, /// We are substituting template argument determined as part of /// template argument deduction for either a class template /// partial specialization or a function template. The /// Entity is either a ClassTemplatePartialSpecializationDecl or /// a FunctionTemplateDecl. DeducedTemplateArgumentSubstitution, /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. PriorTemplateArgumentSubstitution, /// We are checking the validity of a default template argument that /// has been used when naming a template-id. DefaultTemplateArgumentChecking, /// We are instantiating the exception specification for a function /// template which was deferred until it was needed. ExceptionSpecInstantiation } Kind; /// \brief The point of instantiation within the source code. SourceLocation PointOfInstantiation; /// \brief The template (or partial specialization) in which we are /// performing the instantiation, for substitutions of prior template /// arguments. NamedDecl *Template; /// \brief The entity that is being instantiated. Decl *Entity; /// \brief The list of template arguments we are substituting, if they /// are not part of the entity. const TemplateArgument *TemplateArgs; /// \brief The number of template arguments in TemplateArgs. unsigned NumTemplateArgs; ArrayRef template_arguments() const { return {TemplateArgs, NumTemplateArgs}; } /// \brief The template deduction info object associated with the /// substitution or checking of explicit or deduced template arguments. sema::TemplateDeductionInfo *DeductionInfo; /// \brief The source range that covers the construct that cause /// the instantiation, e.g., the template-id that causes a class /// template instantiation. SourceRange InstantiationRange; ActiveTemplateInstantiation() : Kind(TemplateInstantiation), Template(nullptr), Entity(nullptr), TemplateArgs(nullptr), NumTemplateArgs(0), DeductionInfo(nullptr) {} /// \brief Determines whether this template is an actual instantiation /// that should be counted toward the maximum instantiation depth. bool isInstantiationRecord() const; friend bool operator==(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { if (X.Kind != Y.Kind) return false; if (X.Entity != Y.Entity) return false; switch (X.Kind) { case TemplateInstantiation: case ExceptionSpecInstantiation: return true; case PriorTemplateArgumentSubstitution: case DefaultTemplateArgumentChecking: return X.Template == Y.Template && X.TemplateArgs == Y.TemplateArgs; case DefaultTemplateArgumentInstantiation: case ExplicitTemplateArgumentSubstitution: case DeducedTemplateArgumentSubstitution: case DefaultFunctionArgumentInstantiation: return X.TemplateArgs == Y.TemplateArgs; } llvm_unreachable("Invalid InstantiationKind!"); } friend bool operator!=(const ActiveTemplateInstantiation &X, const ActiveTemplateInstantiation &Y) { return !(X == Y); } }; /// \brief List of active template instantiations. /// /// This vector is treated as a stack. As one template instantiation /// requires another template instantiation, additional /// instantiations are pushed onto the stack up to a /// user-configurable limit LangOptions::InstantiationDepth. SmallVector ActiveTemplateInstantiations; /// Specializations whose definitions are currently being instantiated. llvm::DenseSet> InstantiatingSpecializations; /// \brief Extra modules inspected when performing a lookup during a template /// instantiation. Computed lazily. SmallVector ActiveTemplateInstantiationLookupModules; /// \brief Cache of additional modules that should be used for name lookup /// within the current template instantiation. Computed lazily; use /// getLookupModules() to get a complete set. llvm::DenseSet LookupModulesCache; /// \brief Get the set of additional modules that should be checked during /// name lookup. A module and its imports become visible when instanting a /// template defined within it. llvm::DenseSet &getLookupModules(); /// \brief Map from the most recent declaration of a namespace to the most /// recent visible declaration of that namespace. llvm::DenseMap VisibleNamespaceCache; /// \brief Whether we are in a SFINAE context that is not associated with /// template instantiation. /// /// This is used when setting up a SFINAE trap (\c see SFINAETrap) outside /// of a template instantiation or template argument deduction. bool InNonInstantiationSFINAEContext; /// \brief The number of ActiveTemplateInstantiation entries in /// \c ActiveTemplateInstantiations that are not actual instantiations and, /// therefore, should not be counted as part of the instantiation depth. unsigned NonInstantiationEntries; /// \brief The last template from which a template instantiation /// error or warning was produced. /// /// This value is used to suppress printing of redundant template /// instantiation backtraces when there are multiple errors in the /// same instantiation. FIXME: Does this belong in Sema? It's tough /// to implement it anywhere else. ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; /// \brief The current index into pack expansion arguments that will be /// used for substitution of parameter packs. /// /// The pack expansion index will be -1 to indicate that parameter packs /// should be instantiated as themselves. Otherwise, the index specifies /// which argument within the parameter pack will be used for substitution. int ArgumentPackSubstitutionIndex; /// \brief RAII object used to change the argument pack substitution index /// within a \c Sema object. /// /// See \c ArgumentPackSubstitutionIndex for more information. class ArgumentPackSubstitutionIndexRAII { Sema &Self; int OldSubstitutionIndex; public: ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; } ~ArgumentPackSubstitutionIndexRAII() { Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; } }; friend class ArgumentPackSubstitutionRAII; /// \brief For each declaration that involved template argument deduction, the /// set of diagnostics that were suppressed during that template argument /// deduction. /// /// FIXME: Serialize this structure to the AST file. typedef llvm::DenseMap > SuppressedDiagnosticsMap; SuppressedDiagnosticsMap SuppressedDiagnostics; /// \brief A stack object to be created when performing template /// instantiation. /// /// Construction of an object of type \c InstantiatingTemplate /// pushes the current instantiation onto the stack of active /// instantiations. If the size of this stack exceeds the maximum /// number of recursive template instantiations, construction /// produces an error and evaluates true. /// /// Destruction of this object will pop the named instantiation off /// the stack. struct InstantiatingTemplate { /// \brief Note that we are instantiating a class template, /// function template, variable template, alias template, /// or a member thereof. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, Decl *Entity, SourceRange InstantiationRange = SourceRange()); struct ExceptionSpecification {}; /// \brief Note that we are instantiating an exception specification /// of a function template. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, TemplateDecl *Template, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are substituting either explicitly-specified or /// deduced template arguments during function template argument deduction. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, FunctionTemplateDecl *FunctionTemplate, ArrayRef TemplateArgs, ActiveTemplateInstantiation::InstantiationKind Kind, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template /// argument deduction for a class template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating as part of template /// argument deduction for a variable template partial /// specialization. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, VarTemplatePartialSpecializationDecl *PartialSpec, ArrayRef TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are instantiating a default argument for a function /// parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, ParmVarDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); /// \brief Note that we are substituting prior template arguments into a /// non-type parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, NonTypeTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we are substituting prior template arguments into a /// template template parameter. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, NamedDecl *Template, TemplateTemplateParmDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we are checking the default template argument /// against the template parameter for a given template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, NamedDecl *Param, ArrayRef TemplateArgs, SourceRange InstantiationRange); /// \brief Note that we have finished instantiating this template. void Clear(); ~InstantiatingTemplate() { Clear(); } /// \brief Determines whether we have exceeded the maximum /// recursive template instantiations. bool isInvalid() const { return Invalid; } /// \brief Determine whether we are already instantiating this /// specialization in some surrounding active instantiation. bool isAlreadyInstantiating() const { return AlreadyInstantiating; } private: Sema &SemaRef; bool Invalid; bool AlreadyInstantiating; bool SavedInNonInstantiationSFINAEContext; bool CheckInstantiationDepth(SourceLocation PointOfInstantiation, SourceRange InstantiationRange); InstantiatingTemplate( Sema &SemaRef, ActiveTemplateInstantiation::InstantiationKind Kind, SourceLocation PointOfInstantiation, SourceRange InstantiationRange, Decl *Entity, NamedDecl *Template = nullptr, ArrayRef TemplateArgs = None, sema::TemplateDeductionInfo *DeductionInfo = nullptr); InstantiatingTemplate(const InstantiatingTemplate&) = delete; InstantiatingTemplate& operator=(const InstantiatingTemplate&) = delete; }; void PrintInstantiationStack(); /// \brief Determines whether we are currently in a context where /// template argument substitution failures are not considered /// errors. /// /// \returns An empty \c Optional if we're not in a SFINAE context. /// Otherwise, contains a pointer that, if non-NULL, contains the nearest /// template-deduction context object, which can be used to capture /// diagnostics that will be suppressed. Optional isSFINAEContext() const; /// \brief Determines whether we are currently in a context that /// is not evaluated as per C++ [expr] p5. bool isUnevaluatedContext() const { assert(!ExprEvalContexts.empty() && "Must be in an expression evaluation context"); return ExprEvalContexts.back().isUnevaluated(); } /// \brief RAII class used to determine whether SFINAE has /// trapped any errors that occur during template argument /// deduction. class SFINAETrap { Sema &SemaRef; unsigned PrevSFINAEErrors; bool PrevInNonInstantiationSFINAEContext; bool PrevAccessCheckingSFINAE; public: explicit SFINAETrap(Sema &SemaRef, bool AccessCheckingSFINAE = false) : SemaRef(SemaRef), PrevSFINAEErrors(SemaRef.NumSFINAEErrors), PrevInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext), PrevAccessCheckingSFINAE(SemaRef.AccessCheckingSFINAE) { if (!SemaRef.isSFINAEContext()) SemaRef.InNonInstantiationSFINAEContext = true; SemaRef.AccessCheckingSFINAE = AccessCheckingSFINAE; } ~SFINAETrap() { SemaRef.NumSFINAEErrors = PrevSFINAEErrors; SemaRef.InNonInstantiationSFINAEContext = PrevInNonInstantiationSFINAEContext; SemaRef.AccessCheckingSFINAE = PrevAccessCheckingSFINAE; } /// \brief Determine whether any SFINAE errors have been trapped. bool hasErrorOccurred() const { return SemaRef.NumSFINAEErrors > PrevSFINAEErrors; } }; /// \brief RAII class used to indicate that we are performing provisional /// semantic analysis to determine the validity of a construct, so /// typo-correction and diagnostics in the immediate context (not within /// implicitly-instantiated templates) should be suppressed. class TentativeAnalysisScope { Sema &SemaRef; // FIXME: Using a SFINAETrap for this is a hack. SFINAETrap Trap; bool PrevDisableTypoCorrection; public: explicit TentativeAnalysisScope(Sema &SemaRef) : SemaRef(SemaRef), Trap(SemaRef, true), PrevDisableTypoCorrection(SemaRef.DisableTypoCorrection) { SemaRef.DisableTypoCorrection = true; } ~TentativeAnalysisScope() { SemaRef.DisableTypoCorrection = PrevDisableTypoCorrection; } }; /// \brief The current instantiation scope used to store local /// variables. LocalInstantiationScope *CurrentInstantiationScope; /// \brief Tracks whether we are in a context where typo correction is /// disabled. bool DisableTypoCorrection; /// \brief The number of typos corrected by CorrectTypo. unsigned TyposCorrected; typedef llvm::SmallSet SrcLocSet; typedef llvm::DenseMap IdentifierSourceLocations; /// \brief A cache containing identifiers for which typo correction failed and /// their locations, so that repeated attempts to correct an identifier in a /// given location are ignored if typo correction already failed for it. IdentifierSourceLocations TypoCorrectionFailures; /// \brief Worker object for performing CFG-based warnings. sema::AnalysisBasedWarnings AnalysisWarnings; threadSafety::BeforeSet *ThreadSafetyDeclCache; /// \brief An entity for which implicit template instantiation is required. /// /// The source location associated with the declaration is the first place in /// the source code where the declaration was "used". It is not necessarily /// the point of instantiation (which will be either before or after the /// namespace-scope declaration that triggered this implicit instantiation), /// However, it is the location that diagnostics should generally refer to, /// because users will need to know what code triggered the instantiation. typedef std::pair PendingImplicitInstantiation; /// \brief The queue of implicit template instantiations that are required /// but have not yet been performed. std::deque PendingInstantiations; class SavePendingInstantiationsAndVTableUsesRAII { public: SavePendingInstantiationsAndVTableUsesRAII(Sema &S, bool Enabled) : S(S), Enabled(Enabled) { if (!Enabled) return; SavedPendingInstantiations.swap(S.PendingInstantiations); SavedVTableUses.swap(S.VTableUses); } ~SavePendingInstantiationsAndVTableUsesRAII() { if (!Enabled) return; // Restore the set of pending vtables. assert(S.VTableUses.empty() && "VTableUses should be empty before it is discarded."); S.VTableUses.swap(SavedVTableUses); // Restore the set of pending implicit instantiations. assert(S.PendingInstantiations.empty() && "PendingInstantiations should be empty before it is discarded."); S.PendingInstantiations.swap(SavedPendingInstantiations); } private: Sema &S; SmallVector SavedVTableUses; std::deque SavedPendingInstantiations; bool Enabled; }; /// \brief The queue of implicit template instantiations that are required /// and must be performed within the current local scope. /// /// This queue is only used for member functions of local classes in /// templates, which must be instantiated in the same scope as their /// enclosing function, so that they can reference function-local /// types, static variables, enumerators, etc. std::deque PendingLocalImplicitInstantiations; class SavePendingLocalImplicitInstantiationsRAII { public: SavePendingLocalImplicitInstantiationsRAII(Sema &S): S(S) { SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } ~SavePendingLocalImplicitInstantiationsRAII() { assert(S.PendingLocalImplicitInstantiations.empty() && "there shouldn't be any pending local implicit instantiations"); SavedPendingLocalImplicitInstantiations.swap( S.PendingLocalImplicitInstantiations); } private: Sema &S; std::deque SavedPendingLocalImplicitInstantiations; }; /// A helper class for building up ExtParameterInfos. class ExtParameterInfoBuilder { SmallVector Infos; bool HasInteresting = false; public: /// Set the ExtParameterInfo for the parameter at the given index, /// void set(unsigned index, FunctionProtoType::ExtParameterInfo info) { assert(Infos.size() <= index); Infos.resize(index); Infos.push_back(info); if (!HasInteresting) HasInteresting = (info != FunctionProtoType::ExtParameterInfo()); } /// Return a pointer (suitable for setting in an ExtProtoInfo) to the /// ExtParameterInfo array we've built up. const FunctionProtoType::ExtParameterInfo * getPointerOrNull(unsigned numParams) { if (!HasInteresting) return nullptr; Infos.resize(numParams); return Infos.data(); } }; void PerformPendingInstantiations(bool LocalOnly = false); TypeSourceInfo *SubstType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); QualType SubstType(QualType T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstType(TypeLoc TL, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity); TypeSourceInfo *SubstFunctionDeclType(TypeSourceInfo *T, const MultiLevelTemplateArgumentList &TemplateArgs, SourceLocation Loc, DeclarationName Entity, CXXRecordDecl *ThisContext, unsigned ThisTypeQuals); void SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, const MultiLevelTemplateArgumentList &Args); ParmVarDecl *SubstParmVarDecl(ParmVarDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, Optional NumExpansions, bool ExpectParameterPack); bool SubstParmTypes(SourceLocation Loc, ArrayRef Params, const FunctionProtoType::ExtParameterInfo *ExtParamInfos, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &ParamTypes, SmallVectorImpl *OutParams, ExtParameterInfoBuilder &ParamInfos); ExprResult SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs); /// \brief Substitute the given template arguments into a list of /// expressions, expanding pack expansions if required. /// /// \param Exprs The list of expressions to substitute into. /// /// \param IsCall Whether this is some form of call, in which case /// default arguments will be dropped. /// /// \param TemplateArgs The set of template arguments to substitute. /// /// \param Outputs Will receive all of the substituted arguments. /// /// \returns true if an error occurred, false otherwise. bool SubstExprs(ArrayRef Exprs, bool IsCall, const MultiLevelTemplateArgumentList &TemplateArgs, SmallVectorImpl &Outputs); StmtResult SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs); Decl *SubstDecl(Decl *D, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs); ExprResult SubstInitializer(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit); bool SubstBaseSpecifiers(CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateEnum(SourceLocation PointOfInstantiation, EnumDecl *Instantiation, EnumDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); bool InstantiateInClassInitializer( SourceLocation PointOfInstantiation, FieldDecl *Instantiation, FieldDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs); struct LateInstantiatedAttribute { const Attr *TmplAttr; LocalInstantiationScope *Scope; Decl *NewDecl; LateInstantiatedAttribute(const Attr *A, LocalInstantiationScope *S, Decl *D) : TmplAttr(A), Scope(S), NewDecl(D) { } }; typedef SmallVector LateInstantiatedAttrVec; void InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Pattern, Decl *Inst, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK, bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, TemplateSpecializationKind TSK); NestedNameSpecifierLoc SubstNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS, const MultiLevelTemplateArgumentList &TemplateArgs); DeclarationNameInfo SubstDeclarationNameInfo(const DeclarationNameInfo &NameInfo, const MultiLevelTemplateArgumentList &TemplateArgs); TemplateName SubstTemplateName(NestedNameSpecifierLoc QualifierLoc, TemplateName Name, SourceLocation Loc, const MultiLevelTemplateArgumentList &TemplateArgs); bool Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, TemplateArgumentListInfo &Result, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Function); void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); VarTemplateSpecializationDecl *BuildVarTemplateInstantiation( VarTemplateDecl *VarTemplate, VarDecl *FromVar, const TemplateArgumentList &TemplateArgList, const TemplateArgumentListInfo &TemplateArgsInfo, SmallVectorImpl &Converted, SourceLocation PointOfInstantiation, void *InsertPos, LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *StartingScope = nullptr); VarTemplateSpecializationDecl *CompleteVarTemplateSpecializationDecl( VarTemplateSpecializationDecl *VarSpec, VarDecl *PatternDecl, const MultiLevelTemplateArgumentList &TemplateArgs); void BuildVariableInstantiation(VarDecl *NewVar, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs, LateInstantiatedAttrVec *LateAttrs, DeclContext *Owner, LocalInstantiationScope *StartingScope, bool InstantiatingVarTemplate = false); void InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs); void InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false, bool AtEndOfTU = false); void InstantiateStaticDataMemberDefinition( SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive = false, bool DefinitionRequired = false); void InstantiateMemInitializers(CXXConstructorDecl *New, const CXXConstructorDecl *Tmpl, const MultiLevelTemplateArgumentList &TemplateArgs); NamedDecl *FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs); DeclContext *FindInstantiatedContext(SourceLocation Loc, DeclContext *DC, const MultiLevelTemplateArgumentList &TemplateArgs); // Objective-C declarations. enum ObjCContainerKind { OCK_None = -1, OCK_Interface = 0, OCK_Protocol, OCK_Category, OCK_ClassExtension, OCK_Implementation, OCK_CategoryImplementation }; ObjCContainerKind getObjCContainerKind() const; DeclResult actOnObjCTypeParam(Scope *S, ObjCTypeParamVariance variance, SourceLocation varianceLoc, unsigned index, IdentifierInfo *paramName, SourceLocation paramLoc, SourceLocation colonLoc, ParsedType typeBound); ObjCTypeParamList *actOnObjCTypeParamList(Scope *S, SourceLocation lAngleLoc, ArrayRef typeParams, SourceLocation rAngleLoc); void popObjCTypeParamList(Scope *S, ObjCTypeParamList *typeParamList); Decl *ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); void ActOnSuperClassOfClassInterface(Scope *S, SourceLocation AtInterfaceLoc, ObjCInterfaceDecl *IDecl, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperName, SourceLocation SuperLoc, ArrayRef SuperTypeArgs, SourceRange SuperTypeArgsRange); void ActOnTypedefedProtocols(SmallVectorImpl &ProtocolRefs, IdentifierInfo *SuperName, SourceLocation SuperLoc); Decl *ActOnCompatibilityAlias( SourceLocation AtCompatibilityAliasLoc, IdentifierInfo *AliasName, SourceLocation AliasLocation, IdentifierInfo *ClassName, SourceLocation ClassLocation); bool CheckForwardProtocolDeclarationForCircularDependency( IdentifierInfo *PName, SourceLocation &PLoc, SourceLocation PrevLoc, const ObjCList &PList); Decl *ActOnStartProtocolInterface( SourceLocation AtProtoInterfaceLoc, IdentifierInfo *ProtocolName, SourceLocation ProtocolLoc, Decl * const *ProtoRefNames, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, AttributeList *AttrList); Decl *ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl * const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc); Decl *ActOnStartClassImplementation( SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc); Decl *ActOnStartCategoryImplementation(SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); DeclGroupPtrTy ActOnForwardClassDeclaration(SourceLocation Loc, IdentifierInfo **IdentList, SourceLocation *IdentLocs, ArrayRef TypeParamLists, unsigned NumElts); DeclGroupPtrTy ActOnForwardProtocolDeclaration(SourceLocation AtProtoclLoc, ArrayRef IdentList, AttributeList *attrList); void FindProtocolDeclaration(bool WarnOnDeclarations, bool ForObjCContainer, ArrayRef ProtocolId, SmallVectorImpl &Protocols); void DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, SourceLocation ProtocolLoc, IdentifierInfo *TypeArgId, SourceLocation TypeArgLoc, bool SelectProtocolFirst = false); /// Given a list of identifiers (and their locations), resolve the /// names to either Objective-C protocol qualifiers or type /// arguments, as appropriate. void actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, SourceLocation lAngleLoc, ArrayRef identifiers, ArrayRef identifierLocs, SourceLocation rAngleLoc, SourceLocation &typeArgsLAngleLoc, SmallVectorImpl &typeArgs, SourceLocation &typeArgsRAngleLoc, SourceLocation &protocolLAngleLoc, SmallVectorImpl &protocols, SourceLocation &protocolRAngleLoc, bool warnOnIncompleteProtocols); /// Build a an Objective-C protocol-qualified 'id' type where no /// base type was specified. TypeResult actOnObjCProtocolQualifierType( SourceLocation lAngleLoc, ArrayRef protocols, ArrayRef protocolLocs, SourceLocation rAngleLoc); /// Build a specialized and/or protocol-qualified Objective-C type. TypeResult actOnObjCTypeArgsAndProtocolQualifiers( Scope *S, SourceLocation Loc, ParsedType BaseType, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc); /// Build an Objective-C object pointer type. QualType BuildObjCObjectType(QualType BaseType, SourceLocation Loc, SourceLocation TypeArgsLAngleLoc, ArrayRef TypeArgs, SourceLocation TypeArgsRAngleLoc, SourceLocation ProtocolLAngleLoc, ArrayRef Protocols, ArrayRef ProtocolLocs, SourceLocation ProtocolRAngleLoc, bool FailOnError = false); /// Check the application of the Objective-C '__kindof' qualifier to /// the given type. bool checkObjCKindOfType(QualType &type, SourceLocation loc); /// Ensure attributes are consistent with type. /// \param [in, out] Attributes The attributes to check; they will /// be modified to be consistent with \p PropertyTy. void CheckObjCPropertyAttributes(Decl *PropertyPtrTy, SourceLocation Loc, unsigned &Attributes, bool propertyInPrimaryClass); /// Process the specified property declaration and create decls for the /// setters and getters as needed. /// \param property The property declaration being processed void ProcessPropertyDecl(ObjCPropertyDecl *property); void DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *Name, bool OverridingProtocolProperty); void DiagnoseClassExtensionDupMethods(ObjCCategoryDecl *CAT, ObjCInterfaceDecl *ID); Decl *ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef allMethods = None, ArrayRef allTUVars = None); Decl *ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, ObjCDeclSpec &ODS, Selector GetterSel, Selector SetterSel, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC = nullptr); Decl *ActOnPropertyImplDecl(Scope *S, SourceLocation AtLoc, SourceLocation PropertyLoc, bool ImplKind, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, SourceLocation PropertyIvarLoc, ObjCPropertyQueryKind QueryKind); enum ObjCSpecialMethodKind { OSMK_None, OSMK_Alloc, OSMK_New, OSMK_Copy, OSMK_RetainingInit, OSMK_NonRetainingInit }; struct ObjCArgInfo { IdentifierInfo *Name; SourceLocation NameLoc; // The Type is null if no type was specified, and the DeclSpec is invalid // in this case. ParsedType Type; ObjCDeclSpec DeclSpec; /// ArgAttrs - Attribute list for this argument. AttributeList *ArgAttrs; }; Decl *ActOnMethodDeclaration( Scope *S, SourceLocation BeginLoc, // location of the + or -. SourceLocation EndLoc, // location of the ; or {. tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, ArrayRef SelectorLocs, Selector Sel, // optional arguments. The number of types/arguments is obtained // from the Sel.getNumArgs(). ObjCArgInfo *ArgInfo, DeclaratorChunk::ParamInfo *CParamInfo, unsigned CNumArgs, // c-style args AttributeList *AttrList, tok::ObjCKeywordKind MethodImplKind, bool isVariadic, bool MethodDefinition); ObjCMethodDecl *LookupMethodInQualifiedType(Selector Sel, const ObjCObjectPointerType *OPT, bool IsInstance); ObjCMethodDecl *LookupMethodInObjectType(Selector Sel, QualType Ty, bool IsInstance); bool CheckARCMethodDecl(ObjCMethodDecl *method); bool inferObjCARCLifetime(ValueDecl *decl); ExprResult HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Expr *BaseExpr, SourceLocation OpLoc, DeclarationName MemberName, SourceLocation MemberLoc, SourceLocation SuperLoc, QualType SuperType, bool Super); ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); ObjCMethodDecl *tryCaptureObjCSelf(SourceLocation Loc); /// \brief Describes the kind of message expression indicated by a message /// send that starts with an identifier. enum ObjCMessageKind { /// \brief The message is sent to 'super'. ObjCSuperMessage, /// \brief The message is an instance message. ObjCInstanceMessage, /// \brief The message is a class message, and the identifier is a type /// name. ObjCClassMessage }; ObjCMessageKind getObjCMessageKind(Scope *S, IdentifierInfo *Name, SourceLocation NameLoc, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType); ExprResult ActOnSuperMessage(Scope *S, SourceLocation SuperLoc, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnClassMessage(Scope *S, ParsedType Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildInstanceMessage(Expr *Receiver, QualType ReceiverType, SourceLocation SuperLoc, Selector Sel, ObjCMethodDecl *Method, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args, bool isImplicit = false); ExprResult BuildInstanceMessageImplicit(Expr *Receiver, QualType ReceiverType, SourceLocation Loc, Selector Sel, ObjCMethodDecl *Method, MultiExprArg Args); ExprResult ActOnInstanceMessage(Scope *S, Expr *Receiver, Selector Sel, SourceLocation LBracLoc, ArrayRef SelectorLocs, SourceLocation RBracLoc, MultiExprArg Args); ExprResult BuildObjCBridgedCast(SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, TypeSourceInfo *TSInfo, Expr *SubExpr); ExprResult ActOnObjCBridgedCast(Scope *S, SourceLocation LParenLoc, ObjCBridgeCastKind Kind, SourceLocation BridgeKeywordLoc, ParsedType Type, SourceLocation RParenLoc, Expr *SubExpr); void CheckTollFreeBridgeCast(QualType castType, Expr *castExpr); void CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr); bool CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, CastKind &Kind); bool checkObjCBridgeRelatedComponents(SourceLocation Loc, QualType DestType, QualType SrcType, ObjCInterfaceDecl *&RelatedClass, ObjCMethodDecl *&ClassMethod, ObjCMethodDecl *&InstanceMethod, TypedefNameDecl *&TDNDecl, bool CfToNs, bool Diagnose = true); bool CheckObjCBridgeRelatedConversions(SourceLocation Loc, QualType DestType, QualType SrcType, Expr *&SrcExpr, bool Diagnose = true); bool ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&SrcExpr, bool Diagnose = true); bool checkInitMethod(ObjCMethodDecl *method, QualType receiverTypeIfCall); /// \brief Check whether the given new method is a valid override of the /// given overridden method, and set any properties that should be inherited. void CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, const ObjCMethodDecl *Overridden); /// \brief Describes the compatibility of a result type with its method. enum ResultTypeCompatibilityKind { RTC_Compatible, RTC_Incompatible, RTC_Unknown }; void CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC); enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural POAK_Packed, // #pragma options align=packed POAK_Power, // #pragma options align=power POAK_Mac68k, // #pragma options align=mac68k POAK_Reset // #pragma options align=reset }; /// ActOnPragmaOptionsAlign - Called on well formed \#pragma options align. void ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc); /// ActOnPragmaPack - Called on well formed \#pragma pack(...). void ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, StringRef SlotLabel, Expr *Alignment); /// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off]. void ActOnPragmaMSStruct(PragmaMSStructKind Kind); /// ActOnPragmaMSComment - Called on well formed /// \#pragma comment(kind, "arg"). void ActOnPragmaMSComment(SourceLocation CommentLoc, PragmaMSCommentKind Kind, StringRef Arg); /// ActOnPragmaMSPointersToMembers - called on well formed \#pragma /// pointers_to_members(representation method[, general purpose /// representation]). void ActOnPragmaMSPointersToMembers( LangOptions::PragmaMSPointersToMembersKind Kind, SourceLocation PragmaLoc); /// \brief Called on well formed \#pragma vtordisp(). void ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Value); enum PragmaSectionKind { PSK_DataSeg, PSK_BSSSeg, PSK_ConstSeg, PSK_CodeSeg, }; bool UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *TheDecl); bool UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation); /// \brief Called on well formed \#pragma bss_seg/data_seg/const_seg/code_seg. void ActOnPragmaMSSeg(SourceLocation PragmaLocation, PragmaMsStackAction Action, llvm::StringRef StackSlotLabel, StringLiteral *SegmentName, llvm::StringRef PragmaName); /// \brief Called on well formed \#pragma section(). void ActOnPragmaMSSection(SourceLocation PragmaLocation, int SectionFlags, StringLiteral *SegmentName); /// \brief Called on well-formed \#pragma init_seg(). void ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, StringLiteral *SegmentName); /// \brief Called on #pragma clang __debug dump II void ActOnPragmaDump(Scope *S, SourceLocation Loc, IdentifierInfo *II); /// ActOnPragmaDetectMismatch - Call on well-formed \#pragma detect_mismatch void ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, StringRef Value); /// ActOnPragmaUnused - Called on well-formed '\#pragma unused'. void ActOnPragmaUnused(const Token &Identifier, Scope *curScope, SourceLocation PragmaLoc); /// ActOnPragmaVisibility - Called on well formed \#pragma GCC visibility... . void ActOnPragmaVisibility(const IdentifierInfo* VisType, SourceLocation PragmaLoc); NamedDecl *DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, SourceLocation Loc); void DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W); /// ActOnPragmaWeakID - Called on well formed \#pragma weak ident. void ActOnPragmaWeakID(IdentifierInfo* WeakName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc); /// ActOnPragmaRedefineExtname - Called on well formed /// \#pragma redefine_extname oldname newname. void ActOnPragmaRedefineExtname(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaWeakAlias - Called on well formed \#pragma weak ident = ident. void ActOnPragmaWeakAlias(IdentifierInfo* WeakName, IdentifierInfo* AliasName, SourceLocation PragmaLoc, SourceLocation WeakNameLoc, SourceLocation AliasNameLoc); /// ActOnPragmaFPContract - Called on well formed /// \#pragma {STDC,OPENCL} FP_CONTRACT void ActOnPragmaFPContract(tok::OnOffSwitch OOS); /// AddAlignmentAttributesForRecord - Adds any needed alignment attributes to /// a the record decl, to handle '\#pragma pack' and '\#pragma options align'. void AddAlignmentAttributesForRecord(RecordDecl *RD); /// AddMsStructLayoutForRecord - Adds ms_struct layout attribute to record. void AddMsStructLayoutForRecord(RecordDecl *RD); /// FreePackedContext - Deallocate and null out PackContext. void FreePackedContext(); /// PushNamespaceVisibilityAttr - Note that we've entered a /// namespace with a visibility attribute. void PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, SourceLocation Loc); /// AddPushedVisibilityAttribute - If '\#pragma GCC visibility' was used, /// add an appropriate visibility attribute. void AddPushedVisibilityAttribute(Decl *RD); /// PopPragmaVisibility - Pop the top element of the visibility stack; used /// for '\#pragma GCC visibility' and visibility attributes on namespaces. void PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc); /// FreeVisContext - Deallocate and null out VisContext. void FreeVisContext(); /// AddCFAuditedAttribute - Check whether we're currently within /// '\#pragma clang arc_cf_code_audited' and, if so, consider adding /// the appropriate attribute. void AddCFAuditedAttribute(Decl *D); /// \brief Called on well formed \#pragma clang optimize. void ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc); /// \brief Get the location for the currently active "\#pragma clang optimize /// off". If this location is invalid, then the state of the pragma is "on". SourceLocation getOptimizeOffPragmaLocation() const { return OptimizeOffPragmaLocation; } /// \brief Only called on function definitions; if there is a pragma in scope /// with the effect of a range-based optnone, consider marking the function /// with attribute optnone. void AddRangeBasedOptnone(FunctionDecl *FD); /// \brief Adds the 'optnone' attribute to the function declaration if there /// are no conflicts; Loc represents the location causing the 'optnone' /// attribute to be added (usually because of a pragma). void AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, SourceLocation Loc); /// AddAlignedAttr - Adds an aligned attribute to a particular declaration. void AddAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned SpellingListIndex, bool IsPackExpansion); void AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *T, unsigned SpellingListIndex, bool IsPackExpansion); /// AddAssumeAlignedAttr - Adds an assume_aligned attribute to a particular /// declaration. void AddAssumeAlignedAttr(SourceRange AttrRange, Decl *D, Expr *E, Expr *OE, unsigned SpellingListIndex); /// AddAlignValueAttr - Adds an align_value attribute to a particular /// declaration. void AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, unsigned SpellingListIndex); /// AddLaunchBoundsAttr - Adds a launch_bounds attribute to a particular /// declaration. void AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, Expr *MinBlocks, unsigned SpellingListIndex); /// AddModeAttr - Adds a mode attribute to a particular declaration. void AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, unsigned SpellingListIndex, bool InInstantiation = false); void AddParameterABIAttr(SourceRange AttrRange, Decl *D, ParameterABI ABI, unsigned SpellingListIndex); void AddNSConsumedAttr(SourceRange AttrRange, Decl *D, unsigned SpellingListIndex, bool isNSConsumed, bool isTemplateInstantiation); //===--------------------------------------------------------------------===// // C++ Coroutines TS // ExprResult ActOnCoawaitExpr(Scope *S, SourceLocation KwLoc, Expr *E); ExprResult ActOnCoyieldExpr(Scope *S, SourceLocation KwLoc, Expr *E); StmtResult ActOnCoreturnStmt(SourceLocation KwLoc, Expr *E); ExprResult BuildCoawaitExpr(SourceLocation KwLoc, Expr *E); ExprResult BuildCoyieldExpr(SourceLocation KwLoc, Expr *E); StmtResult BuildCoreturnStmt(SourceLocation KwLoc, Expr *E); void CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body); //===--------------------------------------------------------------------===// // OpenMP directives and clauses. // private: void *VarDataSharingAttributesStack; /// Set to true inside '#pragma omp declare target' region. bool IsInOpenMPDeclareTargetContext = false; /// \brief Initialization of data-sharing attributes stack. void InitDataSharingAttributesStack(); void DestroyDataSharingAttributesStack(); ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op, OpenMPClauseKind CKind, bool StrictlyPositive = true); /// Returns OpenMP nesting level for current directive. unsigned getOpenMPNestingLevel() const; public: /// \brief Return true if the provided declaration \a VD should be captured by /// reference. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level); /// \brief Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP /// constructs. VarDecl *IsOpenMPCapturedDecl(ValueDecl *D); ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); /// \brief Check if the specified variable is used in 'private' clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPPrivateDecl(ValueDecl *D, unsigned Level); /// \brief Check if the specified variable is captured by 'target' directive. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. bool isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level); ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); /// \brief Called on start of new data sharing attribute block. void StartOpenMPDSABlock(OpenMPDirectiveKind K, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc); /// \brief Start analysis of clauses. void StartOpenMPClause(OpenMPClauseKind K); /// \brief End analysis of clauses. void EndOpenMPClause(); /// \brief Called on end of data sharing attribute block. void EndOpenMPDSABlock(Stmt *CurDirective); /// \brief Check if the current region is an OpenMP loop region and if it is, /// mark loop control variable, used in \p Init for loop initialization, as /// private by default. /// \param Init First part of the for loop. void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init); // OpenMP directives and clauses. /// \brief Called on correct id-expression from the '#pragma omp /// threadprivate'. ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id); /// \brief Called on well-formed '#pragma omp threadprivate'. DeclGroupPtrTy ActOnOpenMPThreadprivateDirective( SourceLocation Loc, ArrayRef VarList); /// \brief Builds a new OpenMPThreadPrivateDecl and checks its correctness. OMPThreadPrivateDecl *CheckOMPThreadPrivateDecl( SourceLocation Loc, ArrayRef VarList); /// \brief Check if the specified type is allowed to be used in 'omp declare /// reduction' construct. QualType ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, TypeResult ParsedType); /// \brief Called on start of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveStart( Scope *S, DeclContext *DC, DeclarationName Name, ArrayRef> ReductionTypes, AccessSpecifier AS, Decl *PrevDeclInScope = nullptr); /// \brief Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner); /// \brief Initialize declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D); /// \brief Finish current declare reduction construct initializer. void ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, Expr *Initializer); /// \brief Called at the end of '#pragma omp declare reduction'. DeclGroupPtrTy ActOnOpenMPDeclareReductionDirectiveEnd( Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid); /// Called on the start of target region i.e. '#pragma omp declare target'. bool ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc); /// Called at the end of target region i.e. '#pragme omp end declare target'. void ActOnFinishOpenMPDeclareTargetDirective(); /// Called on correct id-expression from the '#pragma omp declare target'. void ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, const DeclarationNameInfo &Id, OMPDeclareTargetDeclAttr::MapTypeTy MT, NamedDeclSetType &SameDirectiveDecls); /// Check declaration inside target region. void checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D); /// Return true inside OpenMP target region. bool isInOpenMPDeclareTargetContext() const { return IsInOpenMPDeclareTargetContext; } /// \brief Initialization of captured region for OpenMP region. void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); /// \brief End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. /// \param Clauses List of clauses for the current OpenMP region. /// /// \returns Statement for finished OpenMP region. StmtResult ActOnOpenMPRegionEnd(StmtResult S, ArrayRef Clauses); StmtResult ActOnOpenMPExecutableDirective( OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp parallel' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp for' after parsing /// of the associated statement. StmtResult ActOnOpenMPForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp for simd' after parsing /// of the associated statement. StmtResult ActOnOpenMPForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp sections' after parsing /// of the associated statement. StmtResult ActOnOpenMPSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp section' after parsing of the /// associated statement. StmtResult ActOnOpenMPSectionDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp single' after parsing of the /// associated statement. StmtResult ActOnOpenMPSingleDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp master' after parsing of the /// associated statement. StmtResult ActOnOpenMPMasterDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp critical' after parsing of the /// associated statement. StmtResult ActOnOpenMPCriticalDirective(const DeclarationNameInfo &DirName, ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp parallel for' after parsing /// of the associated statement. StmtResult ActOnOpenMPParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp parallel sections' after /// parsing of the associated statement. StmtResult ActOnOpenMPParallelSectionsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp task' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskyield'. StmtResult ActOnOpenMPTaskyieldDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp barrier'. StmtResult ActOnOpenMPBarrierDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskwait'. StmtResult ActOnOpenMPTaskwaitDirective(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp taskgroup'. StmtResult ActOnOpenMPTaskgroupDirective(Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp flush'. StmtResult ActOnOpenMPFlushDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp ordered' after parsing of the /// associated statement. StmtResult ActOnOpenMPOrderedDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp atomic' after parsing of the /// associated statement. StmtResult ActOnOpenMPAtomicDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target' after parsing of the /// associated statement. StmtResult ActOnOpenMPTargetDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target data' after parsing of /// the associated statement. StmtResult ActOnOpenMPTargetDataDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target enter data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetEnterDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target exit data' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetExitDataDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target parallel' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp target parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp teams' after parsing of the /// associated statement. StmtResult ActOnOpenMPTeamsDirective(ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp cancellation point'. StmtResult ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// \brief Called on well-formed '\#pragma omp cancel'. StmtResult ActOnOpenMPCancelDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc, OpenMPDirectiveKind CancelRegion); /// \brief Called on well-formed '\#pragma omp taskloop' after parsing of the /// associated statement. StmtResult ActOnOpenMPTaskLoopDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp taskloop simd' after parsing of /// the associated statement. StmtResult ActOnOpenMPTaskLoopSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute' after parsing /// of the associated statement. StmtResult ActOnOpenMPDistributeDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp target update'. StmtResult ActOnOpenMPTargetUpdateDirective(ArrayRef Clauses, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed '\#pragma omp distribute parallel for' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute parallel for simd' /// after parsing of the associated statement. StmtResult ActOnOpenMPDistributeParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp distribute simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPDistributeSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// \brief Called on well-formed '\#pragma omp target parallel for simd' after /// parsing of the associated statement. StmtResult ActOnOpenMPTargetParallelForSimdDirective( ArrayRef Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, llvm::DenseMap &VarsWithImplicitDSA); /// Checks correctness of linear modifiers. bool CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, SourceLocation LinLoc); /// Checks that the specified declaration matches requirements for the linear /// decls. bool CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, OpenMPLinearClauseKind LinKind, QualType Type); /// \brief Called on well-formed '\#pragma omp declare simd' after parsing of /// the associated method/function. DeclGroupPtrTy ActOnOpenMPDeclareSimdDirective( DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, ArrayRef Uniforms, ArrayRef Aligneds, ArrayRef Alignments, ArrayRef Linears, ArrayRef LinModifiers, ArrayRef Steps, SourceRange SR); OMPClause *ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'if' clause. OMPClause *ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation NameModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'final' clause. OMPClause *ActOnOpenMPFinalClause(Expr *Condition, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_threads' clause. OMPClause *ActOnOpenMPNumThreadsClause(Expr *NumThreads, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'safelen' clause. OMPClause *ActOnOpenMPSafelenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'simdlen' clause. OMPClause *ActOnOpenMPSimdlenClause(Expr *Length, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'collapse' clause. OMPClause *ActOnOpenMPCollapseClause(Expr *NumForLoops, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'ordered' clause. OMPClause * ActOnOpenMPOrderedClause(SourceLocation StartLoc, SourceLocation EndLoc, SourceLocation LParenLoc = SourceLocation(), Expr *NumForLoops = nullptr); /// \brief Called on well-formed 'grainsize' clause. OMPClause *ActOnOpenMPGrainsizeClause(Expr *Size, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_tasks' clause. OMPClause *ActOnOpenMPNumTasksClause(Expr *NumTasks, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'hint' clause. OMPClause *ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, unsigned Argument, SourceLocation ArgumentLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'default' clause. OMPClause *ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'proc_bind' clause. OMPClause *ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, SourceLocation KindLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef Arguments, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, ArrayRef ArgumentsLoc, SourceLocation DelimLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'schedule' clause. OMPClause *ActOnOpenMPScheduleClause( OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2, OpenMPScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation M1Loc, SourceLocation M2Loc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPClause(OpenMPClauseKind Kind, SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'nowait' clause. OMPClause *ActOnOpenMPNowaitClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'untied' clause. OMPClause *ActOnOpenMPUntiedClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'mergeable' clause. OMPClause *ActOnOpenMPMergeableClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'read' clause. OMPClause *ActOnOpenMPReadClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'write' clause. OMPClause *ActOnOpenMPWriteClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'update' clause. OMPClause *ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'capture' clause. OMPClause *ActOnOpenMPCaptureClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'seq_cst' clause. OMPClause *ActOnOpenMPSeqCstClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'threads' clause. OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'simd' clause. OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'nogroup' clause. OMPClause *ActOnOpenMPNogroupClause(SourceLocation StartLoc, SourceLocation EndLoc); OMPClause *ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef Vars, Expr *TailExpr, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation DepLinMapLoc); /// \brief Called on well-formed 'private' clause. OMPClause *ActOnOpenMPPrivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'firstprivate' clause. OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'lastprivate' clause. OMPClause *ActOnOpenMPLastprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'reduction' clause. OMPClause *ActOnOpenMPReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef UnresolvedReductions = llvm::None); /// \brief Called on well-formed 'linear' clause. OMPClause * ActOnOpenMPLinearClause(ArrayRef VarList, Expr *Step, SourceLocation StartLoc, SourceLocation LParenLoc, OpenMPLinearClauseKind LinKind, SourceLocation LinLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'aligned' clause. OMPClause *ActOnOpenMPAlignedClause(ArrayRef VarList, Expr *Alignment, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'copyin' clause. OMPClause *ActOnOpenMPCopyinClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'copyprivate' clause. OMPClause *ActOnOpenMPCopyprivateClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'flush' pseudo clause. OMPClause *ActOnOpenMPFlushClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'depend' clause. OMPClause * ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'device' clause. OMPClause *ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'map' clause. OMPClause * ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'num_teams' clause. OMPClause *ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'thread_limit' clause. OMPClause *ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'priority' clause. OMPClause *ActOnOpenMPPriorityClause(Expr *Priority, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'dist_schedule' clause. OMPClause *ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'defaultmap' clause. OMPClause *ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'to' clause. OMPClause *ActOnOpenMPToClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief Called on well-formed 'from' clause. OMPClause *ActOnOpenMPFromClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'use_device_ptr' clause. OMPClause *ActOnOpenMPUseDevicePtrClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// Called on well-formed 'is_device_ptr' clause. OMPClause *ActOnOpenMPIsDevicePtrClause(ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); /// \brief The kind of conversion being performed. enum CheckedConversionKind { /// \brief An implicit conversion. CCK_ImplicitConversion, /// \brief A C-style cast. CCK_CStyleCast, /// \brief A functional-style cast. CCK_FunctionalCast, /// \brief A cast other than a C-style cast. CCK_OtherCast }; /// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit /// cast. If there is already an implicit cast, merge into the existing one. /// If isLvalue, the result of the cast is an lvalue. ExprResult ImpCastExprToType(Expr *E, QualType Type, CastKind CK, ExprValueKind VK = VK_RValue, const CXXCastPath *BasePath = nullptr, CheckedConversionKind CCK = CCK_ImplicitConversion); /// ScalarTypeToBooleanCastKind - Returns the cast kind corresponding /// to the conversion from scalar type ScalarTy to the Boolean type. static CastKind ScalarTypeToBooleanCastKind(QualType ScalarTy); /// IgnoredValueConversions - Given that an expression's result is /// syntactically ignored, perform any conversions that are /// required. ExprResult IgnoredValueConversions(Expr *E); // UsualUnaryConversions - promotes integers (C99 6.3.1.1p2) and converts // functions and arrays to their respective pointers (C99 6.3.2.1). ExprResult UsualUnaryConversions(Expr *E); /// CallExprUnaryConversions - a special case of an unary conversion /// performed on a function designator of a call expression. ExprResult CallExprUnaryConversions(Expr *E); // DefaultFunctionArrayConversion - converts functions and arrays // to their respective pointers (C99 6.3.2.1). ExprResult DefaultFunctionArrayConversion(Expr *E, bool Diagnose = true); // DefaultFunctionArrayLvalueConversion - converts functions and // arrays to their respective pointers and performs the // lvalue-to-rvalue conversion. ExprResult DefaultFunctionArrayLvalueConversion(Expr *E, bool Diagnose = true); // DefaultLvalueConversion - performs lvalue-to-rvalue conversion on // the operand. This is DefaultFunctionArrayLvalueConversion, // except that it assumes the operand isn't of function or array // type. ExprResult DefaultLvalueConversion(Expr *E); // DefaultArgumentPromotion (C99 6.5.2.2p6). Used for function calls that // do not have a prototype. Integer promotions are performed on each // argument, and arguments that have type float are promoted to double. ExprResult DefaultArgumentPromotion(Expr *E); // Used for emitting the right warning by DefaultVariadicArgumentPromotion enum VariadicCallType { VariadicFunction, VariadicBlock, VariadicMethod, VariadicConstructor, VariadicDoesNotApply }; VariadicCallType getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, Expr *Fn); // Used for determining in which context a type is allowed to be passed to a // vararg function. enum VarArgKind { VAK_Valid, VAK_ValidInCXX11, VAK_Undefined, VAK_MSVCUndefined, VAK_Invalid }; // Determines which VarArgKind fits an expression. VarArgKind isValidVarArgType(const QualType &Ty); /// Check to see if the given expression is a valid argument to a variadic /// function, issuing a diagnostic if not. void checkVariadicArgument(const Expr *E, VariadicCallType CT); /// Check to see if a given expression could have '.c_str()' called on it. bool hasCStrMethod(const Expr *E); /// GatherArgumentsForCall - Collector argument expressions for various /// form of call prototypes. bool GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, const FunctionProtoType *Proto, unsigned FirstParam, ArrayRef Args, SmallVectorImpl &AllArgs, VariadicCallType CallType = VariadicDoesNotApply, bool AllowExplicit = false, bool IsListInitialization = false); // DefaultVariadicArgumentPromotion - Like DefaultArgumentPromotion, but // will create a runtime trap if the resulting type is not a POD type. ExprResult DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, FunctionDecl *FDecl); // UsualArithmeticConversions - performs the UsualUnaryConversions on it's // operands and then handles various conversions that are common to binary // operators (C99 6.3.1.8). If both operands aren't arithmetic, this // routine returns the first non-arithmetic type found. The client is // responsible for emitting appropriate error diagnostics. QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, bool IsCompAssign = false); /// AssignConvertType - All of the 'assignment' semantic checks return this /// enum to indicate whether the assignment was allowed. These checks are /// done for simple assignments, as well as initialization, return from /// function, argument passing, etc. The query is phrased in terms of a /// source and destination type. enum AssignConvertType { /// Compatible - the types are compatible according to the standard. Compatible, /// PointerToInt - The assignment converts a pointer to an int, which we /// accept as an extension. PointerToInt, /// IntToPointer - The assignment converts an int to a pointer, which we /// accept as an extension. IntToPointer, /// FunctionVoidPointer - The assignment is between a function pointer and /// void*, which the standard doesn't allow, but we accept as an extension. FunctionVoidPointer, /// IncompatiblePointer - The assignment is between two pointers types that /// are not compatible, but we accept them as an extension. IncompatiblePointer, /// IncompatiblePointer - The assignment is between two pointers types which /// point to integers which have a different sign, but are otherwise /// identical. This is a subset of the above, but broken out because it's by /// far the most common case of incompatible pointers. IncompatiblePointerSign, /// CompatiblePointerDiscardsQualifiers - The assignment discards /// c/v/r qualifiers, which we accept as an extension. CompatiblePointerDiscardsQualifiers, /// IncompatiblePointerDiscardsQualifiers - The assignment /// discards qualifiers that we don't permit to be discarded, /// like address spaces. IncompatiblePointerDiscardsQualifiers, /// IncompatibleNestedPointerQualifiers - The assignment is between two /// nested pointer types, and the qualifiers other than the first two /// levels differ e.g. char ** -> const char **, but we accept them as an /// extension. IncompatibleNestedPointerQualifiers, /// IncompatibleVectors - The assignment is between two vector types that /// have the same size, which we accept as an extension. IncompatibleVectors, /// IntToBlockPointer - The assignment converts an int to a block /// pointer. We disallow this. IntToBlockPointer, /// IncompatibleBlockPointer - The assignment is between two block /// pointers types that are not compatible. IncompatibleBlockPointer, /// IncompatibleObjCQualifiedId - The assignment is between a qualified /// id type and something else (that is incompatible with it). For example, /// "id " = "Foo *", where "Foo *" doesn't implement the XXX protocol. IncompatibleObjCQualifiedId, /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an /// object with __weak qualifier. IncompatibleObjCWeakRef, /// Incompatible - We reject this conversion outright, it is invalid to /// represent it in the AST. Incompatible }; /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the /// assignment conversion type specified by ConvTy. This returns true if the /// conversion was invalid or false if the conversion was accepted. bool DiagnoseAssignmentResult(AssignConvertType ConvTy, SourceLocation Loc, QualType DstType, QualType SrcType, Expr *SrcExpr, AssignmentAction Action, bool *Complained = nullptr); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid /// value, to be used as a mask. bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, bool AllowMask) const; /// DiagnoseAssignmentEnum - Warn if assignment to enum is a constant /// integer not in the range of enum values. void DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, Expr *SrcExpr); /// CheckAssignmentConstraints - Perform type checking for assignment, /// argument passing, variable initialization, and function return values. /// C99 6.5.16. AssignConvertType CheckAssignmentConstraints(SourceLocation Loc, QualType LHSType, QualType RHSType); /// Check assignment constraints and optionally prepare for a conversion of /// the RHS to the LHS type. The conversion is prepared for if ConvertRHS /// is true. AssignConvertType CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, CastKind &Kind, bool ConvertRHS = true); // CheckSingleAssignmentConstraints - Currently used by // CheckAssignmentOperands, and ActOnReturnStmt. Prior to type checking, // this routine performs the default function/array converions, if ConvertRHS // is true. AssignConvertType CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, bool Diagnose = true, bool DiagnoseCFAudited = false, bool ConvertRHS = true); // \brief If the lhs type is a transparent union, check whether we // can initialize the transparent union with the given expression. AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); bool CheckExceptionSpecCompatibility(Expr *From, QualType ToType); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit = false); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, AssignmentAction Action, bool AllowExplicit, ImplicitConversionSequence& ICS); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence& ICS, AssignmentAction Action, CheckedConversionKind CCK = CCK_ImplicitConversion); ExprResult PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK); /// the following "Check" methods will return a valid/converted QualType /// or a null QualType (indicating an error diagnostic was issued). /// type checking binary operators (subroutines of CreateBuiltinBinOp). QualType InvalidOperands(SourceLocation Loc, ExprResult &LHS, ExprResult &RHS); QualType CheckPointerToMemberOperands( // C++ 5.5 ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation OpLoc, bool isIndirect); QualType CheckMultiplyDivideOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool IsDivide); QualType CheckRemainderOperands( // C99 6.5.5 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckAdditionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, QualType* CompLHSTy = nullptr); QualType CheckSubtractionOperands( // C99 6.5.6 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, QualType* CompLHSTy = nullptr); QualType CheckShiftOperands( // C99 6.5.7 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool IsCompAssign = false); QualType CheckCompareOperands( // C99 6.5.8/9 ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc, bool isRelational); QualType CheckBitwiseOperands( // C99 6.5.[10...12] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign = false); QualType CheckLogicalOperands( // C99 6.5.[13,14] ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc); // CheckAssignmentOperands is used for both simple and compound assignment. // For simple assignment, pass both expressions and a null converted type. // For compound assignment, pass both expressions and the converted type. QualType CheckAssignmentOperands( // C99 6.5.16.[1,2] Expr *LHSExpr, ExprResult &RHS, SourceLocation Loc, QualType CompoundType); ExprResult checkPseudoObjectIncDec(Scope *S, SourceLocation OpLoc, UnaryOperatorKind Opcode, Expr *Op); ExprResult checkPseudoObjectAssignment(Scope *S, SourceLocation OpLoc, BinaryOperatorKind Opcode, Expr *LHS, Expr *RHS); ExprResult checkPseudoObjectRValue(Expr *E); Expr *recreateSyntacticForm(PseudoObjectExpr *E); QualType CheckConditionalOperands( // C99 6.5.15 ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc); QualType CXXCheckConditionalOperands( // C++ 5.16 ExprResult &cond, ExprResult &lhs, ExprResult &rhs, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation questionLoc); QualType FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType = nullptr); QualType FindCompositePointerType(SourceLocation Loc, ExprResult &E1, ExprResult &E2, bool *NonStandardCompositeType = nullptr) { Expr *E1Tmp = E1.get(), *E2Tmp = E2.get(); QualType Composite = FindCompositePointerType(Loc, E1Tmp, E2Tmp, NonStandardCompositeType); E1 = E1Tmp; E2 = E2Tmp; return Composite; } QualType FindCompositeObjCPointerType(ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc); bool DiagnoseConditionalForNull(Expr *LHSExpr, Expr *RHSExpr, SourceLocation QuestionLoc); void DiagnoseAlwaysNonNullPointer(Expr *E, Expr::NullPointerConstantKind NullType, bool IsEqual, SourceRange Range); /// type checking for vector binary operators. QualType CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign, bool AllowBothBool, bool AllowBoolConversion); QualType GetSignedVectorType(QualType V); QualType CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool isRelational); QualType CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc); bool areLaxCompatibleVectorTypes(QualType srcType, QualType destType); bool isLaxVectorConversion(QualType srcType, QualType destType); /// type checking declaration initializers (C99 6.7.8) bool CheckForConstantInitializer(Expr *e, QualType t); // type checking C++ declaration initializers (C++ [dcl.init]). /// ReferenceCompareResult - Expresses the result of comparing two /// types (cv1 T1 and cv2 T2) to determine their compatibility for the /// purposes of initialization by reference (C++ [dcl.init.ref]p4). enum ReferenceCompareResult { /// Ref_Incompatible - The two types are incompatible, so direct /// reference binding is not possible. Ref_Incompatible = 0, /// Ref_Related - The two types are reference-related, which means /// that their unqualified forms (T1 and T2) are either the same /// or T1 is a base class of T2. Ref_Related, /// Ref_Compatible_With_Added_Qualification - The two types are /// reference-compatible with added qualification, meaning that /// they are reference-compatible and the qualifiers on T1 (cv1) /// are greater than the qualifiers on T2 (cv2). Ref_Compatible_With_Added_Qualification, /// Ref_Compatible - The two types are reference-compatible and /// have equivalent qualifiers (cv1 == cv2). Ref_Compatible }; ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2, bool &DerivedToBase, bool &ObjCConversion, bool &ObjCLifetimeConversion); ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path); /// \brief Force an expression with unknown-type to an expression of the /// given type. ExprResult forceUnknownAnyToType(Expr *E, QualType ToType); /// \brief Type-check an expression that's being passed to an /// __unknown_anytype parameter. ExprResult checkUnknownAnyArg(SourceLocation callLoc, Expr *result, QualType ¶mType); // CheckVectorCast - check type constraints for vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size. // returns true if the cast is invalid bool CheckVectorCast(SourceRange R, QualType VectorTy, QualType Ty, CastKind &Kind); /// \brief Prepare `SplattedExpr` for a vector splat operation, adding /// implicit casts if necessary. ExprResult prepareVectorSplat(QualType VectorTy, Expr *SplattedExpr); // CheckExtVectorCast - check type constraints for extended vectors. // Since vectors are an extension, there are no C standard reference for this. // We allow casting between vectors and integer datatypes of the same size, // or vectors and the element type of that vector. // returns the cast expr ExprResult CheckExtVectorCast(SourceRange R, QualType DestTy, Expr *CastExpr, CastKind &Kind); ExprResult BuildCXXFunctionalCastExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, Expr *CastExpr, SourceLocation RParenLoc); enum ARCConversionResult { ACR_okay, ACR_unbridged, ACR_error }; /// \brief Checks for invalid conversions and casts between /// retainable pointers and other pointer kinds. ARCConversionResult CheckObjCARCConversion(SourceRange castRange, QualType castType, Expr *&op, CheckedConversionKind CCK, bool Diagnose = true, bool DiagnoseCFAudited = false, BinaryOperatorKind Opc = BO_PtrMemD ); Expr *stripARCUnbridgedCast(Expr *e); void diagnoseARCUnbridgedCast(Expr *e); bool CheckObjCARCUnavailableWeakConversion(QualType castType, QualType ExprType); /// checkRetainCycles - Check whether an Objective-C message send /// might create an obvious retain cycle. void checkRetainCycles(ObjCMessageExpr *msg); void checkRetainCycles(Expr *receiver, Expr *argument); void checkRetainCycles(VarDecl *Var, Expr *Init); /// checkUnsafeAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained type. bool checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS); /// checkUnsafeExprAssigns - Check whether +1 expr is being assigned /// to weak/__unsafe_unretained expression. void checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS); /// CheckMessageArgumentTypes - Check types in an Obj-C message send. /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. bool CheckMessageArgumentTypes(QualType ReceiverType, MultiExprArg Args, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, ExprValueKind &VK); /// \brief Determine the result of a message send expression based on /// the type of the receiver, the method expected to receive the message, /// and the form of the message send. QualType getMessageSendResultType(QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage); /// \brief If the given expression involves a message send to a method /// with a related result type, emit a note describing what happened. void EmitRelatedResultTypeNote(const Expr *E); /// \brief Given that we had incompatible pointer types in a return /// statement, check whether we're in a method with a related result /// type, and if so, emit a note describing what happened. void EmitRelatedResultTypeNoteForReturn(QualType destType); class ConditionResult { Decl *ConditionVar; FullExprArg Condition; bool Invalid; bool HasKnownValue; bool KnownValue; friend class Sema; ConditionResult(Sema &S, Decl *ConditionVar, FullExprArg Condition, bool IsConstexpr) : ConditionVar(ConditionVar), Condition(Condition), Invalid(false), HasKnownValue(IsConstexpr && Condition.get() && !Condition.get()->isValueDependent()), KnownValue(HasKnownValue && !!Condition.get()->EvaluateKnownConstInt(S.Context)) {} explicit ConditionResult(bool Invalid) : ConditionVar(nullptr), Condition(nullptr), Invalid(Invalid), HasKnownValue(false), KnownValue(false) {} public: ConditionResult() : ConditionResult(false) {} bool isInvalid() const { return Invalid; } std::pair get() const { return std::make_pair(cast_or_null(ConditionVar), Condition.get()); } llvm::Optional getKnownValue() const { if (!HasKnownValue) return None; return KnownValue; } }; static ConditionResult ConditionError() { return ConditionResult(true); } enum class ConditionKind { Boolean, ///< A boolean condition, from 'if', 'while', 'for', or 'do'. ConstexprIf, ///< A constant boolean condition from 'if constexpr'. Switch ///< An integral condition for a 'switch' statement. }; ConditionResult ActOnCondition(Scope *S, SourceLocation Loc, Expr *SubExpr, ConditionKind CK); ConditionResult ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); DeclResult ActOnCXXConditionDeclaration(Scope *S, Declarator &D); ExprResult CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK); ExprResult CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond); /// CheckBooleanCondition - Diagnose problems involving the use of /// the given expression as a boolean condition (e.g. in an if /// statement). Also performs the standard function and array /// decays, possibly changing the input variable. /// /// \param Loc - A location associated with the condition, e.g. the /// 'if' keyword. /// \return true iff there were any errors ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr = false); /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); /// \brief Redundant parentheses over an equality comparison can indicate /// that the user intended an assignment used as condition. void DiagnoseEqualityWithExtraParens(ParenExpr *ParenE); /// CheckCXXBooleanCondition - Returns true if conversion to bool is invalid. ExprResult CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr = false); /// ConvertIntegerToTypeWarnOnOverflow - Convert the specified APInt to have /// the specified width and sign. If an overflow occurs, detect it and emit /// the specified diagnostic. void ConvertIntegerToTypeWarnOnOverflow(llvm::APSInt &OldVal, unsigned NewWidth, bool NewSign, SourceLocation Loc, unsigned DiagID); /// Checks that the Objective-C declaration is declared in the global scope. /// Emits an error and marks the declaration as invalid if it's not declared /// in the global scope. bool CheckObjCDeclScope(Decl *D); /// \brief Abstract base class used for diagnosing integer constant /// expression violations. class VerifyICEDiagnoser { public: bool Suppress; VerifyICEDiagnoser(bool Suppress = false) : Suppress(Suppress) { } virtual void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) =0; virtual void diagnoseFold(Sema &S, SourceLocation Loc, SourceRange SR); virtual ~VerifyICEDiagnoser() { } }; /// VerifyIntegerConstantExpression - Verifies that an expression is an ICE, /// and reports the appropriate diagnostics. Returns false on success. /// Can optionally return the value of the expression. ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, VerifyICEDiagnoser &Diagnoser, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, unsigned DiagID, bool AllowFold = true); ExprResult VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result = nullptr); /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. /// Can optionally return whether the bit-field is of width 0 ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth = nullptr); enum CUDAFunctionTarget { CFT_Device, CFT_Global, CFT_Host, CFT_HostDevice, CFT_InvalidTarget }; CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D); // CUDA function call preference. Must be ordered numerically from // worst to best. enum CUDAFunctionPreference { CFP_Never, // Invalid caller/callee combination. CFP_WrongSide, // Calls from host-device to host or device // function that do not match current compilation // mode. Only in effect if // LangOpts.CUDADisableTargetCallChecks is true. CFP_HostDevice, // Any calls to host/device functions. CFP_SameSide, // Calls from host-device to host or device // function matching current compilation mode. CFP_Native, // host-to-host or device-to-device calls. }; /// Identifies relative preference of a given Caller/Callee /// combination, based on their host/device attributes. /// \param Caller function which needs address of \p Callee. /// nullptr in case of global context. /// \param Callee target function /// /// \returns preference value for particular Caller/Callee combination. CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee); /// Determines whether Caller may invoke Callee, based on their CUDA /// host/device attributes. Returns true if the call is not allowed. bool CheckCUDATarget(const FunctionDecl *Caller, const FunctionDecl *Callee) { return IdentifyCUDAPreference(Caller, Callee) == CFP_Never; } /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, /// depending on FD and the current compilation settings. void maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *FD, const LookupResult &Previous); /// Finds a function in \p Matches with highest calling priority /// from \p Caller context and erases all functions with lower /// calling priority. void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, SmallVectorImpl &Matches); void EraseUnwantedCUDAMatches(const FunctionDecl *Caller, SmallVectorImpl &Matches); void EraseUnwantedCUDAMatches( const FunctionDecl *Caller, SmallVectorImpl> &Matches); /// Given a implicit special member, infer its CUDA target from the /// calls it needs to make to underlying base/field special members. /// \param ClassDecl the class for which the member is being created. /// \param CSM the kind of special member. /// \param MemberDecl the special member itself. /// \param ConstRHS true if this is a copy operation with a const object on /// its RHS. /// \param Diagnose true if this call should emit diagnostics. /// \return true if there was an error inferring. /// The result of this call is implicit CUDA target attribute(s) attached to /// the member declaration. bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXSpecialMember CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose); /// \return true if \p CD can be considered empty according to CUDA /// (E.2.3.1 in CUDA 7.5 Programming guide). bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); /// \name Code completion //@{ /// \brief Describes the context in which code completion occurs. enum ParserCompletionContext { /// \brief Code completion occurs at top-level or namespace context. PCC_Namespace, /// \brief Code completion occurs within a class, struct, or union. PCC_Class, /// \brief Code completion occurs within an Objective-C interface, protocol, /// or category. PCC_ObjCInterface, /// \brief Code completion occurs within an Objective-C implementation or /// category implementation PCC_ObjCImplementation, /// \brief Code completion occurs within the list of instance variables /// in an Objective-C interface, protocol, category, or implementation. PCC_ObjCInstanceVariableList, /// \brief Code completion occurs following one or more template /// headers. PCC_Template, /// \brief Code completion occurs following one or more template /// headers within a class. PCC_MemberTemplate, /// \brief Code completion occurs within an expression. PCC_Expression, /// \brief Code completion occurs within a statement, which may /// also be an expression or a declaration. PCC_Statement, /// \brief Code completion occurs at the beginning of the /// initialization statement (or expression) in a for loop. PCC_ForInit, /// \brief Code completion occurs within the condition of an if, /// while, switch, or for statement. PCC_Condition, /// \brief Code completion occurs within the body of a function on a /// recovery path, where we do not have a specific handle on our position /// in the grammar. PCC_RecoveryInFunction, /// \brief Code completion occurs where only a type is permitted. PCC_Type, /// \brief Code completion occurs in a parenthesized expression, which /// might also be a type cast. PCC_ParenthesizedExpression, /// \brief Code completion occurs within a sequence of declaration /// specifiers within a function, method, or block. PCC_LocalDeclarationSpecifiers }; void CodeCompleteModuleImport(SourceLocation ImportLoc, ModuleIdPath Path); void CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext); void CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, bool AllowNestedNameSpecifiers); struct CodeCompleteExpressionData; void CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data); void CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, SourceLocation OpLoc, bool IsArrow); void CodeCompletePostfixExpression(Scope *S, ExprResult LHS); void CodeCompleteTag(Scope *S, unsigned TagSpec); void CodeCompleteTypeQualifiers(DeclSpec &DS); void CodeCompleteBracketDeclarator(Scope *S); void CodeCompleteCase(Scope *S); void CodeCompleteCall(Scope *S, Expr *Fn, ArrayRef Args); void CodeCompleteConstructor(Scope *S, QualType Type, SourceLocation Loc, ArrayRef Args); void CodeCompleteInitializer(Scope *S, Decl *D); void CodeCompleteReturn(Scope *S); void CodeCompleteAfterIf(Scope *S); void CodeCompleteAssignmentRHS(Scope *S, Expr *LHS); void CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, bool EnteringContext); void CodeCompleteUsing(Scope *S); void CodeCompleteUsingDirective(Scope *S); void CodeCompleteNamespaceDecl(Scope *S); void CodeCompleteNamespaceAliasDecl(Scope *S); void CodeCompleteOperatorName(Scope *S); void CodeCompleteConstructorInitializer( Decl *Constructor, ArrayRef Initializers); void CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, bool AfterAmpersand); void CodeCompleteObjCAtDirective(Scope *S); void CodeCompleteObjCAtVisibility(Scope *S); void CodeCompleteObjCAtStatement(Scope *S); void CodeCompleteObjCAtExpression(Scope *S); void CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS); void CodeCompleteObjCPropertyGetter(Scope *S); void CodeCompleteObjCPropertySetter(Scope *S); void CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, ArrayRef SelIdents, bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences( ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); void CodeCompleteObjCInterfaceDecl(Scope *S); void CodeCompleteObjCSuperclass(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationDecl(Scope *S); void CodeCompleteObjCInterfaceCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCImplementationCategory(Scope *S, IdentifierInfo *ClassName, SourceLocation ClassNameLoc); void CodeCompleteObjCPropertyDefinition(Scope *S); void CodeCompleteObjCPropertySynthesizeIvar(Scope *S, IdentifierInfo *PropertyName); void CodeCompleteObjCMethodDecl(Scope *S, bool IsInstanceMethod, ParsedType ReturnType); void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnType, ArrayRef SelIdents); void CodeCompletePreprocessorDirective(bool InConditional); void CodeCompleteInPreprocessorConditionalExclusion(Scope *S); void CodeCompletePreprocessorMacroName(bool IsDefinition); void CodeCompletePreprocessorExpression(); void CodeCompletePreprocessorMacroArgument(Scope *S, IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument); void CodeCompleteNaturalLanguage(); void GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, SmallVectorImpl &Results); //@} //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system public: SourceLocation getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const; private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE=nullptr, bool AllowOnePastEnd=true, bool IndexNegated=false); void CheckArrayAccess(const Expr *E); // Used to grab the relevant information from a FormatAttr and a // FunctionDeclaration. struct FormatStringInfo { unsigned FormatIdx; unsigned FirstDataArg; bool HasVAListArg; }; static bool getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, FormatStringInfo *FSI); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation loc, ArrayRef Args); bool CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto); bool CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto); void CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc); void checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType); bool CheckObjCString(Expr *Arg); ExprResult CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth); bool CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartImpl(CallExpr *TheCall); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinMSVAStart(CallExpr *TheCall); bool SemaBuiltinVAStartARM(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); public: // Used by C++ template instantiation. ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, SourceLocation BuiltinLoc, SourceLocation RParenLoc); private: bool SemaBuiltinPrefetch(CallExpr *TheCall); bool SemaBuiltinAssume(CallExpr *TheCall); bool SemaBuiltinAssumeAligned(CallExpr *TheCall); bool SemaBuiltinLongjmp(CallExpr *TheCall); bool SemaBuiltinSetjmp(CallExpr *TheCall); ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op); bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High); + bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Multiple); bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, unsigned ExpectedFieldNum, bool AllowName); public: enum FormatStringType { FST_Scanf, FST_Printf, FST_NSString, FST_Strftime, FST_Strfmon, FST_Kprintf, FST_FreeBSDKPrintf, FST_OSTrace, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); bool FormatStringHasSArg(const StringLiteral *FExpr); static bool GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx); private: bool CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs); bool CheckFormatArguments(ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, VariadicCallType CallType, SourceLocation Loc, SourceRange range, llvm::SmallBitVector &CheckedVarArgs); void CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl, IdentifierInfo *FnInfo); void CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName); void CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckStrncatArguments(const CallExpr *Call, IdentifierInfo *FnName); void CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod = false, const AttrVec *Attrs = nullptr, const FunctionDecl *FD = nullptr); void CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr* RHS); void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation()); void CheckBoolLikeConversion(Expr *E, SourceLocation CC); void CheckForIntOverflow(Expr *E); void CheckUnsequencedOperations(Expr *E); /// \brief Perform semantic checks on a completed expression. This will either /// be a full-expression or a default argument expression. void CheckCompletedExpr(Expr *E, SourceLocation CheckLoc = SourceLocation(), bool IsConstexpr = false); void CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *Field, Expr *Init); /// \brief Check if the given expression contains 'break' or 'continue' /// statement that produces control flow different from GCC. void CheckBreakContinueBinding(Expr *E); /// \brief Check whether receiver is mutable ObjC container which /// attempts to add itself into the container void CheckObjCCircularContainer(ObjCMessageExpr *Message); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm); public: /// \brief Register a magic integral constant to be used as a type tag. void RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull); struct TypeTagData { TypeTagData() {} TypeTagData(QualType Type, bool LayoutCompatible, bool MustBeNull) : Type(Type), LayoutCompatible(LayoutCompatible), MustBeNull(MustBeNull) {} QualType Type; /// If true, \c Type should be compared with other expression's types for /// layout-compatibility. unsigned LayoutCompatible : 1; unsigned MustBeNull : 1; }; /// A pair of ArgumentKind identifier and magic value. This uniquely /// identifies the magic value. typedef std::pair TypeTagMagicValue; private: /// \brief A map from magic value to type information. std::unique_ptr> TypeTagForDatatypeMagicValues; /// \brief Peform checks on a call of a function with argument_with_type_tag /// or pointer_with_type_tag attributes. void CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs); /// \brief The parser's current scope. /// /// The parser maintains this state here. Scope *CurScope; mutable IdentifierInfo *Ident_super; mutable IdentifierInfo *Ident___float128; /// Nullability type specifiers. IdentifierInfo *Ident__Nonnull = nullptr; IdentifierInfo *Ident__Nullable = nullptr; IdentifierInfo *Ident__Null_unspecified = nullptr; IdentifierInfo *Ident_NSError = nullptr; protected: friend class Parser; friend class InitializationSequence; friend class ASTReader; friend class ASTDeclReader; friend class ASTWriter; public: /// Retrieve the keyword associated IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability); /// The struct behind the CFErrorRef pointer. RecordDecl *CFError = nullptr; /// Retrieve the identifier "NSError". IdentifierInfo *getNSErrorIdent(); /// \brief Retrieve the parser's current scope. /// /// This routine must only be used when it is certain that semantic analysis /// and the parser are in precisely the same context, which is not the case /// when, e.g., we are performing any kind of template instantiation. /// Therefore, the only safe places to use this scope are in the parser /// itself and in routines directly invoked from the parser and *never* from /// template substitution or instantiation. Scope *getCurScope() const { return CurScope; } void incrementMSManglingNumber() const { return CurScope->incrementMSManglingNumber(); } IdentifierInfo *getSuperIdentifier() const; IdentifierInfo *getFloat128Identifier() const; Decl *getObjCDeclContext() const; DeclContext *getCurLexicalContext() const { return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } AvailabilityResult getCurContextAvailability() const; const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast(DC)) DC = CatD->getClassInterface(); return DC; } /// \brief To be used for checking whether the arguments being passed to /// function exceeds the number of parameters expected for it. static bool TooManyArguments(size_t NumParams, size_t NumArgs, bool PartialOverloading = false) { // We check whether we're just after a comma in code-completion. if (NumArgs > 0 && PartialOverloading) return NumArgs + 1 > NumParams; // If so, we view as an extra argument. return NumArgs > NumParams; } // Emitting members of dllexported classes is delayed until the class // (including field initializers) is fully parsed. SmallVector DelayedDllExportClasses; }; /// \brief RAII object that enters a new expression evaluation context. class EnterExpressionEvaluationContext { Sema &Actions; bool Entered = true; public: EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl = nullptr, bool IsDecltype = false, bool ShouldEnter = true) : Actions(Actions), Entered(ShouldEnter) { if (Entered) Actions.PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype); } EnterExpressionEvaluationContext(Sema &Actions, Sema::ExpressionEvaluationContext NewContext, Sema::ReuseLambdaContextDecl_t, bool IsDecltype = false) : Actions(Actions) { Actions.PushExpressionEvaluationContext(NewContext, Sema::ReuseLambdaContextDecl, IsDecltype); } ~EnterExpressionEvaluationContext() { if (Entered) Actions.PopExpressionEvaluationContext(); } }; DeductionFailureInfo MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); /// \brief Contains a late templated function. /// Will be parsed at the end of the translation unit, used by Sema & Parser. struct LateParsedTemplate { CachedTokens Toks; /// \brief The template function declaration to be late parsed. Decl *D; }; } // end namespace clang #endif diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 643e191fb01a..be5d4ad8feda 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -1,8618 +1,8620 @@ //===--- Targets.cpp - Implement target feature support -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements construction of a TargetInfo object from a // target triple. // //===----------------------------------------------------------------------===// #include "clang/Basic/Builtins.h" #include "clang/Basic/Cuda.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/MacroBuilder.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TargetParser.h" #include #include using namespace clang; //===----------------------------------------------------------------------===// // Common code shared among targets. //===----------------------------------------------------------------------===// /// DefineStd - Define a macro name and standard variants. For example if /// MacroName is "unix", then this will define "__unix", "__unix__", and "unix" /// when in GNU mode. static void DefineStd(MacroBuilder &Builder, StringRef MacroName, const LangOptions &Opts) { assert(MacroName[0] != '_' && "Identifier should be in the user's namespace"); // If in GNU mode (e.g. -std=gnu99 but not -std=c99) define the raw identifier // in the user's namespace. if (Opts.GNUMode) Builder.defineMacro(MacroName); // Define __unix. Builder.defineMacro("__" + MacroName); // Define __unix__. Builder.defineMacro("__" + MacroName + "__"); } static void defineCPUMacros(MacroBuilder &Builder, StringRef CPUName, bool Tuning = true) { Builder.defineMacro("__" + CPUName); Builder.defineMacro("__" + CPUName + "__"); if (Tuning) Builder.defineMacro("__tune_" + CPUName + "__"); } static TargetInfo *AllocateTarget(const llvm::Triple &Triple, const TargetOptions &Opts); //===----------------------------------------------------------------------===// // Defines specific to certain operating systems. //===----------------------------------------------------------------------===// namespace { template class OSTargetInfo : public TgtInfo { protected: virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const=0; public: OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TgtInfo(Triple, Opts) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { TgtInfo::getTargetDefines(Opts, Builder); getOSDefines(Opts, TgtInfo::getTriple(), Builder); } }; // CloudABI Target template class CloudABITargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__CloudABI__"); Builder.defineMacro("__ELF__"); // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. Builder.defineMacro("__STDC_ISO_10646__", "201206L"); Builder.defineMacro("__STDC_UTF_16__"); Builder.defineMacro("__STDC_UTF_32__"); } public: CloudABITargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) {} }; static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, const llvm::Triple &Triple, StringRef &PlatformName, VersionTuple &PlatformMinVersion) { Builder.defineMacro("__APPLE_CC__", "6000"); Builder.defineMacro("__APPLE__"); Builder.defineMacro("OBJC_NEW_PROPERTIES"); // AddressSanitizer doesn't play well with source fortification, which is on // by default on Darwin. if (Opts.Sanitize.has(SanitizerKind::Address)) Builder.defineMacro("_FORTIFY_SOURCE", "0"); // Darwin defines __weak, __strong, and __unsafe_unretained even in C mode. if (!Opts.ObjC1) { // __weak is always defined, for use in blocks and with objc pointers. Builder.defineMacro("__weak", "__attribute__((objc_gc(weak)))"); Builder.defineMacro("__strong", ""); Builder.defineMacro("__unsafe_unretained", ""); } if (Opts.Static) Builder.defineMacro("__STATIC__"); else Builder.defineMacro("__DYNAMIC__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); // Get the platform type and version number from the triple. unsigned Maj, Min, Rev; if (Triple.isMacOSX()) { Triple.getMacOSXVersion(Maj, Min, Rev); PlatformName = "macos"; } else { Triple.getOSVersion(Maj, Min, Rev); PlatformName = llvm::Triple::getOSTypeName(Triple.getOS()); } // If -target arch-pc-win32-macho option specified, we're // generating code for Win32 ABI. No need to emit // __ENVIRONMENT_XX_OS_VERSION_MIN_REQUIRED__. if (PlatformName == "win32") { PlatformMinVersion = VersionTuple(Maj, Min, Rev); return; } // Set the appropriate OS version define. if (Triple.isiOS()) { assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[7]; if (Maj < 10) { Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); Str[2] = '0' + (Min % 10); Str[3] = '0' + (Rev / 10); Str[4] = '0' + (Rev % 10); Str[5] = '\0'; } else { // Handle versions >= 10. Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); Str[2] = '0' + (Min / 10); Str[3] = '0' + (Min % 10); Str[4] = '0' + (Rev / 10); Str[5] = '0' + (Rev % 10); Str[6] = '\0'; } if (Triple.isTvOS()) Builder.defineMacro("__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__", Str); else Builder.defineMacro("__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__", Str); } else if (Triple.isWatchOS()) { assert(Maj < 10 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[6]; Str[0] = '0' + Maj; Str[1] = '0' + (Min / 10); Str[2] = '0' + (Min % 10); Str[3] = '0' + (Rev / 10); Str[4] = '0' + (Rev % 10); Str[5] = '\0'; Builder.defineMacro("__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__", Str); } else if (Triple.isMacOSX()) { // Note that the Driver allows versions which aren't representable in the // define (because we only get a single digit for the minor and micro // revision numbers). So, we limit them to the maximum representable // version. assert(Maj < 100 && Min < 100 && Rev < 100 && "Invalid version!"); char Str[7]; if (Maj < 10 || (Maj == 10 && Min < 10)) { Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); Str[2] = '0' + std::min(Min, 9U); Str[3] = '0' + std::min(Rev, 9U); Str[4] = '\0'; } else { // Handle versions > 10.9. Str[0] = '0' + (Maj / 10); Str[1] = '0' + (Maj % 10); Str[2] = '0' + (Min / 10); Str[3] = '0' + (Min % 10); Str[4] = '0' + (Rev / 10); Str[5] = '0' + (Rev % 10); Str[6] = '\0'; } Builder.defineMacro("__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__", Str); } // Tell users about the kernel if there is one. if (Triple.isOSDarwin()) Builder.defineMacro("__MACH__"); // The Watch ABI uses Dwarf EH. if(Triple.isWatchABI()) Builder.defineMacro("__ARM_DWARF_EH__"); PlatformMinVersion = VersionTuple(Maj, Min, Rev); } template class DarwinTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { getDarwinDefines(Builder, Opts, Triple, this->PlatformName, this->PlatformMinVersion); } public: DarwinTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { // By default, no TLS, and we whitelist permitted architecture/OS // combinations. this->TLSSupported = false; if (Triple.isMacOSX()) this->TLSSupported = !Triple.isMacOSXVersionLT(10, 7); else if (Triple.isiOS()) { // 64-bit iOS supported it from 8 onwards, 32-bit from 9 onwards. if (Triple.getArch() == llvm::Triple::x86_64 || Triple.getArch() == llvm::Triple::aarch64) this->TLSSupported = !Triple.isOSVersionLT(8); else if (Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) this->TLSSupported = !Triple.isOSVersionLT(9); } else if (Triple.isWatchOS()) this->TLSSupported = !Triple.isOSVersionLT(2); this->MCountName = "\01mcount"; } std::string isValidSectionSpecifier(StringRef SR) const override { // Let MCSectionMachO validate this. StringRef Segment, Section; unsigned TAA, StubSize; bool HasTAA; return llvm::MCSectionMachO::ParseSectionSpecifier(SR, Segment, Section, TAA, HasTAA, StubSize); } const char *getStaticInitSectionSpecifier() const override { // FIXME: We should return 0 when building kexts. return "__TEXT,__StaticInit,regular,pure_instructions"; } /// Darwin does not support protected visibility. Darwin's "default" /// is very similar to ELF's "protected"; Darwin requires a "weak" /// attribute on declarations that can be dynamically replaced. bool hasProtectedVisibility() const override { return false; } unsigned getExnObjectAlignment() const override { // The alignment of an exception object is 8-bytes for darwin since // libc++abi doesn't declare _Unwind_Exception with __attribute__((aligned)) // and therefore doesn't guarantee 16-byte alignment. return 64; } }; // DragonFlyBSD Target template class DragonFlyBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // DragonFly defines; list based off of gcc output Builder.defineMacro("__DragonFly__"); Builder.defineMacro("__DragonFly_cc_version", "100001"); Builder.defineMacro("__ELF__"); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); Builder.defineMacro("__tune_i386__"); DefineStd(Builder, "unix", Opts); } public: DragonFlyBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; } } }; #ifndef FREEBSD_CC_VERSION #define FREEBSD_CC_VERSION 0U #endif // FreeBSD Target template class FreeBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // FreeBSD defines; list based off of gcc output unsigned Release = Triple.getOSMajorVersion(); if (Release == 0U) Release = 8U; unsigned CCVersion = FREEBSD_CC_VERSION; if (CCVersion == 0U) CCVersion = Release * 100000U + 1U; Builder.defineMacro("__FreeBSD__", Twine(Release)); Builder.defineMacro("__FreeBSD_cc_version", Twine(CCVersion)); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); // On FreeBSD, wchar_t contains the number of the code point as // used by the character set of the locale. These character sets are // not necessarily a superset of ASCII. // // FIXME: This is wrong; the macro refers to the numerical values // of wchar_t *literals*, which are not locale-dependent. However, // FreeBSD systems apparently depend on us getting this wrong, and // setting this to 1 is conforming even if all the basic source // character literals have the same encoding as char and wchar_t. Builder.defineMacro("__STDC_MB_MIGHT_NEQ_WC__", "1"); } public: FreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: this->MCountName = "_mcount"; break; case llvm::Triple::arm: this->MCountName = "__mcount"; break; } } }; // GNU/kFreeBSD Target template class KFreeBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // GNU/kFreeBSD defines; list based off of gcc output DefineStd(Builder, "unix", Opts); Builder.defineMacro("__FreeBSD_kernel__"); Builder.defineMacro("__GLIBC__"); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } public: KFreeBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) {} }; // Haiku Target template class HaikuTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Haiku defines; list based off of gcc output Builder.defineMacro("__HAIKU__"); Builder.defineMacro("__ELF__"); DefineStd(Builder, "unix", Opts); } public: HaikuTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->SizeType = TargetInfo::UnsignedLong; this->IntPtrType = TargetInfo::SignedLong; this->PtrDiffType = TargetInfo::SignedLong; this->ProcessIDType = TargetInfo::SignedLong; this->TLSSupported = false; } }; // Minix Target template class MinixTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Minix defines Builder.defineMacro("__minix", "3"); Builder.defineMacro("_EM_WSIZE", "4"); Builder.defineMacro("_EM_PSIZE", "4"); Builder.defineMacro("_EM_SSIZE", "2"); Builder.defineMacro("_EM_LSIZE", "4"); Builder.defineMacro("_EM_FSIZE", "4"); Builder.defineMacro("_EM_DSIZE", "8"); Builder.defineMacro("__ELF__"); DefineStd(Builder, "unix", Opts); } public: MinixTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) {} }; // Linux target template class LinuxTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Linux defines; list based off of gcc output DefineStd(Builder, "unix", Opts); DefineStd(Builder, "linux", Opts); Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); if (Triple.isAndroid()) { Builder.defineMacro("__ANDROID__", "1"); unsigned Maj, Min, Rev; Triple.getEnvironmentVersion(Maj, Min, Rev); this->PlatformName = "android"; this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); } if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); if (this->HasFloat128) Builder.defineMacro("__FLOAT128__"); } public: LinuxTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->WIntType = TargetInfo::UnsignedInt; switch (Triple.getArch()) { default: break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: this->MCountName = "_mcount"; break; case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::systemz: this->HasFloat128 = true; break; } } const char *getStaticInitSectionSpecifier() const override { return ".text.startup"; } }; // NetBSD Target template class NetBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // NetBSD defines; list based off of gcc output Builder.defineMacro("__NetBSD__"); Builder.defineMacro("__unix__"); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_POSIX_THREADS"); switch (Triple.getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: Builder.defineMacro("__ARM_DWARF_EH__"); break; } } public: NetBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->MCountName = "_mcount"; } }; // OpenBSD Target template class OpenBSDTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // OpenBSD defines; list based off of gcc output Builder.defineMacro("__OpenBSD__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); } public: OpenBSDTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->TLSSupported = false; switch (Triple.getArch()) { default: case llvm::Triple::x86: case llvm::Triple::x86_64: case llvm::Triple::arm: case llvm::Triple::sparc: this->MCountName = "__mcount"; break; case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::ppc: case llvm::Triple::sparcv9: this->MCountName = "_mcount"; break; } } }; // Bitrig Target template class BitrigTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // Bitrig defines; list based off of gcc output Builder.defineMacro("__Bitrig__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); switch (Triple.getArch()) { default: break; case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: Builder.defineMacro("__ARM_DWARF_EH__"); break; } } public: BitrigTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->MCountName = "__mcount"; } }; // PSP Target template class PSPTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // PSP defines; list based on the output of the pspdev gcc toolchain. Builder.defineMacro("PSP"); Builder.defineMacro("_PSP"); Builder.defineMacro("__psp__"); Builder.defineMacro("__ELF__"); } public: PSPTargetInfo(const llvm::Triple &Triple) : OSTargetInfo(Triple) {} }; // PS3 PPU Target template class PS3PPUTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // PS3 PPU defines. Builder.defineMacro("__PPC__"); Builder.defineMacro("__PPU__"); Builder.defineMacro("__CELLOS_LV2__"); Builder.defineMacro("__ELF__"); Builder.defineMacro("__LP32__"); Builder.defineMacro("_ARCH_PPC64"); Builder.defineMacro("__powerpc64__"); } public: PS3PPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->LongWidth = this->LongAlign = 32; this->PointerWidth = this->PointerAlign = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->SizeType = TargetInfo::UnsignedInt; this->resetDataLayout("E-m:e-p:32:32-i64:64-n32:64"); } }; template class PS4OSTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__FreeBSD__", "9"); Builder.defineMacro("__FreeBSD_cc_version", "900001"); Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__ORBIS__"); } public: PS4OSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->WCharType = this->UnsignedShort; // On PS4, TLS variable cannot be aligned to more than 32 bytes (256 bits). this->MaxTLSAlign = 256; // On PS4, do not honor explicit bit field alignment, // as in "__attribute__((aligned(2))) int b : 1;". this->UseExplicitBitFieldAlignment = false; switch (Triple.getArch()) { default: case llvm::Triple::x86_64: this->MCountName = ".mcount"; break; } } }; // Solaris target template class SolarisTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { DefineStd(Builder, "sun", Opts); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__svr4__"); Builder.defineMacro("__SVR4"); // Solaris headers require _XOPEN_SOURCE to be set to 600 for C99 and // newer, but to 500 for everything else. feature_test.h has a check to // ensure that you are not using C99 with an old version of X/Open or C89 // with a new version. if (Opts.C99) Builder.defineMacro("_XOPEN_SOURCE", "600"); else Builder.defineMacro("_XOPEN_SOURCE", "500"); if (Opts.CPlusPlus) Builder.defineMacro("__C99FEATURES__"); Builder.defineMacro("_LARGEFILE_SOURCE"); Builder.defineMacro("_LARGEFILE64_SOURCE"); Builder.defineMacro("__EXTENSIONS__"); Builder.defineMacro("_REENTRANT"); } public: SolarisTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->WCharType = this->SignedInt; // FIXME: WIntType should be SignedLong } }; // Windows target template class WindowsTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("_WIN32"); } void getVisualStudioDefines(const LangOptions &Opts, MacroBuilder &Builder) const { if (Opts.CPlusPlus) { if (Opts.RTTIData) Builder.defineMacro("_CPPRTTI"); if (Opts.CXXExceptions) Builder.defineMacro("_CPPUNWIND"); } if (Opts.Bool) Builder.defineMacro("__BOOL_DEFINED"); if (!Opts.CharIsSigned) Builder.defineMacro("_CHAR_UNSIGNED"); // FIXME: POSIXThreads isn't exactly the option this should be defined for, // but it works for now. if (Opts.POSIXThreads) Builder.defineMacro("_MT"); if (Opts.MSCompatibilityVersion) { Builder.defineMacro("_MSC_VER", Twine(Opts.MSCompatibilityVersion / 100000)); Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); // FIXME We cannot encode the revision information into 32-bits Builder.defineMacro("_MSC_BUILD", Twine(1)); if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { if (Opts.CPlusPlus1z) Builder.defineMacro("_MSVC_LANG", "201403L"); else if (Opts.CPlusPlus14) Builder.defineMacro("_MSVC_LANG", "201402L"); } } if (Opts.MicrosoftExt) { Builder.defineMacro("_MSC_EXTENSIONS"); if (Opts.CPlusPlus11) { Builder.defineMacro("_RVALUE_REFERENCES_V2_SUPPORTED"); Builder.defineMacro("_RVALUE_REFERENCES_SUPPORTED"); Builder.defineMacro("_NATIVE_NULLPTR_SUPPORTED"); } } Builder.defineMacro("_INTEGRAL_MAX_BITS", "64"); } public: WindowsTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) {} }; template class NaClTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); Builder.defineMacro("__native_client__"); } public: NaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->LongAlign = 32; this->LongWidth = 32; this->PointerAlign = 32; this->PointerWidth = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->DoubleAlign = 64; this->LongDoubleWidth = 64; this->LongDoubleAlign = 64; this->LongLongWidth = 64; this->LongLongAlign = 64; this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; // RegParmMax is inherited from the underlying architecture this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; if (Triple.getArch() == llvm::Triple::arm) { // Handled in ARM's setABI(). } else if (Triple.getArch() == llvm::Triple::x86) { this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32-S128"); } else if (Triple.getArch() == llvm::Triple::x86_64) { this->resetDataLayout("e-m:e-p:32:32-i64:64-n8:16:32:64-S128"); } else if (Triple.getArch() == llvm::Triple::mipsel) { // Handled on mips' setDataLayout. } else { assert(Triple.getArch() == llvm::Triple::le32); this->resetDataLayout("e-p:32:32-i64:64"); } } }; // WebAssembly target template class WebAssemblyOSTargetInfo : public OSTargetInfo { void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const final { // A common platform macro. if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); // Follow g++ convention and predefine _GNU_SOURCE for C++. if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } // As an optimization, group static init code together in a section. const char *getStaticInitSectionSpecifier() const final { return ".text.__startup"; } public: explicit WebAssemblyOSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { this->MCountName = "__mcount"; this->TheCXXABI.set(TargetCXXABI::WebAssembly); } }; //===----------------------------------------------------------------------===// // Specific target implementations. //===----------------------------------------------------------------------===// // PPC abstract base class class PPCTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; std::string CPU; // Target cpu features. bool HasVSX; bool HasP8Vector; bool HasP8Crypto; bool HasDirectMove; bool HasQPX; bool HasHTM; bool HasBPERMD; bool HasExtDiv; protected: std::string ABI; public: PPCTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), HasBPERMD(false), HasExtDiv(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); SimdDefaultAlign = 128; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; } /// \brief Flags for architecture specific defines. typedef enum { ArchDefineNone = 0, ArchDefineName = 1 << 0, // is substituted for arch name. ArchDefinePpcgr = 1 << 1, ArchDefinePpcsq = 1 << 2, ArchDefine440 = 1 << 3, ArchDefine603 = 1 << 4, ArchDefine604 = 1 << 5, ArchDefinePwr4 = 1 << 6, ArchDefinePwr5 = 1 << 7, ArchDefinePwr5x = 1 << 8, ArchDefinePwr6 = 1 << 9, ArchDefinePwr6x = 1 << 10, ArchDefinePwr7 = 1 << 11, ArchDefinePwr8 = 1 << 12, ArchDefinePwr9 = 1 << 13, ArchDefineA2 = 1 << 14, ArchDefineA2q = 1 << 15 } ArchDefineTypes; // Note: GCC recognizes the following additional cpus: // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, // titan, rs64. bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch(Name) .Case("generic", true) .Case("440", true) .Case("450", true) .Case("601", true) .Case("602", true) .Case("603", true) .Case("603e", true) .Case("603ev", true) .Case("604", true) .Case("604e", true) .Case("620", true) .Case("630", true) .Case("g3", true) .Case("7400", true) .Case("g4", true) .Case("7450", true) .Case("g4+", true) .Case("750", true) .Case("970", true) .Case("g5", true) .Case("a2", true) .Case("a2q", true) .Case("e500mc", true) .Case("e5500", true) .Case("power3", true) .Case("pwr3", true) .Case("power4", true) .Case("pwr4", true) .Case("power5", true) .Case("pwr5", true) .Case("power5x", true) .Case("pwr5x", true) .Case("power6", true) .Case("pwr6", true) .Case("power6x", true) .Case("pwr6x", true) .Case("power7", true) .Case("pwr7", true) .Case("power8", true) .Case("pwr8", true) .Case("power9", true) .Case("pwr9", true) .Case("powerpc", true) .Case("ppc", true) .Case("powerpc64", true) .Case("ppc64", true) .Case("powerpc64le", true) .Case("ppc64le", true) .Default(false); if (CPUKnown) CPU = Name; return CPUKnown; } StringRef getABI() const override { return ABI; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::PPC::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; bool hasFeature(StringRef Feature) const override; void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const override; ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'O': // Zero break; case 'b': // Base register case 'f': // Floating point register Info.setAllowsRegister(); break; // FIXME: The following are added to allow parsing. // I just took a guess at what the actions should be. // Also, is more specific checking needed? I.e. specific registers? case 'd': // Floating point register (containing 64-bit value) case 'v': // Altivec vector register Info.setAllowsRegister(); break; case 'w': switch (Name[1]) { case 'd':// VSX vector register to hold vector double data case 'f':// VSX vector register to hold vector float data case 's':// VSX vector register to hold scalar float data case 'a':// Any VSX register case 'c':// An individual CR bit break; default: return false; } Info.setAllowsRegister(); Name++; // Skip over 'w'. break; case 'h': // `MQ', `CTR', or `LINK' register case 'q': // `MQ' register case 'c': // `CTR' register case 'l': // `LINK' register case 'x': // `CR' register (condition register) number 0 case 'y': // `CR' register (condition register) case 'z': // `XER[CA]' carry bit (part of the XER register) Info.setAllowsRegister(); break; case 'I': // Signed 16-bit constant case 'J': // Unsigned 16-bit constant shifted left 16 bits // (use `L' instead for SImode constants) case 'K': // Unsigned 16-bit constant case 'L': // Signed 16-bit constant shifted left 16 bits case 'M': // Constant larger than 31 case 'N': // Exact power of 2 case 'P': // Constant whose negation is a signed 16-bit constant case 'G': // Floating point constant that can be loaded into a // register with one instruction per word case 'H': // Integer/Floating point constant that can be loaded // into a register using three instructions break; case 'm': // Memory operand. Note that on PowerPC targets, m can // include addresses that update the base register. It // is therefore only safe to use `m' in an asm statement // if that asm statement accesses the operand exactly once. // The asm statement must also use `%U' as a // placeholder for the "update" flag in the corresponding // load or store instruction. For example: // asm ("st%U0 %1,%0" : "=m" (mem) : "r" (val)); // is correct but: // asm ("st %1,%0" : "=m" (mem) : "r" (val)); // is not. Use es rather than m if you don't want the base // register to be updated. case 'e': if (Name[1] != 's') return false; // es: A "stable" memory operand; that is, one which does not // include any automodification of the base register. Unlike // `m', this constraint can be used in asm statements that // might access the operand several times, or that might not // access it at all. Info.setAllowsMemory(); Name++; // Skip over 'e'. break; case 'Q': // Memory operand that is an offset from a register (it is // usually better to use `m' or `es' in asm statements) case 'Z': // Memory operand that is an indexed or indirect from a // register (it is usually better to use `m' or `es' in // asm statements) Info.setAllowsMemory(); Info.setAllowsRegister(); break; case 'R': // AIX TOC entry case 'a': // Address operand that is an indexed or indirect from a // register (`p' is preferable for asm statements) case 'S': // Constant suitable as a 64-bit mask operand case 'T': // Constant suitable as a 32-bit mask operand case 'U': // System V Release 4 small data area reference case 't': // AND masks that can be performed by two rldic{l, r} // instructions case 'W': // Vector constant that does not require memory case 'j': // Vector constant that is all zeros. break; // End FIXME. } return true; } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'e': case 'w': // Two-character constraint; add "^" hint for later parsing. R = std::string("^") + std::string(Constraint, 2); Constraint++; break; default: return TargetInfo::convertConstraint(Constraint); } return R; } const char *getClobbers() const override { return ""; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 3; if (RegNo == 1) return 4; return -1; } bool hasSjLjLowering() const override { return true; } bool useFloat128ManglingForLongDouble() const override { return LongDoubleWidth == 128 && LongDoubleFormat == &llvm::APFloat::PPCDoubleDouble && getTriple().isOSBinFormatELF(); } }; const Builtin::Info PPCTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsPPC.def" }; /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. bool PPCTargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (const auto &Feature : Features) { if (Feature == "+vsx") { HasVSX = true; } else if (Feature == "+bpermd") { HasBPERMD = true; } else if (Feature == "+extdiv") { HasExtDiv = true; } else if (Feature == "+power8-vector") { HasP8Vector = true; } else if (Feature == "+crypto") { HasP8Crypto = true; } else if (Feature == "+direct-move") { HasDirectMove = true; } else if (Feature == "+qpx") { HasQPX = true; } else if (Feature == "+htm") { HasHTM = true; } else if (Feature == "+float128") { HasFloat128 = true; } // TODO: Finish this list and add an assert that we've handled them // all. } return true; } /// PPCTargetInfo::getTargetDefines - Return a set of the PowerPC-specific /// #defines that are not tied to a specific subtarget. void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. Builder.defineMacro("__ppc__"); Builder.defineMacro("__PPC__"); Builder.defineMacro("_ARCH_PPC"); Builder.defineMacro("__powerpc__"); Builder.defineMacro("__POWERPC__"); if (PointerWidth == 64) { Builder.defineMacro("_ARCH_PPC64"); Builder.defineMacro("__powerpc64__"); Builder.defineMacro("__ppc64__"); Builder.defineMacro("__PPC64__"); } // Target properties. if (getTriple().getArch() == llvm::Triple::ppc64le) { Builder.defineMacro("_LITTLE_ENDIAN"); } else { if (getTriple().getOS() != llvm::Triple::NetBSD && getTriple().getOS() != llvm::Triple::OpenBSD) Builder.defineMacro("_BIG_ENDIAN"); } // ABI options. if (ABI == "elfv1" || ABI == "elfv1-qpx") Builder.defineMacro("_CALL_ELF", "1"); if (ABI == "elfv2") Builder.defineMacro("_CALL_ELF", "2"); // Subtarget options. Builder.defineMacro("__NATURAL_ALIGNMENT__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); // FIXME: Should be controlled by command line option. if (LongDoubleWidth == 128) Builder.defineMacro("__LONG_DOUBLE_128__"); if (Opts.AltiVec) { Builder.defineMacro("__VEC__", "10206"); Builder.defineMacro("__ALTIVEC__"); } // CPU identification. ArchDefineTypes defs = (ArchDefineTypes)llvm::StringSwitch(CPU) .Case("440", ArchDefineName) .Case("450", ArchDefineName | ArchDefine440) .Case("601", ArchDefineName) .Case("602", ArchDefineName | ArchDefinePpcgr) .Case("603", ArchDefineName | ArchDefinePpcgr) .Case("603e", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) .Case("603ev", ArchDefineName | ArchDefine603 | ArchDefinePpcgr) .Case("604", ArchDefineName | ArchDefinePpcgr) .Case("604e", ArchDefineName | ArchDefine604 | ArchDefinePpcgr) .Case("620", ArchDefineName | ArchDefinePpcgr) .Case("630", ArchDefineName | ArchDefinePpcgr) .Case("7400", ArchDefineName | ArchDefinePpcgr) .Case("7450", ArchDefineName | ArchDefinePpcgr) .Case("750", ArchDefineName | ArchDefinePpcgr) .Case("970", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("a2", ArchDefineA2) .Case("a2q", ArchDefineName | ArchDefineA2 | ArchDefineA2q) .Case("pwr3", ArchDefinePpcgr) .Case("pwr4", ArchDefineName | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr5", ArchDefineName | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr5x", ArchDefineName | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr6", ArchDefineName | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr6x", ArchDefineName | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr7", ArchDefineName | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr8", ArchDefineName | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("pwr9", ArchDefineName | ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power3", ArchDefinePpcgr) .Case("power4", ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power5", ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power5x", ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power6", ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power6x", ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power7", ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power8", ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Case("power9", ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6x | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) .Default(ArchDefineNone); if (defs & ArchDefineName) Builder.defineMacro(Twine("_ARCH_", StringRef(CPU).upper())); if (defs & ArchDefinePpcgr) Builder.defineMacro("_ARCH_PPCGR"); if (defs & ArchDefinePpcsq) Builder.defineMacro("_ARCH_PPCSQ"); if (defs & ArchDefine440) Builder.defineMacro("_ARCH_440"); if (defs & ArchDefine603) Builder.defineMacro("_ARCH_603"); if (defs & ArchDefine604) Builder.defineMacro("_ARCH_604"); if (defs & ArchDefinePwr4) Builder.defineMacro("_ARCH_PWR4"); if (defs & ArchDefinePwr5) Builder.defineMacro("_ARCH_PWR5"); if (defs & ArchDefinePwr5x) Builder.defineMacro("_ARCH_PWR5X"); if (defs & ArchDefinePwr6) Builder.defineMacro("_ARCH_PWR6"); if (defs & ArchDefinePwr6x) Builder.defineMacro("_ARCH_PWR6X"); if (defs & ArchDefinePwr7) Builder.defineMacro("_ARCH_PWR7"); if (defs & ArchDefinePwr8) Builder.defineMacro("_ARCH_PWR8"); if (defs & ArchDefinePwr9) Builder.defineMacro("_ARCH_PWR9"); if (defs & ArchDefineA2) Builder.defineMacro("_ARCH_A2"); if (defs & ArchDefineA2q) { Builder.defineMacro("_ARCH_A2Q"); Builder.defineMacro("_ARCH_QP"); } if (getTriple().getVendor() == llvm::Triple::BGQ) { Builder.defineMacro("__bg__"); Builder.defineMacro("__THW_BLUEGENE__"); Builder.defineMacro("__bgq__"); Builder.defineMacro("__TOS_BGQ__"); } if (HasVSX) Builder.defineMacro("__VSX__"); if (HasP8Vector) Builder.defineMacro("__POWER8_VECTOR__"); if (HasP8Crypto) Builder.defineMacro("__CRYPTO__"); if (HasHTM) Builder.defineMacro("__HTM__"); if (HasFloat128) Builder.defineMacro("__FLOAT128__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); if (PointerWidth == 64) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); // FIXME: The following are not yet generated here by Clang, but are // generated by GCC: // // _SOFT_FLOAT_ // __RECIP_PRECISION__ // __APPLE_ALTIVEC__ // __RECIP__ // __RECIPF__ // __RSQRTE__ // __RSQRTEF__ // _SOFT_DOUBLE_ // __NO_LWSYNC__ // __HAVE_BSWAP__ // __LONGDOUBLE128 // __CMODEL_MEDIUM__ // __CMODEL_LARGE__ // _CALL_SYSV // _CALL_DARWIN // __NO_FPRS__ } // Handle explicit options being passed to the compiler here: if we've // explicitly turned off vsx and turned on power8-vector or direct-move then // go ahead and error since the customer has expressed a somewhat incompatible // set of options. static bool ppcUserFeaturesCheck(DiagnosticsEngine &Diags, const std::vector &FeaturesVec) { if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "-vsx") != FeaturesVec.end()) { if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+power8-vector") != FeaturesVec.end()) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mpower8-vector" << "-mno-vsx"; return false; } if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+direct-move") != FeaturesVec.end()) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mdirect-move" << "-mno-vsx"; return false; } if (std::find(FeaturesVec.begin(), FeaturesVec.end(), "+float128") != FeaturesVec.end()) { Diags.Report(diag::err_opt_not_valid_with_opt) << "-mfloat128" << "-mno-vsx"; return false; } } return true; } bool PPCTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { Features["altivec"] = llvm::StringSwitch(CPU) .Case("7400", true) .Case("g4", true) .Case("7450", true) .Case("g4+", true) .Case("970", true) .Case("g5", true) .Case("pwr6", true) .Case("pwr7", true) .Case("pwr8", true) .Case("pwr9", true) .Case("ppc64", true) .Case("ppc64le", true) .Default(false); Features["qpx"] = (CPU == "a2q"); Features["crypto"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Default(false); Features["power8-vector"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Default(false); Features["bpermd"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); Features["extdiv"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); Features["direct-move"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Default(false); Features["vsx"] = llvm::StringSwitch(CPU) .Case("ppc64le", true) .Case("pwr9", true) .Case("pwr8", true) .Case("pwr7", true) .Default(false); if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) return false; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("powerpc", true) .Case("vsx", HasVSX) .Case("power8-vector", HasP8Vector) .Case("crypto", HasP8Crypto) .Case("direct-move", HasDirectMove) .Case("qpx", HasQPX) .Case("htm", HasHTM) .Case("bpermd", HasBPERMD) .Case("extdiv", HasExtDiv) .Case("float128", HasFloat128) .Default(false); } void PPCTargetInfo::setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const { // If we're enabling direct-move or power8-vector go ahead and enable vsx // as well. Do the inverse if we're disabling vsx. We'll diagnose any user // incompatible options. if (Enabled) { if (Name == "direct-move") { Features[Name] = Features["vsx"] = true; } else if (Name == "power8-vector") { Features[Name] = Features["vsx"] = true; } else if (Name == "float128") { Features[Name] = Features["vsx"] = true; } else { Features[Name] = true; } } else { if (Name == "vsx") { Features[Name] = Features["direct-move"] = Features["power8-vector"] = Features["float128"] = false; } else { Features[Name] = false; } } } const char * const PPCTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", "mq", "lr", "ctr", "ap", "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", "xer", "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "vrsave", "vscr", "spe_acc", "spefscr", "sfp" }; ArrayRef PPCTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias PPCTargetInfo::GCCRegAliases[] = { // While some of these aliases do map to different registers // they still share the same register name. { { "0" }, "r0" }, { { "1"}, "r1" }, { { "2" }, "r2" }, { { "3" }, "r3" }, { { "4" }, "r4" }, { { "5" }, "r5" }, { { "6" }, "r6" }, { { "7" }, "r7" }, { { "8" }, "r8" }, { { "9" }, "r9" }, { { "10" }, "r10" }, { { "11" }, "r11" }, { { "12" }, "r12" }, { { "13" }, "r13" }, { { "14" }, "r14" }, { { "15" }, "r15" }, { { "16" }, "r16" }, { { "17" }, "r17" }, { { "18" }, "r18" }, { { "19" }, "r19" }, { { "20" }, "r20" }, { { "21" }, "r21" }, { { "22" }, "r22" }, { { "23" }, "r23" }, { { "24" }, "r24" }, { { "25" }, "r25" }, { { "26" }, "r26" }, { { "27" }, "r27" }, { { "28" }, "r28" }, { { "29" }, "r29" }, { { "30" }, "r30" }, { { "31" }, "r31" }, { { "fr0" }, "f0" }, { { "fr1" }, "f1" }, { { "fr2" }, "f2" }, { { "fr3" }, "f3" }, { { "fr4" }, "f4" }, { { "fr5" }, "f5" }, { { "fr6" }, "f6" }, { { "fr7" }, "f7" }, { { "fr8" }, "f8" }, { { "fr9" }, "f9" }, { { "fr10" }, "f10" }, { { "fr11" }, "f11" }, { { "fr12" }, "f12" }, { { "fr13" }, "f13" }, { { "fr14" }, "f14" }, { { "fr15" }, "f15" }, { { "fr16" }, "f16" }, { { "fr17" }, "f17" }, { { "fr18" }, "f18" }, { { "fr19" }, "f19" }, { { "fr20" }, "f20" }, { { "fr21" }, "f21" }, { { "fr22" }, "f22" }, { { "fr23" }, "f23" }, { { "fr24" }, "f24" }, { { "fr25" }, "f25" }, { { "fr26" }, "f26" }, { { "fr27" }, "f27" }, { { "fr28" }, "f28" }, { { "fr29" }, "f29" }, { { "fr30" }, "f30" }, { { "fr31" }, "f31" }, { { "cc" }, "cr0" }, }; ArrayRef PPCTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } class PPC32TargetInfo : public PPCTargetInfo { public: PPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : PPCTargetInfo(Triple, Opts) { resetDataLayout("E-m:e-p:32:32-i64:64-n32"); switch (getTriple().getOS()) { case llvm::Triple::Linux: case llvm::Triple::FreeBSD: case llvm::Triple::NetBSD: SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; break; default: break; } if (getTriple().getOS() == llvm::Triple::FreeBSD) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } // PPC32 supports atomics up to 4 bytes. MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; } BuiltinVaListKind getBuiltinVaListKind() const override { // This is the ELF definition, and is overridden by the Darwin sub-target return TargetInfo::PowerABIBuiltinVaList; } }; // Note: ABI differences may eventually require us to have a separate // TargetInfo for little endian. class PPC64TargetInfo : public PPCTargetInfo { public: PPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : PPCTargetInfo(Triple, Opts) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; IntMaxType = SignedLong; Int64Type = SignedLong; if ((Triple.getArch() == llvm::Triple::ppc64le)) { resetDataLayout("e-m:e-i64:64-n32:64"); ABI = "elfv2"; } else { resetDataLayout("E-m:e-i64:64-n32:64"); ABI = "elfv1"; } switch (getTriple().getOS()) { case llvm::Triple::FreeBSD: LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; break; case llvm::Triple::NetBSD: IntMaxType = SignedLongLong; Int64Type = SignedLongLong; break; default: break; } // PPC64 supports atomics up to 8 bytes. MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } // PPC64 Linux-specific ABI options. bool setABI(const std::string &Name) override { if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { ABI = Name; return true; } return false; } }; class DarwinPPC32TargetInfo : public DarwinTargetInfo { public: DarwinPPC32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { HasAlignMac68kSupport = true; BoolWidth = BoolAlign = 32; //XXX support -mone-byte-bool? PtrDiffType = SignedInt; // for http://llvm.org/bugs/show_bug.cgi?id=15726 LongLongAlign = 32; SuitableAlign = 128; resetDataLayout("E-m:o-p:32:32-f64:32:64-n32"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } }; class DarwinPPC64TargetInfo : public DarwinTargetInfo { public: DarwinPPC64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { HasAlignMac68kSupport = true; SuitableAlign = 128; resetDataLayout("E-m:o-i64:64-n32:64"); } }; static const unsigned NVPTXAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 4, // opencl_constant // FIXME: generic has to be added to the target 0, // opencl_generic 1, // cuda_device 4, // cuda_constant 3, // cuda_shared }; class NVPTXTargetInfo : public TargetInfo { static const char *const GCCRegNames[]; static const Builtin::Info BuiltinInfo[]; CudaArch GPU; public: NVPTXTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple) { BigEndian = false; TLSSupported = false; LongWidth = LongAlign = 64; AddrSpaceMap = &NVPTXAddrSpaceMap; UseAddrSpaceMapMangling = true; // Define available target features // These must be defined in sorted order! NoAsmVariants = true; GPU = CudaArch::SM_20; // If possible, get a TargetInfo for our host triple, so we can match its // types. llvm::Triple HostTriple(Opts.HostTriple); if (HostTriple.isNVPTX()) return; std::unique_ptr HostTarget( AllocateTarget(llvm::Triple(Opts.HostTriple), Opts)); if (!HostTarget) { return; } PointerWidth = HostTarget->getPointerWidth(/* AddrSpace = */ 0); PointerAlign = HostTarget->getPointerAlign(/* AddrSpace = */ 0); BoolWidth = HostTarget->getBoolWidth(); BoolAlign = HostTarget->getBoolAlign(); IntWidth = HostTarget->getIntWidth(); IntAlign = HostTarget->getIntAlign(); HalfWidth = HostTarget->getHalfWidth(); HalfAlign = HostTarget->getHalfAlign(); FloatWidth = HostTarget->getFloatWidth(); FloatAlign = HostTarget->getFloatAlign(); DoubleWidth = HostTarget->getDoubleWidth(); DoubleAlign = HostTarget->getDoubleAlign(); LongWidth = HostTarget->getLongWidth(); LongAlign = HostTarget->getLongAlign(); LongLongWidth = HostTarget->getLongLongWidth(); LongLongAlign = HostTarget->getLongLongAlign(); MinGlobalAlign = HostTarget->getMinGlobalAlign(); DefaultAlignForAttributeAligned = HostTarget->getDefaultAlignForAttributeAligned(); SizeType = HostTarget->getSizeType(); IntMaxType = HostTarget->getIntMaxType(); PtrDiffType = HostTarget->getPtrDiffType(/* AddrSpace = */ 0); IntPtrType = HostTarget->getIntPtrType(); WCharType = HostTarget->getWCharType(); WIntType = HostTarget->getWIntType(); Char16Type = HostTarget->getChar16Type(); Char32Type = HostTarget->getChar32Type(); Int64Type = HostTarget->getInt64Type(); SigAtomicType = HostTarget->getSigAtomicType(); ProcessIDType = HostTarget->getProcessIDType(); UseBitFieldTypeAlignment = HostTarget->useBitFieldTypeAlignment(); UseZeroLengthBitfieldAlignment = HostTarget->useZeroLengthBitfieldAlignment(); UseExplicitBitFieldAlignment = HostTarget->useExplicitBitFieldAlignment(); ZeroLengthBitfieldBoundary = HostTarget->getZeroLengthBitfieldBoundary(); // Properties intentionally not copied from host: // - LargeArrayMinWidth, LargeArrayAlign: Not visible across the // host/device boundary. // - SuitableAlign: Not visible across the host/device boundary, and may // correctly be different on host/device, e.g. if host has wider vector // types than device. // - LongDoubleWidth, LongDoubleAlign: nvptx's long double type is the same // as its double type, but that's not necessarily true on the host. // TODO: nvcc emits a warning when using long double on device; we should // do the same. } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__PTX__"); Builder.defineMacro("__NVPTX__"); if (Opts.CUDAIsDevice) { // Set __CUDA_ARCH__ for the GPU specified. std::string CUDAArchCode = [this] { switch (GPU) { case CudaArch::UNKNOWN: assert(false && "No GPU arch when compiling CUDA device code."); return ""; case CudaArch::SM_20: return "200"; case CudaArch::SM_21: return "210"; case CudaArch::SM_30: return "300"; case CudaArch::SM_32: return "320"; case CudaArch::SM_35: return "350"; case CudaArch::SM_37: return "370"; case CudaArch::SM_50: return "500"; case CudaArch::SM_52: return "520"; case CudaArch::SM_53: return "530"; case CudaArch::SM_60: return "600"; case CudaArch::SM_61: return "610"; case CudaArch::SM_62: return "620"; } llvm_unreachable("unhandled CudaArch"); }(); Builder.defineMacro("__CUDA_ARCH__", CUDAArchCode); } } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::NVPTX::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return Feature == "ptx" || Feature == "nvptx"; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'c': case 'h': case 'r': case 'l': case 'f': case 'd': Info.setAllowsRegister(); return true; } } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { // FIXME: implement return TargetInfo::CharPtrBuiltinVaList; } bool setCPU(const std::string &Name) override { GPU = StringToCudaArch(Name); return GPU != CudaArch::UNKNOWN; } void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); Opts.cl_clang_storage_class_specifiers = 1; Opts.cl_khr_gl_sharing = 1; Opts.cl_khr_icd = 1; Opts.cl_khr_fp64 = 1; Opts.cl_khr_byte_addressable_store = 1; Opts.cl_khr_global_int32_base_atomics = 1; Opts.cl_khr_global_int32_extended_atomics = 1; Opts.cl_khr_local_int32_base_atomics = 1; Opts.cl_khr_local_int32_extended_atomics = 1; } }; const Builtin::Info NVPTXTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNVPTX.def" }; const char *const NVPTXTargetInfo::GCCRegNames[] = {"r0"}; ArrayRef NVPTXTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } class NVPTX32TargetInfo : public NVPTXTargetInfo { public: NVPTX32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : NVPTXTargetInfo(Triple, Opts) { LongWidth = LongAlign = 32; PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = TargetInfo::SignedInt; IntPtrType = TargetInfo::SignedInt; resetDataLayout("e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"); } }; class NVPTX64TargetInfo : public NVPTXTargetInfo { public: NVPTX64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : NVPTXTargetInfo(Triple, Opts) { PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = TargetInfo::SignedLong; IntPtrType = TargetInfo::SignedLong; resetDataLayout("e-i64:64-v16:16-v32:32-n16:32:64"); } }; static const unsigned AMDGPUAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 2, // opencl_constant 4, // opencl_generic 1, // cuda_device 2, // cuda_constant 3 // cuda_shared }; // If you edit the description strings, make sure you update // getPointerWidthV(). static const char *const DataLayoutStringR600 = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; static const char *const DataLayoutStringSI = "e-p:32:32-p1:64:64-p2:64:64-p3:32:32-p4:64:64-p5:32:32" "-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128" "-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64"; class AMDGPUTargetInfo final : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; /// \brief The GPU profiles supported by the AMDGPU target. enum GPUKind { GK_NONE, GK_R600, GK_R600_DOUBLE_OPS, GK_R700, GK_R700_DOUBLE_OPS, GK_EVERGREEN, GK_EVERGREEN_DOUBLE_OPS, GK_NORTHERN_ISLANDS, GK_CAYMAN, GK_SOUTHERN_ISLANDS, GK_SEA_ISLANDS, GK_VOLCANIC_ISLANDS } GPU; bool hasFP64:1; bool hasFMAF:1; bool hasLDEXPF:1; static bool isAMDGCN(const llvm::Triple &TT) { return TT.getArch() == llvm::Triple::amdgcn; } public: AMDGPUTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) , GPU(isAMDGCN(Triple) ? GK_SOUTHERN_ISLANDS : GK_R600), hasFP64(false), hasFMAF(false), hasLDEXPF(false) { if (getTriple().getArch() == llvm::Triple::amdgcn) { hasFP64 = true; hasFMAF = true; hasLDEXPF = true; } resetDataLayout(getTriple().getArch() == llvm::Triple::amdgcn ? DataLayoutStringSI : DataLayoutStringR600); AddrSpaceMap = &AMDGPUAddrSpaceMap; UseAddrSpaceMapMangling = true; } uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (GPU <= GK_CAYMAN) return 32; switch(AddrSpace) { default: return 64; case 0: case 3: case 5: return 32; } } const char * getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: break; case 'v': // vgpr case 's': // sgpr Info.setAllowsRegister(); return true; } return false; } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeatureVec) const override; ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::AMDGPU::LastTSBuiltin - Builtin::FirstTSBuiltin); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { if (getTriple().getArch() == llvm::Triple::amdgcn) Builder.defineMacro("__AMDGCN__"); else Builder.defineMacro("__R600__"); if (hasFMAF) Builder.defineMacro("__HAS_FMAF__"); if (hasLDEXPF) Builder.defineMacro("__HAS_LDEXPF__"); if (hasFP64) Builder.defineMacro("__HAS_FP64__"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } static GPUKind parseR600Name(StringRef Name) { return llvm::StringSwitch(Name) .Case("r600" , GK_R600) .Case("rv610", GK_R600) .Case("rv620", GK_R600) .Case("rv630", GK_R600) .Case("rv635", GK_R600) .Case("rs780", GK_R600) .Case("rs880", GK_R600) .Case("rv670", GK_R600_DOUBLE_OPS) .Case("rv710", GK_R700) .Case("rv730", GK_R700) .Case("rv740", GK_R700_DOUBLE_OPS) .Case("rv770", GK_R700_DOUBLE_OPS) .Case("palm", GK_EVERGREEN) .Case("cedar", GK_EVERGREEN) .Case("sumo", GK_EVERGREEN) .Case("sumo2", GK_EVERGREEN) .Case("redwood", GK_EVERGREEN) .Case("juniper", GK_EVERGREEN) .Case("hemlock", GK_EVERGREEN_DOUBLE_OPS) .Case("cypress", GK_EVERGREEN_DOUBLE_OPS) .Case("barts", GK_NORTHERN_ISLANDS) .Case("turks", GK_NORTHERN_ISLANDS) .Case("caicos", GK_NORTHERN_ISLANDS) .Case("cayman", GK_CAYMAN) .Case("aruba", GK_CAYMAN) .Default(GK_NONE); } static GPUKind parseAMDGCNName(StringRef Name) { return llvm::StringSwitch(Name) - .Case("tahiti", GK_SOUTHERN_ISLANDS) - .Case("pitcairn", GK_SOUTHERN_ISLANDS) - .Case("verde", GK_SOUTHERN_ISLANDS) - .Case("oland", GK_SOUTHERN_ISLANDS) - .Case("hainan", GK_SOUTHERN_ISLANDS) - .Case("bonaire", GK_SEA_ISLANDS) - .Case("kabini", GK_SEA_ISLANDS) - .Case("kaveri", GK_SEA_ISLANDS) - .Case("hawaii", GK_SEA_ISLANDS) - .Case("mullins", GK_SEA_ISLANDS) - .Case("tonga", GK_VOLCANIC_ISLANDS) - .Case("iceland", GK_VOLCANIC_ISLANDS) - .Case("carrizo", GK_VOLCANIC_ISLANDS) - .Case("fiji", GK_VOLCANIC_ISLANDS) - .Case("stoney", GK_VOLCANIC_ISLANDS) + .Case("tahiti", GK_SOUTHERN_ISLANDS) + .Case("pitcairn", GK_SOUTHERN_ISLANDS) + .Case("verde", GK_SOUTHERN_ISLANDS) + .Case("oland", GK_SOUTHERN_ISLANDS) + .Case("hainan", GK_SOUTHERN_ISLANDS) + .Case("bonaire", GK_SEA_ISLANDS) + .Case("kabini", GK_SEA_ISLANDS) + .Case("kaveri", GK_SEA_ISLANDS) + .Case("hawaii", GK_SEA_ISLANDS) + .Case("mullins", GK_SEA_ISLANDS) + .Case("tonga", GK_VOLCANIC_ISLANDS) + .Case("iceland", GK_VOLCANIC_ISLANDS) + .Case("carrizo", GK_VOLCANIC_ISLANDS) + .Case("fiji", GK_VOLCANIC_ISLANDS) + .Case("stoney", GK_VOLCANIC_ISLANDS) + .Case("polaris10", GK_VOLCANIC_ISLANDS) + .Case("polaris11", GK_VOLCANIC_ISLANDS) .Default(GK_NONE); } bool setCPU(const std::string &Name) override { if (getTriple().getArch() == llvm::Triple::amdgcn) GPU = parseAMDGCNName(Name); else GPU = parseR600Name(Name); return GPU != GK_NONE; } void setSupportedOpenCLOpts() override { auto &Opts = getSupportedOpenCLOpts(); Opts.cl_clang_storage_class_specifiers = 1; Opts.cl_khr_icd = 1; if (hasFP64) Opts.cl_khr_fp64 = 1; if (GPU >= GK_EVERGREEN) { Opts.cl_khr_byte_addressable_store = 1; Opts.cl_khr_global_int32_base_atomics = 1; Opts.cl_khr_global_int32_extended_atomics = 1; Opts.cl_khr_local_int32_base_atomics = 1; Opts.cl_khr_local_int32_extended_atomics = 1; } if (GPU >= GK_SOUTHERN_ISLANDS) { Opts.cl_khr_fp16 = 1; Opts.cl_khr_int64_base_atomics = 1; Opts.cl_khr_int64_extended_atomics = 1; Opts.cl_khr_3d_image_writes = 1; } } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { default: return CCCR_Warning; case CC_C: case CC_OpenCLKernel: return CCCR_OK; } } }; const Builtin::Info AMDGPUTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, #include "clang/Basic/BuiltinsAMDGPU.def" }; const char * const AMDGPUTargetInfo::GCCRegNames[] = { "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39", "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47", "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55", "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63", "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87", "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95", "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103", "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111", "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119", "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127", "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135", "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159", "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167", "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175", "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183", "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191", "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199", "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207", "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231", "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239", "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247", "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55", "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63", "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71", "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79", "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87", "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95", "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119", "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127", "exec", "vcc", "scc", "m0", "flat_scratch", "exec_lo", "exec_hi", "vcc_lo", "vcc_hi", "flat_scratch_lo", "flat_scratch_hi" }; ArrayRef AMDGPUTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } bool AMDGPUTargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeatureVec) const { // XXX - What does the member GPU mean if device name string passed here? if (getTriple().getArch() == llvm::Triple::amdgcn) { if (CPU.empty()) CPU = "tahiti"; switch (parseAMDGCNName(CPU)) { case GK_SOUTHERN_ISLANDS: case GK_SEA_ISLANDS: break; case GK_VOLCANIC_ISLANDS: Features["s-memrealtime"] = true; Features["16-bit-insts"] = true; break; case GK_NONE: return false; default: llvm_unreachable("unhandled subtarget"); } } else { if (CPU.empty()) CPU = "r600"; switch (parseR600Name(CPU)) { case GK_R600: case GK_R700: case GK_EVERGREEN: case GK_NORTHERN_ISLANDS: break; case GK_R600_DOUBLE_OPS: case GK_R700_DOUBLE_OPS: case GK_EVERGREEN_DOUBLE_OPS: case GK_CAYMAN: Features["fp64"] = true; break; case GK_NONE: return false; default: llvm_unreachable("unhandled subtarget"); } } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeatureVec); } // Namespace for x86 abstract base class const Builtin::Info BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, #include "clang/Basic/BuiltinsX86.def" }; static const char* const GCCRegNames[] = { "ax", "dx", "cx", "bx", "si", "di", "bp", "sp", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "argp", "flags", "fpcr", "fpsr", "dirflag", "frame", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", "xmm16", "xmm17", "xmm18", "xmm19", "xmm20", "xmm21", "xmm22", "xmm23", "xmm24", "xmm25", "xmm26", "xmm27", "xmm28", "xmm29", "xmm30", "xmm31", "ymm16", "ymm17", "ymm18", "ymm19", "ymm20", "ymm21", "ymm22", "ymm23", "ymm24", "ymm25", "ymm26", "ymm27", "ymm28", "ymm29", "ymm30", "ymm31", "zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31", }; const TargetInfo::AddlRegName AddlRegNames[] = { { { "al", "ah", "eax", "rax" }, 0 }, { { "bl", "bh", "ebx", "rbx" }, 3 }, { { "cl", "ch", "ecx", "rcx" }, 2 }, { { "dl", "dh", "edx", "rdx" }, 1 }, { { "esi", "rsi" }, 4 }, { { "edi", "rdi" }, 5 }, { { "esp", "rsp" }, 7 }, { { "ebp", "rbp" }, 6 }, { { "r8d", "r8w", "r8b" }, 38 }, { { "r9d", "r9w", "r9b" }, 39 }, { { "r10d", "r10w", "r10b" }, 40 }, { { "r11d", "r11w", "r11b" }, 41 }, { { "r12d", "r12w", "r12b" }, 42 }, { { "r13d", "r13w", "r13b" }, 43 }, { { "r14d", "r14w", "r14b" }, 44 }, { { "r15d", "r15w", "r15b" }, 45 }, }; // X86 target abstract base class; x86-32 and x86-64 are very close, so // most of the implementation can be shared. class X86TargetInfo : public TargetInfo { enum X86SSEEnum { NoSSE, SSE1, SSE2, SSE3, SSSE3, SSE41, SSE42, AVX, AVX2, AVX512F } SSELevel = NoSSE; enum MMX3DNowEnum { NoMMX3DNow, MMX, AMD3DNow, AMD3DNowAthlon } MMX3DNowLevel = NoMMX3DNow; enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP; bool HasAES = false; bool HasPCLMUL = false; bool HasLZCNT = false; bool HasRDRND = false; bool HasFSGSBASE = false; bool HasBMI = false; bool HasBMI2 = false; bool HasPOPCNT = false; bool HasRTM = false; bool HasPRFCHW = false; bool HasRDSEED = false; bool HasADX = false; bool HasTBM = false; bool HasFMA = false; bool HasF16C = false; bool HasAVX512CD = false; bool HasAVX512ER = false; bool HasAVX512PF = false; bool HasAVX512DQ = false; bool HasAVX512BW = false; bool HasAVX512VL = false; bool HasAVX512VBMI = false; bool HasAVX512IFMA = false; bool HasSHA = false; bool HasMPX = false; bool HasSGX = false; bool HasCX16 = false; bool HasFXSR = false; bool HasXSAVE = false; bool HasXSAVEOPT = false; bool HasXSAVEC = false; bool HasXSAVES = false; bool HasMWAITX = false; bool HasPKU = false; bool HasCLFLUSHOPT = false; bool HasPCOMMIT = false; bool HasCLWB = false; bool HasUMIP = false; bool HasMOVBE = false; bool HasPREFETCHWT1 = false; /// \brief Enumeration of all of the X86 CPUs supported by Clang. /// /// Each enumeration represents a particular CPU supported by Clang. These /// loosely correspond to the options passed to '-march' or '-mtune' flags. enum CPUKind { CK_Generic, /// \name i386 /// i386-generation processors. //@{ CK_i386, //@} /// \name i486 /// i486-generation processors. //@{ CK_i486, CK_WinChipC6, CK_WinChip2, CK_C3, //@} /// \name i586 /// i586-generation processors, P5 microarchitecture based. //@{ CK_i586, CK_Pentium, CK_PentiumMMX, //@} /// \name i686 /// i686-generation processors, P6 / Pentium M microarchitecture based. //@{ CK_i686, CK_PentiumPro, CK_Pentium2, CK_Pentium3, CK_Pentium3M, CK_PentiumM, CK_C3_2, /// This enumerator is a bit odd, as GCC no longer accepts -march=yonah. /// Clang however has some logic to suport this. // FIXME: Warn, deprecate, and potentially remove this. CK_Yonah, //@} /// \name Netburst /// Netburst microarchitecture based processors. //@{ CK_Pentium4, CK_Pentium4M, CK_Prescott, CK_Nocona, //@} /// \name Core /// Core microarchitecture based processors. //@{ CK_Core2, /// This enumerator, like \see CK_Yonah, is a bit odd. It is another /// codename which GCC no longer accepts as an option to -march, but Clang /// has some logic for recognizing it. // FIXME: Warn, deprecate, and potentially remove this. CK_Penryn, //@} /// \name Atom /// Atom processors //@{ CK_Bonnell, CK_Silvermont, //@} /// \name Nehalem /// Nehalem microarchitecture based processors. CK_Nehalem, /// \name Westmere /// Westmere microarchitecture based processors. CK_Westmere, /// \name Sandy Bridge /// Sandy Bridge microarchitecture based processors. CK_SandyBridge, /// \name Ivy Bridge /// Ivy Bridge microarchitecture based processors. CK_IvyBridge, /// \name Haswell /// Haswell microarchitecture based processors. CK_Haswell, /// \name Broadwell /// Broadwell microarchitecture based processors. CK_Broadwell, /// \name Skylake Client /// Skylake client microarchitecture based processors. CK_SkylakeClient, /// \name Skylake Server /// Skylake server microarchitecture based processors. CK_SkylakeServer, /// \name Cannonlake Client /// Cannonlake client microarchitecture based processors. CK_Cannonlake, /// \name Knights Landing /// Knights Landing processor. CK_KNL, /// \name Lakemont /// Lakemont microarchitecture based processors. CK_Lakemont, /// \name K6 /// K6 architecture processors. //@{ CK_K6, CK_K6_2, CK_K6_3, //@} /// \name K7 /// K7 architecture processors. //@{ CK_Athlon, CK_AthlonThunderbird, CK_Athlon4, CK_AthlonXP, CK_AthlonMP, //@} /// \name K8 /// K8 architecture processors. //@{ CK_Athlon64, CK_Athlon64SSE3, CK_AthlonFX, CK_K8, CK_K8SSE3, CK_Opteron, CK_OpteronSSE3, CK_AMDFAM10, //@} /// \name Bobcat /// Bobcat architecture processors. //@{ CK_BTVER1, CK_BTVER2, //@} /// \name Bulldozer /// Bulldozer architecture processors. //@{ CK_BDVER1, CK_BDVER2, CK_BDVER3, CK_BDVER4, //@} /// This specification is deprecated and will be removed in the future. /// Users should prefer \see CK_K8. // FIXME: Warn on this when the CPU is set to it. //@{ CK_x86_64, //@} /// \name Geode /// Geode processors. //@{ CK_Geode //@} } CPU = CK_Generic; CPUKind getCPUKind(StringRef CPU) const { return llvm::StringSwitch(CPU) .Case("i386", CK_i386) .Case("i486", CK_i486) .Case("winchip-c6", CK_WinChipC6) .Case("winchip2", CK_WinChip2) .Case("c3", CK_C3) .Case("i586", CK_i586) .Case("pentium", CK_Pentium) .Case("pentium-mmx", CK_PentiumMMX) .Case("i686", CK_i686) .Case("pentiumpro", CK_PentiumPro) .Case("pentium2", CK_Pentium2) .Case("pentium3", CK_Pentium3) .Case("pentium3m", CK_Pentium3M) .Case("pentium-m", CK_PentiumM) .Case("c3-2", CK_C3_2) .Case("yonah", CK_Yonah) .Case("pentium4", CK_Pentium4) .Case("pentium4m", CK_Pentium4M) .Case("prescott", CK_Prescott) .Case("nocona", CK_Nocona) .Case("core2", CK_Core2) .Case("penryn", CK_Penryn) .Case("bonnell", CK_Bonnell) .Case("atom", CK_Bonnell) // Legacy name. .Case("silvermont", CK_Silvermont) .Case("slm", CK_Silvermont) // Legacy name. .Case("nehalem", CK_Nehalem) .Case("corei7", CK_Nehalem) // Legacy name. .Case("westmere", CK_Westmere) .Case("sandybridge", CK_SandyBridge) .Case("corei7-avx", CK_SandyBridge) // Legacy name. .Case("ivybridge", CK_IvyBridge) .Case("core-avx-i", CK_IvyBridge) // Legacy name. .Case("haswell", CK_Haswell) .Case("core-avx2", CK_Haswell) // Legacy name. .Case("broadwell", CK_Broadwell) .Case("skylake", CK_SkylakeClient) .Case("skylake-avx512", CK_SkylakeServer) .Case("skx", CK_SkylakeServer) // Legacy name. .Case("cannonlake", CK_Cannonlake) .Case("knl", CK_KNL) .Case("lakemont", CK_Lakemont) .Case("k6", CK_K6) .Case("k6-2", CK_K6_2) .Case("k6-3", CK_K6_3) .Case("athlon", CK_Athlon) .Case("athlon-tbird", CK_AthlonThunderbird) .Case("athlon-4", CK_Athlon4) .Case("athlon-xp", CK_AthlonXP) .Case("athlon-mp", CK_AthlonMP) .Case("athlon64", CK_Athlon64) .Case("athlon64-sse3", CK_Athlon64SSE3) .Case("athlon-fx", CK_AthlonFX) .Case("k8", CK_K8) .Case("k8-sse3", CK_K8SSE3) .Case("opteron", CK_Opteron) .Case("opteron-sse3", CK_OpteronSSE3) .Case("barcelona", CK_AMDFAM10) .Case("amdfam10", CK_AMDFAM10) .Case("btver1", CK_BTVER1) .Case("btver2", CK_BTVER2) .Case("bdver1", CK_BDVER1) .Case("bdver2", CK_BDVER2) .Case("bdver3", CK_BDVER3) .Case("bdver4", CK_BDVER4) .Case("x86-64", CK_x86_64) .Case("geode", CK_Geode) .Default(CK_Generic); } enum FPMathKind { FP_Default, FP_SSE, FP_387 } FPMath = FP_Default; public: X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } unsigned getFloatEvalMethod() const override { // X87 evaluates with 80 bits "long double" precision. return SSELevel == NoSSE ? 2 : 0; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::X86::LastTSBuiltin-Builtin::FirstTSBuiltin); } ArrayRef getGCCRegNames() const override { return llvm::makeArrayRef(GCCRegNames); } ArrayRef getGCCRegAliases() const override { return None; } ArrayRef getGCCAddlRegNames() const override { return llvm::makeArrayRef(AddlRegNames); } bool validateCpuSupports(StringRef Name) const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override { // esp and ebp are the only 32-bit registers the x86 backend can currently // handle. if (RegName.equals("esp") || RegName.equals("ebp")) { // Check that the register size is 32-bit. HasSizeMismatch = RegSize != 32; return true; } return false; } bool validateOutputSize(StringRef Constraint, unsigned Size) const override; bool validateInputSize(StringRef Constraint, unsigned Size) const override; virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; std::string convertConstraint(const char *&Constraint) const override; const char *getClobbers() const override { return "~{dirflag},~{fpsr},~{flags}"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; static void setSSELevel(llvm::StringMap &Features, X86SSEEnum Level, bool Enabled); static void setMMXLevel(llvm::StringMap &Features, MMX3DNowEnum Level, bool Enabled); static void setXOPLevel(llvm::StringMap &Features, XOPEnum Level, bool Enabled); void setFeatureEnabled(llvm::StringMap &Features, StringRef Name, bool Enabled) const override { setFeatureEnabledImpl(Features, Name, Enabled); } // This exists purely to cut down on the number of virtual calls in // initFeatureMap which calls this repeatedly. static void setFeatureEnabledImpl(llvm::StringMap &Features, StringRef Name, bool Enabled); bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool hasFeature(StringRef Feature) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; StringRef getABI() const override { if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX512F) return "avx512"; if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) return "avx"; if (getTriple().getArch() == llvm::Triple::x86 && MMX3DNowLevel == NoMMX3DNow) return "no-mmx"; return ""; } bool setCPU(const std::string &Name) override { CPU = getCPUKind(Name); // Perform any per-CPU checks necessary to determine if this CPU is // acceptable. // FIXME: This results in terrible diagnostics. Clang just says the CPU is // invalid without explaining *why*. switch (CPU) { case CK_Generic: // No processor selected! return false; case CK_i386: case CK_i486: case CK_WinChipC6: case CK_WinChip2: case CK_C3: case CK_i586: case CK_Pentium: case CK_PentiumMMX: case CK_i686: case CK_PentiumPro: case CK_Pentium2: case CK_Pentium3: case CK_Pentium3M: case CK_PentiumM: case CK_Yonah: case CK_C3_2: case CK_Pentium4: case CK_Pentium4M: case CK_Lakemont: case CK_Prescott: case CK_K6: case CK_K6_2: case CK_K6_3: case CK_Athlon: case CK_AthlonThunderbird: case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: case CK_Geode: // Only accept certain architectures when compiling in 32-bit mode. if (getTriple().getArch() != llvm::Triple::x86) return false; // Fallthrough case CK_Nocona: case CK_Core2: case CK_Penryn: case CK_Bonnell: case CK_Silvermont: case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: case CK_IvyBridge: case CK_Haswell: case CK_Broadwell: case CK_SkylakeClient: case CK_SkylakeServer: case CK_Cannonlake: case CK_KNL: case CK_Athlon64: case CK_Athlon64SSE3: case CK_AthlonFX: case CK_K8: case CK_K8SSE3: case CK_Opteron: case CK_OpteronSSE3: case CK_AMDFAM10: case CK_BTVER1: case CK_BTVER2: case CK_BDVER1: case CK_BDVER2: case CK_BDVER3: case CK_BDVER4: case CK_x86_64: return true; } llvm_unreachable("Unhandled CPU kind"); } bool setFPMath(StringRef Name) override; CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { // Most of the non-ARM calling conventions are i386 conventions. switch (CC) { case CC_X86ThisCall: case CC_X86FastCall: case CC_X86StdCall: case CC_X86VectorCall: case CC_C: case CC_Swift: case CC_X86Pascal: case CC_IntelOclBicc: return CCCR_OK; default: return CCCR_Warning; } } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return MT == CCMT_Member ? CC_X86ThisCall : CC_C; } bool hasSjLjLowering() const override { return true; } void setSupportedOpenCLOpts() override { getSupportedOpenCLOpts().setAll(); } }; bool X86TargetInfo::setFPMath(StringRef Name) { if (Name == "387") { FPMath = FP_387; return true; } if (Name == "sse") { FPMath = FP_SSE; return true; } return false; } bool X86TargetInfo::initFeatureMap( llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { // FIXME: This *really* should not be here. // X86_64 always has SSE2. if (getTriple().getArch() == llvm::Triple::x86_64) setFeatureEnabledImpl(Features, "sse2", true); const CPUKind Kind = getCPUKind(CPU); // Enable X87 for all X86 processors but Lakemont. if (Kind != CK_Lakemont) setFeatureEnabledImpl(Features, "x87", true); switch (Kind) { case CK_Generic: case CK_i386: case CK_i486: case CK_i586: case CK_Pentium: case CK_i686: case CK_PentiumPro: case CK_Lakemont: break; case CK_PentiumMMX: case CK_Pentium2: case CK_K6: case CK_WinChipC6: setFeatureEnabledImpl(Features, "mmx", true); break; case CK_Pentium3: case CK_Pentium3M: case CK_C3_2: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_PentiumM: case CK_Pentium4: case CK_Pentium4M: case CK_x86_64: setFeatureEnabledImpl(Features, "sse2", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: setFeatureEnabledImpl(Features, "sse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Core2: case CK_Bonnell: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Penryn: setFeatureEnabledImpl(Features, "sse4.1", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_Cannonlake: setFeatureEnabledImpl(Features, "avx512ifma", true); setFeatureEnabledImpl(Features, "avx512vbmi", true); setFeatureEnabledImpl(Features, "sha", true); setFeatureEnabledImpl(Features, "umip", true); // FALLTHROUGH case CK_SkylakeServer: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512dq", true); setFeatureEnabledImpl(Features, "avx512bw", true); setFeatureEnabledImpl(Features, "avx512vl", true); setFeatureEnabledImpl(Features, "pku", true); setFeatureEnabledImpl(Features, "pcommit", true); setFeatureEnabledImpl(Features, "clwb", true); // FALLTHROUGH case CK_SkylakeClient: setFeatureEnabledImpl(Features, "xsavec", true); setFeatureEnabledImpl(Features, "xsaves", true); setFeatureEnabledImpl(Features, "mpx", true); setFeatureEnabledImpl(Features, "sgx", true); setFeatureEnabledImpl(Features, "clflushopt", true); // FALLTHROUGH case CK_Broadwell: setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); // FALLTHROUGH case CK_Haswell: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "rtm", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "movbe", true); // FALLTHROUGH case CK_IvyBridge: setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); // FALLTHROUGH case CK_SandyBridge: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_Westmere: case CK_Silvermont: setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); // FALLTHROUGH case CK_Nehalem: setFeatureEnabledImpl(Features, "sse4.2", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); break; case CK_KNL: setFeatureEnabledImpl(Features, "avx512f", true); setFeatureEnabledImpl(Features, "avx512cd", true); setFeatureEnabledImpl(Features, "avx512er", true); setFeatureEnabledImpl(Features, "avx512pf", true); setFeatureEnabledImpl(Features, "prefetchwt1", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "rdseed", true); setFeatureEnabledImpl(Features, "adx", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "rtm", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "rdrnd", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "xsaveopt", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "movbe", true); break; case CK_K6_2: case CK_K6_3: case CK_WinChip2: case CK_C3: setFeatureEnabledImpl(Features, "3dnow", true); break; case CK_Athlon: case CK_AthlonThunderbird: case CK_Geode: setFeatureEnabledImpl(Features, "3dnowa", true); break; case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: setFeatureEnabledImpl(Features, "sse", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_K8: case CK_Opteron: case CK_Athlon64: case CK_AthlonFX: setFeatureEnabledImpl(Features, "sse2", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_AMDFAM10: setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); // FALLTHROUGH case CK_K8SSE3: case CK_OpteronSSE3: case CK_Athlon64SSE3: setFeatureEnabledImpl(Features, "sse3", true); setFeatureEnabledImpl(Features, "3dnowa", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_BTVER2: setFeatureEnabledImpl(Features, "avx", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BTVER1: setFeatureEnabledImpl(Features, "ssse3", true); setFeatureEnabledImpl(Features, "sse4a", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "popcnt", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); break; case CK_BDVER4: setFeatureEnabledImpl(Features, "avx2", true); setFeatureEnabledImpl(Features, "bmi2", true); setFeatureEnabledImpl(Features, "mwaitx", true); // FALLTHROUGH case CK_BDVER3: setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "xsaveopt", true); // FALLTHROUGH case CK_BDVER2: setFeatureEnabledImpl(Features, "bmi", true); setFeatureEnabledImpl(Features, "fma", true); setFeatureEnabledImpl(Features, "f16c", true); setFeatureEnabledImpl(Features, "tbm", true); // FALLTHROUGH case CK_BDVER1: // xop implies avx, sse4a and fma4. setFeatureEnabledImpl(Features, "xop", true); setFeatureEnabledImpl(Features, "lzcnt", true); setFeatureEnabledImpl(Features, "aes", true); setFeatureEnabledImpl(Features, "pclmul", true); setFeatureEnabledImpl(Features, "prfchw", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "xsave", true); break; } if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) return false; // Can't do this earlier because we need to be able to explicitly enable // or disable these features and the things that they depend upon. // Enable popcnt if sse4.2 is enabled and popcnt is not explicitly disabled. auto I = Features.find("sse4.2"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-popcnt") == FeaturesVec.end()) Features["popcnt"] = true; // Enable prfchw if 3DNow! is enabled and prfchw is not explicitly disabled. I = Features.find("3dnow"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-prfchw") == FeaturesVec.end()) Features["prfchw"] = true; // Additionally, if SSE is enabled and mmx is not explicitly disabled, // then enable MMX. I = Features.find("sse"); if (I != Features.end() && I->getValue() && std::find(FeaturesVec.begin(), FeaturesVec.end(), "-mmx") == FeaturesVec.end()) Features["mmx"] = true; return true; } void X86TargetInfo::setSSELevel(llvm::StringMap &Features, X86SSEEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AVX512F: Features["avx512f"] = true; case AVX2: Features["avx2"] = true; case AVX: Features["avx"] = true; Features["xsave"] = true; case SSE42: Features["sse4.2"] = true; case SSE41: Features["sse4.1"] = true; case SSSE3: Features["ssse3"] = true; case SSE3: Features["sse3"] = true; case SSE2: Features["sse2"] = true; case SSE1: Features["sse"] = true; case NoSSE: break; } return; } switch (Level) { case NoSSE: case SSE1: Features["sse"] = false; case SSE2: Features["sse2"] = Features["pclmul"] = Features["aes"] = Features["sha"] = false; case SSE3: Features["sse3"] = false; setXOPLevel(Features, NoXOP, false); case SSSE3: Features["ssse3"] = false; case SSE41: Features["sse4.1"] = false; case SSE42: Features["sse4.2"] = false; case AVX: Features["fma"] = Features["avx"] = Features["f16c"] = Features["xsave"] = Features["xsaveopt"] = false; setXOPLevel(Features, FMA4, false); case AVX2: Features["avx2"] = false; case AVX512F: Features["avx512f"] = Features["avx512cd"] = Features["avx512er"] = Features["avx512pf"] = Features["avx512dq"] = Features["avx512bw"] = Features["avx512vl"] = Features["avx512vbmi"] = Features["avx512ifma"] = false; } } void X86TargetInfo::setMMXLevel(llvm::StringMap &Features, MMX3DNowEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case AMD3DNowAthlon: Features["3dnowa"] = true; case AMD3DNow: Features["3dnow"] = true; case MMX: Features["mmx"] = true; case NoMMX3DNow: break; } return; } switch (Level) { case NoMMX3DNow: case MMX: Features["mmx"] = false; case AMD3DNow: Features["3dnow"] = false; case AMD3DNowAthlon: Features["3dnowa"] = false; } } void X86TargetInfo::setXOPLevel(llvm::StringMap &Features, XOPEnum Level, bool Enabled) { if (Enabled) { switch (Level) { case XOP: Features["xop"] = true; case FMA4: Features["fma4"] = true; setSSELevel(Features, AVX, true); case SSE4A: Features["sse4a"] = true; setSSELevel(Features, SSE3, true); case NoXOP: break; } return; } switch (Level) { case NoXOP: case SSE4A: Features["sse4a"] = false; case FMA4: Features["fma4"] = false; case XOP: Features["xop"] = false; } } void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap &Features, StringRef Name, bool Enabled) { // This is a bit of a hack to deal with the sse4 target feature when used // as part of the target attribute. We handle sse4 correctly everywhere // else. See below for more information on how we handle the sse4 options. if (Name != "sse4") Features[Name] = Enabled; if (Name == "mmx") { setMMXLevel(Features, MMX, Enabled); } else if (Name == "sse") { setSSELevel(Features, SSE1, Enabled); } else if (Name == "sse2") { setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse3") { setSSELevel(Features, SSE3, Enabled); } else if (Name == "ssse3") { setSSELevel(Features, SSSE3, Enabled); } else if (Name == "sse4.2") { setSSELevel(Features, SSE42, Enabled); } else if (Name == "sse4.1") { setSSELevel(Features, SSE41, Enabled); } else if (Name == "3dnow") { setMMXLevel(Features, AMD3DNow, Enabled); } else if (Name == "3dnowa") { setMMXLevel(Features, AMD3DNowAthlon, Enabled); } else if (Name == "aes") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "pclmul") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "avx") { setSSELevel(Features, AVX, Enabled); } else if (Name == "avx2") { setSSELevel(Features, AVX2, Enabled); } else if (Name == "avx512f") { setSSELevel(Features, AVX512F, Enabled); } else if (Name == "avx512cd" || Name == "avx512er" || Name == "avx512pf" || Name == "avx512dq" || Name == "avx512bw" || Name == "avx512vl" || Name == "avx512vbmi" || Name == "avx512ifma") { if (Enabled) setSSELevel(Features, AVX512F, Enabled); } else if (Name == "fma") { if (Enabled) setSSELevel(Features, AVX, Enabled); } else if (Name == "fma4") { setXOPLevel(Features, FMA4, Enabled); } else if (Name == "xop") { setXOPLevel(Features, XOP, Enabled); } else if (Name == "sse4a") { setXOPLevel(Features, SSE4A, Enabled); } else if (Name == "f16c") { if (Enabled) setSSELevel(Features, AVX, Enabled); } else if (Name == "sha") { if (Enabled) setSSELevel(Features, SSE2, Enabled); } else if (Name == "sse4") { // We can get here via the __target__ attribute since that's not controlled // via the -msse4/-mno-sse4 command line alias. Handle this the same way // here - turn on the sse4.2 if enabled, turn off the sse4.1 level if // disabled. if (Enabled) setSSELevel(Features, SSE42, Enabled); else setSSELevel(Features, SSE41, Enabled); } else if (Name == "xsave") { if (!Enabled) Features["xsaveopt"] = false; } else if (Name == "xsaveopt" || Name == "xsavec" || Name == "xsaves") { if (Enabled) Features["xsave"] = true; } } /// handleTargetFeatures - Perform initialization based on the user /// configured set of features. bool X86TargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (const auto &Feature : Features) { if (Feature[0] != '+') continue; if (Feature == "+aes") { HasAES = true; } else if (Feature == "+pclmul") { HasPCLMUL = true; } else if (Feature == "+lzcnt") { HasLZCNT = true; } else if (Feature == "+rdrnd") { HasRDRND = true; } else if (Feature == "+fsgsbase") { HasFSGSBASE = true; } else if (Feature == "+bmi") { HasBMI = true; } else if (Feature == "+bmi2") { HasBMI2 = true; } else if (Feature == "+popcnt") { HasPOPCNT = true; } else if (Feature == "+rtm") { HasRTM = true; } else if (Feature == "+prfchw") { HasPRFCHW = true; } else if (Feature == "+rdseed") { HasRDSEED = true; } else if (Feature == "+adx") { HasADX = true; } else if (Feature == "+tbm") { HasTBM = true; } else if (Feature == "+fma") { HasFMA = true; } else if (Feature == "+f16c") { HasF16C = true; } else if (Feature == "+avx512cd") { HasAVX512CD = true; } else if (Feature == "+avx512er") { HasAVX512ER = true; } else if (Feature == "+avx512pf") { HasAVX512PF = true; } else if (Feature == "+avx512dq") { HasAVX512DQ = true; } else if (Feature == "+avx512bw") { HasAVX512BW = true; } else if (Feature == "+avx512vl") { HasAVX512VL = true; } else if (Feature == "+avx512vbmi") { HasAVX512VBMI = true; } else if (Feature == "+avx512ifma") { HasAVX512IFMA = true; } else if (Feature == "+sha") { HasSHA = true; } else if (Feature == "+mpx") { HasMPX = true; } else if (Feature == "+movbe") { HasMOVBE = true; } else if (Feature == "+sgx") { HasSGX = true; } else if (Feature == "+cx16") { HasCX16 = true; } else if (Feature == "+fxsr") { HasFXSR = true; } else if (Feature == "+xsave") { HasXSAVE = true; } else if (Feature == "+xsaveopt") { HasXSAVEOPT = true; } else if (Feature == "+xsavec") { HasXSAVEC = true; } else if (Feature == "+xsaves") { HasXSAVES = true; } else if (Feature == "+mwaitx") { HasMWAITX = true; } else if (Feature == "+pku") { HasPKU = true; } else if (Feature == "+clflushopt") { HasCLFLUSHOPT = true; } else if (Feature == "+pcommit") { HasPCOMMIT = true; } else if (Feature == "+clwb") { HasCLWB = true; } else if (Feature == "+umip") { HasUMIP = true; } else if (Feature == "+prefetchwt1") { HasPREFETCHWT1 = true; } X86SSEEnum Level = llvm::StringSwitch(Feature) .Case("+avx512f", AVX512F) .Case("+avx2", AVX2) .Case("+avx", AVX) .Case("+sse4.2", SSE42) .Case("+sse4.1", SSE41) .Case("+ssse3", SSSE3) .Case("+sse3", SSE3) .Case("+sse2", SSE2) .Case("+sse", SSE1) .Default(NoSSE); SSELevel = std::max(SSELevel, Level); MMX3DNowEnum ThreeDNowLevel = llvm::StringSwitch(Feature) .Case("+3dnowa", AMD3DNowAthlon) .Case("+3dnow", AMD3DNow) .Case("+mmx", MMX) .Default(NoMMX3DNow); MMX3DNowLevel = std::max(MMX3DNowLevel, ThreeDNowLevel); XOPEnum XLevel = llvm::StringSwitch(Feature) .Case("+xop", XOP) .Case("+fma4", FMA4) .Case("+sse4a", SSE4A) .Default(NoXOP); XOPLevel = std::max(XOPLevel, XLevel); } // LLVM doesn't have a separate switch for fpmath, so only accept it if it // matches the selected sse level. if ((FPMath == FP_SSE && SSELevel < SSE1) || (FPMath == FP_387 && SSELevel >= SSE1)) { Diags.Report(diag::err_target_unsupported_fpmath) << (FPMath == FP_SSE ? "sse" : "387"); return false; } SimdDefaultAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } /// X86TargetInfo::getTargetDefines - Return the set of the X86-specific macro /// definitions for this particular subtarget. void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. if (getTriple().getArch() == llvm::Triple::x86_64) { Builder.defineMacro("__amd64__"); Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); Builder.defineMacro("__x86_64__"); if (getTriple().getArchName() == "x86_64h") { Builder.defineMacro("__x86_64h"); Builder.defineMacro("__x86_64h__"); } } else { DefineStd(Builder, "i386", Opts); } // Subtarget options. // FIXME: We are hard-coding the tune parameters based on the CPU, but they // truly should be based on -mtune options. switch (CPU) { case CK_Generic: break; case CK_i386: // The rest are coming from the i386 define above. Builder.defineMacro("__tune_i386__"); break; case CK_i486: case CK_WinChipC6: case CK_WinChip2: case CK_C3: defineCPUMacros(Builder, "i486"); break; case CK_PentiumMMX: Builder.defineMacro("__pentium_mmx__"); Builder.defineMacro("__tune_pentium_mmx__"); // Fallthrough case CK_i586: case CK_Pentium: defineCPUMacros(Builder, "i586"); defineCPUMacros(Builder, "pentium"); break; case CK_Pentium3: case CK_Pentium3M: case CK_PentiumM: Builder.defineMacro("__tune_pentium3__"); // Fallthrough case CK_Pentium2: case CK_C3_2: Builder.defineMacro("__tune_pentium2__"); // Fallthrough case CK_PentiumPro: Builder.defineMacro("__tune_i686__"); Builder.defineMacro("__tune_pentiumpro__"); // Fallthrough case CK_i686: Builder.defineMacro("__i686"); Builder.defineMacro("__i686__"); // Strangely, __tune_i686__ isn't defined by GCC when CPU == i686. Builder.defineMacro("__pentiumpro"); Builder.defineMacro("__pentiumpro__"); break; case CK_Pentium4: case CK_Pentium4M: defineCPUMacros(Builder, "pentium4"); break; case CK_Yonah: case CK_Prescott: case CK_Nocona: defineCPUMacros(Builder, "nocona"); break; case CK_Core2: case CK_Penryn: defineCPUMacros(Builder, "core2"); break; case CK_Bonnell: defineCPUMacros(Builder, "atom"); break; case CK_Silvermont: defineCPUMacros(Builder, "slm"); break; case CK_Nehalem: case CK_Westmere: case CK_SandyBridge: case CK_IvyBridge: case CK_Haswell: case CK_Broadwell: case CK_SkylakeClient: // FIXME: Historically, we defined this legacy name, it would be nice to // remove it at some point. We've never exposed fine-grained names for // recent primary x86 CPUs, and we should keep it that way. defineCPUMacros(Builder, "corei7"); break; case CK_SkylakeServer: defineCPUMacros(Builder, "skx"); break; case CK_Cannonlake: break; case CK_KNL: defineCPUMacros(Builder, "knl"); break; case CK_Lakemont: Builder.defineMacro("__tune_lakemont__"); break; case CK_K6_2: Builder.defineMacro("__k6_2__"); Builder.defineMacro("__tune_k6_2__"); // Fallthrough case CK_K6_3: if (CPU != CK_K6_2) { // In case of fallthrough // FIXME: GCC may be enabling these in cases where some other k6 // architecture is specified but -m3dnow is explicitly provided. The // exact semantics need to be determined and emulated here. Builder.defineMacro("__k6_3__"); Builder.defineMacro("__tune_k6_3__"); } // Fallthrough case CK_K6: defineCPUMacros(Builder, "k6"); break; case CK_Athlon: case CK_AthlonThunderbird: case CK_Athlon4: case CK_AthlonXP: case CK_AthlonMP: defineCPUMacros(Builder, "athlon"); if (SSELevel != NoSSE) { Builder.defineMacro("__athlon_sse__"); Builder.defineMacro("__tune_athlon_sse__"); } break; case CK_K8: case CK_K8SSE3: case CK_x86_64: case CK_Opteron: case CK_OpteronSSE3: case CK_Athlon64: case CK_Athlon64SSE3: case CK_AthlonFX: defineCPUMacros(Builder, "k8"); break; case CK_AMDFAM10: defineCPUMacros(Builder, "amdfam10"); break; case CK_BTVER1: defineCPUMacros(Builder, "btver1"); break; case CK_BTVER2: defineCPUMacros(Builder, "btver2"); break; case CK_BDVER1: defineCPUMacros(Builder, "bdver1"); break; case CK_BDVER2: defineCPUMacros(Builder, "bdver2"); break; case CK_BDVER3: defineCPUMacros(Builder, "bdver3"); break; case CK_BDVER4: defineCPUMacros(Builder, "bdver4"); break; case CK_Geode: defineCPUMacros(Builder, "geode"); break; } // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); // Define __NO_MATH_INLINES on linux/x86 so that we don't get inline // functions in glibc header files that use FP Stack inline asm which the // backend can't deal with (PR879). Builder.defineMacro("__NO_MATH_INLINES"); if (HasAES) Builder.defineMacro("__AES__"); if (HasPCLMUL) Builder.defineMacro("__PCLMUL__"); if (HasLZCNT) Builder.defineMacro("__LZCNT__"); if (HasRDRND) Builder.defineMacro("__RDRND__"); if (HasFSGSBASE) Builder.defineMacro("__FSGSBASE__"); if (HasBMI) Builder.defineMacro("__BMI__"); if (HasBMI2) Builder.defineMacro("__BMI2__"); if (HasPOPCNT) Builder.defineMacro("__POPCNT__"); if (HasRTM) Builder.defineMacro("__RTM__"); if (HasPRFCHW) Builder.defineMacro("__PRFCHW__"); if (HasRDSEED) Builder.defineMacro("__RDSEED__"); if (HasADX) Builder.defineMacro("__ADX__"); if (HasTBM) Builder.defineMacro("__TBM__"); if (HasMWAITX) Builder.defineMacro("__MWAITX__"); switch (XOPLevel) { case XOP: Builder.defineMacro("__XOP__"); case FMA4: Builder.defineMacro("__FMA4__"); case SSE4A: Builder.defineMacro("__SSE4A__"); case NoXOP: break; } if (HasFMA) Builder.defineMacro("__FMA__"); if (HasF16C) Builder.defineMacro("__F16C__"); if (HasAVX512CD) Builder.defineMacro("__AVX512CD__"); if (HasAVX512ER) Builder.defineMacro("__AVX512ER__"); if (HasAVX512PF) Builder.defineMacro("__AVX512PF__"); if (HasAVX512DQ) Builder.defineMacro("__AVX512DQ__"); if (HasAVX512BW) Builder.defineMacro("__AVX512BW__"); if (HasAVX512VL) Builder.defineMacro("__AVX512VL__"); if (HasAVX512VBMI) Builder.defineMacro("__AVX512VBMI__"); if (HasAVX512IFMA) Builder.defineMacro("__AVX512IFMA__"); if (HasSHA) Builder.defineMacro("__SHA__"); if (HasFXSR) Builder.defineMacro("__FXSR__"); if (HasXSAVE) Builder.defineMacro("__XSAVE__"); if (HasXSAVEOPT) Builder.defineMacro("__XSAVEOPT__"); if (HasXSAVEC) Builder.defineMacro("__XSAVEC__"); if (HasXSAVES) Builder.defineMacro("__XSAVES__"); if (HasPKU) Builder.defineMacro("__PKU__"); if (HasCX16) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16"); // Each case falls through to the previous one here. switch (SSELevel) { case AVX512F: Builder.defineMacro("__AVX512F__"); case AVX2: Builder.defineMacro("__AVX2__"); case AVX: Builder.defineMacro("__AVX__"); case SSE42: Builder.defineMacro("__SSE4_2__"); case SSE41: Builder.defineMacro("__SSE4_1__"); case SSSE3: Builder.defineMacro("__SSSE3__"); case SSE3: Builder.defineMacro("__SSE3__"); case SSE2: Builder.defineMacro("__SSE2__"); Builder.defineMacro("__SSE2_MATH__"); // -mfp-math=sse always implied. case SSE1: Builder.defineMacro("__SSE__"); Builder.defineMacro("__SSE_MATH__"); // -mfp-math=sse always implied. case NoSSE: break; } if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { switch (SSELevel) { case AVX512F: case AVX2: case AVX: case SSE42: case SSE41: case SSSE3: case SSE3: case SSE2: Builder.defineMacro("_M_IX86_FP", Twine(2)); break; case SSE1: Builder.defineMacro("_M_IX86_FP", Twine(1)); break; default: Builder.defineMacro("_M_IX86_FP", Twine(0)); } } // Each case falls through to the previous one here. switch (MMX3DNowLevel) { case AMD3DNowAthlon: Builder.defineMacro("__3dNOW_A__"); case AMD3DNow: Builder.defineMacro("__3dNOW__"); case MMX: Builder.defineMacro("__MMX__"); case NoMMX3DNow: break; } if (CPU >= CK_i486) { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); } if (CPU >= CK_i586) Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } bool X86TargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch(Feature) .Case("aes", HasAES) .Case("avx", SSELevel >= AVX) .Case("avx2", SSELevel >= AVX2) .Case("avx512f", SSELevel >= AVX512F) .Case("avx512cd", HasAVX512CD) .Case("avx512er", HasAVX512ER) .Case("avx512pf", HasAVX512PF) .Case("avx512dq", HasAVX512DQ) .Case("avx512bw", HasAVX512BW) .Case("avx512vl", HasAVX512VL) .Case("avx512vbmi", HasAVX512VBMI) .Case("avx512ifma", HasAVX512IFMA) .Case("bmi", HasBMI) .Case("bmi2", HasBMI2) .Case("clflushopt", HasCLFLUSHOPT) .Case("clwb", HasCLWB) .Case("cx16", HasCX16) .Case("f16c", HasF16C) .Case("fma", HasFMA) .Case("fma4", XOPLevel >= FMA4) .Case("fsgsbase", HasFSGSBASE) .Case("fxsr", HasFXSR) .Case("lzcnt", HasLZCNT) .Case("mm3dnow", MMX3DNowLevel >= AMD3DNow) .Case("mm3dnowa", MMX3DNowLevel >= AMD3DNowAthlon) .Case("mmx", MMX3DNowLevel >= MMX) .Case("movbe", HasMOVBE) .Case("mpx", HasMPX) .Case("pclmul", HasPCLMUL) .Case("pcommit", HasPCOMMIT) .Case("pku", HasPKU) .Case("popcnt", HasPOPCNT) .Case("prefetchwt1", HasPREFETCHWT1) .Case("prfchw", HasPRFCHW) .Case("rdrnd", HasRDRND) .Case("rdseed", HasRDSEED) .Case("rtm", HasRTM) .Case("sgx", HasSGX) .Case("sha", HasSHA) .Case("sse", SSELevel >= SSE1) .Case("sse2", SSELevel >= SSE2) .Case("sse3", SSELevel >= SSE3) .Case("ssse3", SSELevel >= SSSE3) .Case("sse4.1", SSELevel >= SSE41) .Case("sse4.2", SSELevel >= SSE42) .Case("sse4a", XOPLevel >= SSE4A) .Case("tbm", HasTBM) .Case("umip", HasUMIP) .Case("x86", true) .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) .Case("xop", XOPLevel >= XOP) .Case("xsave", HasXSAVE) .Case("xsavec", HasXSAVEC) .Case("xsaves", HasXSAVES) .Case("xsaveopt", HasXSAVEOPT) .Default(false); } // We can't use a generic validation scheme for the features accepted here // versus subtarget features accepted in the target attribute because the // bitfield structure that's initialized in the runtime only supports the // below currently rather than the full range of subtarget features. (See // X86TargetInfo::hasFeature for a somewhat comprehensive list). bool X86TargetInfo::validateCpuSupports(StringRef FeatureStr) const { return llvm::StringSwitch(FeatureStr) .Case("cmov", true) .Case("mmx", true) .Case("popcnt", true) .Case("sse", true) .Case("sse2", true) .Case("sse3", true) .Case("ssse3", true) .Case("sse4.1", true) .Case("sse4.2", true) .Case("avx", true) .Case("avx2", true) .Case("sse4a", true) .Case("fma4", true) .Case("xop", true) .Case("fma", true) .Case("avx512f", true) .Case("bmi", true) .Case("bmi2", true) .Case("aes", true) .Case("pclmul", true) .Case("avx512vl", true) .Case("avx512bw", true) .Case("avx512dq", true) .Case("avx512cd", true) .Case("avx512er", true) .Case("avx512pf", true) .Case("avx512vbmi", true) .Case("avx512ifma", true) .Default(false); } bool X86TargetInfo::validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; // Constant constraints. case 'e': // 32-bit signed integer constant for use with sign-extending x86_64 // instructions. case 'Z': // 32-bit unsigned integer constant for use with zero-extending // x86_64 instructions. case 's': Info.setRequiresImmediate(); return true; case 'I': Info.setRequiresImmediate(0, 31); return true; case 'J': Info.setRequiresImmediate(0, 63); return true; case 'K': Info.setRequiresImmediate(-128, 127); return true; case 'L': Info.setRequiresImmediate({ int(0xff), int(0xffff), int(0xffffffff) }); return true; case 'M': Info.setRequiresImmediate(0, 3); return true; case 'N': Info.setRequiresImmediate(0, 255); return true; case 'O': Info.setRequiresImmediate(0, 127); return true; // Register constraints. case 'Y': // 'Y' is the first character for several 2-character constraints. // Shift the pointer to the second character of the constraint. Name++; switch (*Name) { default: return false; case '0': // First SSE register. case 't': // Any SSE register, when SSE2 is enabled. case 'i': // Any SSE register, when SSE2 and inter-unit moves enabled. case 'm': // Any MMX register, when inter-unit moves enabled. Info.setAllowsRegister(); return true; } case 'f': // Any x87 floating point stack register. // Constraint 'f' cannot be used for output operands. if (Info.ConstraintStr[0] == '=') return false; Info.setAllowsRegister(); return true; case 'a': // eax. case 'b': // ebx. case 'c': // ecx. case 'd': // edx. case 'S': // esi. case 'D': // edi. case 'A': // edx:eax. case 't': // Top of floating point stack. case 'u': // Second from top of floating point stack. case 'q': // Any register accessible as [r]l: a, b, c, and d. case 'y': // Any MMX register. case 'x': // Any SSE register. case 'Q': // Any register accessible as [r]h: a, b, c, and d. case 'R': // "Legacy" registers: ax, bx, cx, dx, di, si, sp, bp. case 'l': // "Index" registers: any general register that can be used as an // index in a base+index memory access. Info.setAllowsRegister(); return true; // Floating point constant constraints. case 'C': // SSE floating point constant. case 'G': // x87 floating point constant. return true; } } bool X86TargetInfo::validateOutputSize(StringRef Constraint, unsigned Size) const { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); return validateOperandSize(Constraint, Size); } bool X86TargetInfo::validateInputSize(StringRef Constraint, unsigned Size) const { return validateOperandSize(Constraint, Size); } bool X86TargetInfo::validateOperandSize(StringRef Constraint, unsigned Size) const { switch (Constraint[0]) { default: break; case 'y': return Size <= 64; case 'f': case 't': case 'u': return Size <= 128; case 'x': if (SSELevel >= AVX512F) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; else if (SSELevel >= AVX) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; case 'Y': // 'Y' is the first character for several 2-character constraints. switch (Constraint[1]) { default: break; case 'm': // 'Ym' is synonymous with 'y'. return Size <= 64; case 'i': case 't': // 'Yi' and 'Yt' are synonymous with 'x' when SSE2 is enabled. if (SSELevel >= AVX512F) return Size <= 512U; else if (SSELevel >= AVX) return Size <= 256U; return SSELevel >= SSE2 && Size <= 128U; } } return true; } std::string X86TargetInfo::convertConstraint(const char *&Constraint) const { switch (*Constraint) { case 'a': return std::string("{ax}"); case 'b': return std::string("{bx}"); case 'c': return std::string("{cx}"); case 'd': return std::string("{dx}"); case 'S': return std::string("{si}"); case 'D': return std::string("{di}"); case 'p': // address return std::string("im"); case 't': // top of floating point stack. return std::string("{st}"); case 'u': // second from top of floating point stack. return std::string("{st(1)}"); // second from top of floating point stack. default: return std::string(1, *Constraint); } } // X86-32 generic target class X86_32TargetInfo : public X86TargetInfo { public: X86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86TargetInfo(Triple, Opts) { DoubleAlign = LongLongAlign = 32; LongDoubleWidth = 96; LongDoubleAlign = 32; SuitableAlign = 128; resetDataLayout("e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128"); SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; RegParmMax = 3; // Use fpret for all types. RealTypeUsesObjCFPRet = ((1 << TargetInfo::Float) | (1 << TargetInfo::Double) | (1 << TargetInfo::LongDouble)); // x86-32 has atomics up to 8 bytes // FIXME: Check that we actually have cmpxchg8b before setting // MaxAtomicInlineWidth. (cmpxchg8b is an i586 instruction.) MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 2; return -1; } bool validateOperandSize(StringRef Constraint, unsigned Size) const override { switch (Constraint[0]) { default: break; case 'R': case 'q': case 'Q': case 'a': case 'b': case 'c': case 'd': case 'S': case 'D': return Size <= 32; case 'A': return Size <= 64; } return X86TargetInfo::validateOperandSize(Constraint, Size); } }; class NetBSDI386TargetInfo : public NetBSDTargetInfo { public: NetBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : NetBSDTargetInfo(Triple, Opts) {} unsigned getFloatEvalMethod() const override { unsigned Major, Minor, Micro; getTriple().getOSVersion(Major, Minor, Micro); // New NetBSD uses the default rounding mode. if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 26) || Major == 0) return X86_32TargetInfo::getFloatEvalMethod(); // NetBSD before 6.99.26 defaults to "double" rounding. return 1; } }; class OpenBSDI386TargetInfo : public OpenBSDTargetInfo { public: OpenBSDI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OpenBSDTargetInfo(Triple, Opts) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; } }; class BitrigI386TargetInfo : public BitrigTargetInfo { public: BitrigI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : BitrigTargetInfo(Triple, Opts) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; } }; class DarwinI386TargetInfo : public DarwinTargetInfo { public: DarwinI386TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { LongDoubleWidth = 128; LongDoubleAlign = 128; SuitableAlign = 128; MaxVectorAlign = 256; // The watchOS simulator uses the builtin bool type for Objective-C. llvm::Triple T = llvm::Triple(Triple); if (T.isWatchOS()) UseSignedCharForObjCBool = false; SizeType = UnsignedLong; IntPtrType = SignedLong; resetDataLayout("e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128"); HasAlignMac68kSupport = true; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { if (!DarwinTargetInfo::handleTargetFeatures(Features, Diags)) return false; // We now know the features we have: we can decide how to align vectors. MaxVectorAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } }; // x86-32 Windows target class WindowsX86_32TargetInfo : public WindowsTargetInfo { public: WindowsX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsTargetInfo(Triple, Opts) { WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); resetDataLayout(IsWinCOFF ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsTargetInfo::getTargetDefines(Opts, Builder); } }; // x86-32 Windows Visual Studio target class MicrosoftX86_32TargetInfo : public WindowsX86_32TargetInfo { public: MicrosoftX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsX86_32TargetInfo(Triple, Opts) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); WindowsX86_32TargetInfo::getVisualStudioDefines(Opts, Builder); // The value of the following reflects processor type. // 300=386, 400=486, 500=Pentium, 600=Blend (default) // We lost the original triple, so we use the default. Builder.defineMacro("_M_IX86", "600"); } }; static void addCygMingDefines(const LangOptions &Opts, MacroBuilder &Builder) { // Mingw and cygwin define __declspec(a) to __attribute__((a)). Clang // supports __declspec natively under -fms-extensions, but we define a no-op // __declspec macro anyway for pre-processor compatibility. if (Opts.MicrosoftExt) Builder.defineMacro("__declspec", "__declspec"); else Builder.defineMacro("__declspec(a)", "__attribute__((a))"); if (!Opts.MicrosoftExt) { // Provide macros for all the calling convention keywords. Provide both // single and double underscore prefixed variants. These are available on // x64 as well as x86, even though they have no effect. const char *CCs[] = {"cdecl", "stdcall", "fastcall", "thiscall", "pascal"}; for (const char *CC : CCs) { std::string GCCSpelling = "__attribute__((__"; GCCSpelling += CC; GCCSpelling += "__))"; Builder.defineMacro(Twine("_") + CC, GCCSpelling); Builder.defineMacro(Twine("__") + CC, GCCSpelling); } } } static void addMinGWDefines(const LangOptions &Opts, MacroBuilder &Builder) { Builder.defineMacro("__MSVCRT__"); Builder.defineMacro("__MINGW32__"); addCygMingDefines(Opts, Builder); } // x86-32 MinGW target class MinGWX86_32TargetInfo : public WindowsX86_32TargetInfo { public: MinGWX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsX86_32TargetInfo(Triple, Opts) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_32TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN32", Opts); DefineStd(Builder, "WINNT", Opts); Builder.defineMacro("_X86_"); addMinGWDefines(Opts, Builder); } }; // x86-32 Cygwin target class CygwinX86_32TargetInfo : public X86_32TargetInfo { public: CygwinX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86_32TargetInfo(Triple, Opts) { WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; resetDataLayout("e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_X86_"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); addCygMingDefines(Opts, Builder); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } }; // x86-32 Haiku target class HaikuX86_32TargetInfo : public HaikuTargetInfo { public: HaikuX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : HaikuTargetInfo(Triple, Opts) { } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { HaikuTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__INTEL__"); } }; // X86-32 MCU target class MCUX86_32TargetInfo : public X86_32TargetInfo { public: MCUX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86_32TargetInfo(Triple, Opts) { LongDoubleWidth = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; resetDataLayout("e-m:e-p:32:32-i64:32-f64:32-f128:32-n8:16:32-a:0:32-S32"); WIntType = UnsignedInt; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { // On MCU we support only C calling convention. return CC == CC_C ? CCCR_OK : CCCR_Warning; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__iamcu"); Builder.defineMacro("__iamcu__"); } bool allowsLargerPreferedTypeAlignment() const override { return false; } }; // RTEMS Target template class RTEMSTargetInfo : public OSTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { // RTEMS defines; list based off of gcc output Builder.defineMacro("__rtems__"); Builder.defineMacro("__ELF__"); } public: RTEMSTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo(Triple, Opts) { switch (Triple.getArch()) { default: case llvm::Triple::x86: // this->MCountName = ".mcount"; break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: // this->MCountName = "_mcount"; break; case llvm::Triple::arm: // this->MCountName = "__mcount"; break; } } }; // x86-32 RTEMS target class RTEMSX86_32TargetInfo : public X86_32TargetInfo { public: RTEMSX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86_32TargetInfo(Triple, Opts) { SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_32TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__INTEL__"); Builder.defineMacro("__rtems__"); } }; // x86-64 generic target class X86_64TargetInfo : public X86TargetInfo { public: X86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86TargetInfo(Triple, Opts) { const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; LongDoubleWidth = 128; LongDoubleAlign = 128; LargeArrayMinWidth = 128; LargeArrayAlign = 128; SuitableAlign = 128; SizeType = IsX32 ? UnsignedInt : UnsignedLong; PtrDiffType = IsX32 ? SignedInt : SignedLong; IntPtrType = IsX32 ? SignedInt : SignedLong; IntMaxType = IsX32 ? SignedLongLong : SignedLong; Int64Type = IsX32 ? SignedLongLong : SignedLong; RegParmMax = 6; // Pointers are 32-bit in x32. resetDataLayout(IsX32 ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" : IsWinCOFF ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"); // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); // Use fp2ret for _Complex long double. ComplexLongDoubleUsesFP2Ret = true; // Make __builtin_ms_va_list available. HasBuiltinMSVaList = true; // x86-64 has atomics up to 16 bytes. MaxAtomicPromoteWidth = 128; MaxAtomicInlineWidth = 128; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::X86_64ABIBuiltinVaList; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_C: case CC_Swift: case CC_X86VectorCall: case CC_IntelOclBicc: case CC_X86_64Win64: case CC_PreserveMost: case CC_PreserveAll: return CCCR_OK; default: return CCCR_Warning; } } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return CC_C; } // for x32 we need it here explicitly bool hasInt128Type() const override { return true; } unsigned getUnwindWordWidth() const override { return 64; } unsigned getRegisterWidth() const override { return 64; } bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize, bool &HasSizeMismatch) const override { // rsp and rbp are the only 64-bit registers the x86 backend can currently // handle. if (RegName.equals("rsp") || RegName.equals("rbp")) { // Check that the register size is 64-bit. HasSizeMismatch = RegSize != 64; return true; } // Check if the register is a 32-bit register the backend can handle. return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, HasSizeMismatch); } }; // x86-64 Windows target class WindowsX86_64TargetInfo : public WindowsTargetInfo { public: WindowsX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsTargetInfo(Triple, Opts) { WCharType = UnsignedShort; LongWidth = LongAlign = 32; DoubleAlign = LongLongAlign = 64; IntMaxType = SignedLongLong; Int64Type = SignedLongLong; SizeType = UnsignedLongLong; PtrDiffType = SignedLongLong; IntPtrType = SignedLongLong; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_WIN64"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: return CCCR_Ignore; case CC_C: case CC_X86VectorCall: case CC_IntelOclBicc: case CC_X86_64SysV: return CCCR_OK; default: return CCCR_Warning; } } }; // x86-64 Windows Visual Studio target class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo { public: MicrosoftX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsX86_64TargetInfo(Triple, Opts) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); WindowsX86_64TargetInfo::getVisualStudioDefines(Opts, Builder); Builder.defineMacro("_M_X64", "100"); Builder.defineMacro("_M_AMD64", "100"); } }; // x86-64 MinGW target class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { public: MinGWX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsX86_64TargetInfo(Triple, Opts) { // Mingw64 rounds long double size and alignment up to 16 bytes, but sticks // with x86 FP ops. Weird. LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsX86_64TargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN64", Opts); Builder.defineMacro("__MINGW64__"); addMinGWDefines(Opts, Builder); // GCC defines this macro when it is using __gxx_personality_seh0. if (!Opts.SjLjExceptions) Builder.defineMacro("__SEH__"); } }; // x86-64 Cygwin target class CygwinX86_64TargetInfo : public X86_64TargetInfo { public: CygwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : X86_64TargetInfo(Triple, Opts) { TLSSupported = false; WCharType = UnsignedShort; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { X86_64TargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__x86_64__"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN64__"); addCygMingDefines(Opts, Builder); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); // GCC defines this macro when it is using __gxx_personality_seh0. if (!Opts.SjLjExceptions) Builder.defineMacro("__SEH__"); } }; class DarwinX86_64TargetInfo : public DarwinTargetInfo { public: DarwinX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { Int64Type = SignedLongLong; // The 64-bit iOS simulator uses the builtin bool type for Objective-C. llvm::Triple T = llvm::Triple(Triple); if (T.isiOS()) UseSignedCharForObjCBool = false; resetDataLayout("e-m:o-i64:64-f80:128-n8:16:32:64-S128"); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { if (!DarwinTargetInfo::handleTargetFeatures(Features, Diags)) return false; // We now know the features we have: we can decide how to align vectors. MaxVectorAlign = hasFeature("avx512f") ? 512 : hasFeature("avx") ? 256 : 128; return true; } }; class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo { public: OpenBSDX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OpenBSDTargetInfo(Triple, Opts) { IntMaxType = SignedLongLong; Int64Type = SignedLongLong; } }; class BitrigX86_64TargetInfo : public BitrigTargetInfo { public: BitrigX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : BitrigTargetInfo(Triple, Opts) { IntMaxType = SignedLongLong; Int64Type = SignedLongLong; } }; class ARMTargetInfo : public TargetInfo { // Possible FPU choices. enum FPUMode { VFP2FPU = (1 << 0), VFP3FPU = (1 << 1), VFP4FPU = (1 << 2), NeonFPU = (1 << 3), FPARMV8 = (1 << 4) }; // Possible HWDiv features. enum HWDivMode { HWDivThumb = (1 << 0), HWDivARM = (1 << 1) }; static bool FPUModeIsVFP(FPUMode Mode) { return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU | FPARMV8); } static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; std::string ABI, CPU; StringRef CPUProfile; StringRef CPUAttr; enum { FP_Default, FP_VFP, FP_Neon } FPMath; unsigned ArchISA; unsigned ArchKind = llvm::ARM::AK_ARMV4T; unsigned ArchProfile; unsigned ArchVersion; unsigned FPU : 5; unsigned IsAAPCS : 1; unsigned HWDiv : 2; // Initialized via features. unsigned SoftFloat : 1; unsigned SoftFloatABI : 1; unsigned CRC : 1; unsigned Crypto : 1; unsigned DSP : 1; unsigned Unaligned : 1; enum { LDREX_B = (1 << 0), /// byte (8-bit) LDREX_H = (1 << 1), /// half (16-bit) LDREX_W = (1 << 2), /// word (32-bit) LDREX_D = (1 << 3), /// double (64-bit) }; uint32_t LDREX; // ACLE 6.5.1 Hardware floating point enum { HW_FP_HP = (1 << 1), /// half (16-bit) HW_FP_SP = (1 << 2), /// single (32-bit) HW_FP_DP = (1 << 3), /// double (64-bit) }; uint32_t HW_FP; static const Builtin::Info BuiltinInfo[]; void setABIAAPCS() { IsAAPCS = true; DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; const llvm::Triple &T = getTriple(); // size_t is unsigned long on MachO-derived environments, NetBSD and Bitrig. if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD || T.getOS() == llvm::Triple::Bitrig) SizeType = UnsignedLong; else SizeType = UnsignedInt; switch (T.getOS()) { case llvm::Triple::NetBSD: WCharType = SignedInt; break; case llvm::Triple::Win32: WCharType = UnsignedShort; break; case llvm::Triple::Linux: default: // AAPCS 7.1.1, ARM-Linux ABI 2.4: type of wchar_t is unsigned int. WCharType = UnsignedInt; break; } UseBitFieldTypeAlignment = true; ZeroLengthBitfieldBoundary = 0; // Thumb1 add sp, #imm requires the immediate value be multiple of 4, // so set preferred for small types to 32. if (T.isOSBinFormatMachO()) { resetDataLayout(BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); } else if (T.isOSWindows()) { assert(!BigEndian && "Windows on ARM does not support big endian"); resetDataLayout("e" "-m:w" "-p:32:32" "-i64:64" "-v128:64:128" "-a:0:32" "-n32" "-S64"); } else if (T.isOSNaCl()) { assert(!BigEndian && "NaCl on ARM does not support big endian"); resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"); } else { resetDataLayout(BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" : "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); } // FIXME: Enumerated types are variable width in straight AAPCS. } void setABIAPCS(bool IsAAPCS16) { const llvm::Triple &T = getTriple(); IsAAPCS = false; if (IsAAPCS16) DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; else DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 32; // size_t is unsigned int on FreeBSD. if (T.getOS() == llvm::Triple::FreeBSD) SizeType = UnsignedInt; else SizeType = UnsignedLong; // Revert to using SignedInt on apcs-gnu to comply with existing behaviour. WCharType = SignedInt; // Do not respect the alignment of bit-field types when laying out // structures. This corresponds to PCC_BITFIELD_TYPE_MATTERS in gcc. UseBitFieldTypeAlignment = false; /// gcc forces the alignment to 4 bytes, regardless of the type of the /// zero length bitfield. This corresponds to EMPTY_FIELD_BOUNDARY in /// gcc. ZeroLengthBitfieldBoundary = 32; if (T.isOSBinFormatMachO() && IsAAPCS16) { assert(!BigEndian && "AAPCS16 does not support big-endian"); resetDataLayout("e-m:o-p:32:32-i64:64-a:0:32-n32-S128"); } else if (T.isOSBinFormatMachO()) resetDataLayout( BigEndian ? "E-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" : "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); else resetDataLayout( BigEndian ? "E-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32" : "e-m:e-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"); // FIXME: Override "preferred align" for double and long long. } void setArchInfo() { StringRef ArchName = getTriple().getArchName(); ArchISA = llvm::ARM::parseArchISA(ArchName); CPU = llvm::ARM::getDefaultCPU(ArchName); unsigned AK = llvm::ARM::parseArch(ArchName); if (AK != llvm::ARM::AK_INVALID) ArchKind = AK; setArchInfo(ArchKind); } void setArchInfo(unsigned Kind) { StringRef SubArch; // cache TargetParser info ArchKind = Kind; SubArch = llvm::ARM::getSubArch(ArchKind); ArchProfile = llvm::ARM::parseArchProfile(SubArch); ArchVersion = llvm::ARM::parseArchVersion(SubArch); // cache CPU related strings CPUAttr = getCPUAttr(); CPUProfile = getCPUProfile(); } void setAtomic() { // when triple does not specify a sub arch, // then we are not using inline atomics bool ShouldUseInlineAtomic = (ArchISA == llvm::ARM::IK_ARM && ArchVersion >= 6) || (ArchISA == llvm::ARM::IK_THUMB && ArchVersion >= 7); // Cortex M does not support 8 byte atomics, while general Thumb2 does. if (ArchProfile == llvm::ARM::PK_M) { MaxAtomicPromoteWidth = 32; if (ShouldUseInlineAtomic) MaxAtomicInlineWidth = 32; } else { MaxAtomicPromoteWidth = 64; if (ShouldUseInlineAtomic) MaxAtomicInlineWidth = 64; } } bool isThumb() const { return (ArchISA == llvm::ARM::IK_THUMB); } bool supportsThumb() const { return CPUAttr.count('T') || ArchVersion >= 6; } bool supportsThumb2() const { return CPUAttr.equals("6T2") || (ArchVersion >= 7 && !CPUAttr.equals("8M_BASE")); } StringRef getCPUAttr() const { // For most sub-arches, the build attribute CPU name is enough. // For Cortex variants, it's slightly different. switch(ArchKind) { default: return llvm::ARM::getCPUAttr(ArchKind); case llvm::ARM::AK_ARMV6M: return "6M"; case llvm::ARM::AK_ARMV7S: return "7S"; case llvm::ARM::AK_ARMV7A: return "7A"; case llvm::ARM::AK_ARMV7R: return "7R"; case llvm::ARM::AK_ARMV7M: return "7M"; case llvm::ARM::AK_ARMV7EM: return "7EM"; case llvm::ARM::AK_ARMV8A: return "8A"; case llvm::ARM::AK_ARMV8_1A: return "8_1A"; case llvm::ARM::AK_ARMV8_2A: return "8_2A"; case llvm::ARM::AK_ARMV8MBaseline: return "8M_BASE"; case llvm::ARM::AK_ARMV8MMainline: return "8M_MAIN"; } } StringRef getCPUProfile() const { switch(ArchProfile) { case llvm::ARM::PK_A: return "A"; case llvm::ARM::PK_R: return "R"; case llvm::ARM::PK_M: return "M"; default: return ""; } } public: ARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts, bool IsBigEndian) : TargetInfo(Triple), FPMath(FP_Default), IsAAPCS(true), LDREX(0), HW_FP(0) { BigEndian = IsBigEndian; switch (getTriple().getOS()) { case llvm::Triple::NetBSD: PtrDiffType = SignedLong; break; default: PtrDiffType = SignedInt; break; } // Cache arch related info. setArchInfo(); // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; // FIXME: This duplicates code from the driver that sets the -target-abi // option - this code is used if -target-abi isn't passed and should // be unified in some way. if (Triple.isOSBinFormatMachO()) { // The backend is hardwired to assume AAPCS for M-class processors, ensure // the frontend matches that. if (Triple.getEnvironment() == llvm::Triple::EABI || Triple.getOS() == llvm::Triple::UnknownOS || StringRef(CPU).startswith("cortex-m")) { setABI("aapcs"); } else if (Triple.isWatchABI()) { setABI("aapcs16"); } else { setABI("apcs-gnu"); } } else if (Triple.isOSWindows()) { // FIXME: this is invalid for WindowsCE setABI("aapcs"); } else { // Select the default based on the platform. switch (Triple.getEnvironment()) { case llvm::Triple::Android: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: case llvm::Triple::MuslEABI: case llvm::Triple::MuslEABIHF: setABI("aapcs-linux"); break; case llvm::Triple::EABIHF: case llvm::Triple::EABI: setABI("aapcs"); break; case llvm::Triple::GNU: setABI("apcs-gnu"); break; default: if (Triple.getOS() == llvm::Triple::NetBSD) setABI("apcs-gnu"); else setABI("aapcs"); break; } } // ARM targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericARM); // ARM has atomics up to 8 bytes setAtomic(); // Do force alignment of members that follow zero length bitfields. If // the alignment of the zero-length bitfield is greater than the member // that follows it, `bar', `bar' will be aligned as the type of the // zero length bitfield. UseZeroLengthBitfieldAlignment = true; if (Triple.getOS() == llvm::Triple::Linux || Triple.getOS() == llvm::Triple::UnknownOS) this->MCountName = Opts.EABIVersion == "gnu" ? "\01__gnu_mcount_nc" : "\01mcount"; } StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { ABI = Name; // The defaults (above) are for AAPCS, check if we need to change them. // // FIXME: We need support for -meabi... we could just mangle it into the // name. if (Name == "apcs-gnu" || Name == "aapcs16") { setABIAPCS(Name == "aapcs16"); return true; } if (Name == "aapcs" || Name == "aapcs-vfp" || Name == "aapcs-linux") { setABIAAPCS(); return true; } return false; } // FIXME: This should be based on Arch attributes, not CPU names. bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { std::vector TargetFeatures; unsigned Arch = llvm::ARM::parseArch(getTriple().getArchName()); // get default FPU features unsigned FPUKind = llvm::ARM::getDefaultFPU(CPU, Arch); llvm::ARM::getFPUFeatures(FPUKind, TargetFeatures); // get default Extension features unsigned Extensions = llvm::ARM::getDefaultExtensions(CPU, Arch); llvm::ARM::getExtensionFeatures(Extensions, TargetFeatures); for (const char *Feature : TargetFeatures) if (Feature[0] == '+') Features[Feature+1] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { FPU = 0; CRC = 0; Crypto = 0; DSP = 0; Unaligned = 1; SoftFloat = SoftFloatABI = false; HWDiv = 0; // This does not diagnose illegal cases like having both // "+vfpv2" and "+vfpv3" or having "+neon" and "+fp-only-sp". uint32_t HW_FP_remove = 0; for (const auto &Feature : Features) { if (Feature == "+soft-float") { SoftFloat = true; } else if (Feature == "+soft-float-abi") { SoftFloatABI = true; } else if (Feature == "+vfp2") { FPU |= VFP2FPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+vfp3") { FPU |= VFP3FPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+vfp4") { FPU |= VFP4FPU; HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; } else if (Feature == "+fp-armv8") { FPU |= FPARMV8; HW_FP |= HW_FP_SP | HW_FP_DP | HW_FP_HP; } else if (Feature == "+neon") { FPU |= NeonFPU; HW_FP |= HW_FP_SP | HW_FP_DP; } else if (Feature == "+hwdiv") { HWDiv |= HWDivThumb; } else if (Feature == "+hwdiv-arm") { HWDiv |= HWDivARM; } else if (Feature == "+crc") { CRC = 1; } else if (Feature == "+crypto") { Crypto = 1; } else if (Feature == "+dsp") { DSP = 1; } else if (Feature == "+fp-only-sp") { HW_FP_remove |= HW_FP_DP; } else if (Feature == "+strict-align") { Unaligned = 0; } else if (Feature == "+fp16") { HW_FP |= HW_FP_HP; } } HW_FP &= ~HW_FP_remove; switch (ArchVersion) { case 6: if (ArchProfile == llvm::ARM::PK_M) LDREX = 0; else if (ArchKind == llvm::ARM::AK_ARMV6K) LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; else LDREX = LDREX_W; break; case 7: if (ArchProfile == llvm::ARM::PK_M) LDREX = LDREX_W | LDREX_H | LDREX_B ; else LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; break; case 8: LDREX = LDREX_D | LDREX_W | LDREX_H | LDREX_B ; } if (!(FPU & NeonFPU) && FPMath == FP_Neon) { Diags.Report(diag::err_target_unsupported_fpmath) << "neon"; return false; } if (FPMath == FP_Neon) Features.push_back("+neonfp"); else if (FPMath == FP_VFP) Features.push_back("-neonfp"); // Remove front-end specific options which the backend handles differently. auto Feature = std::find(Features.begin(), Features.end(), "+soft-float-abi"); if (Feature != Features.end()) Features.erase(Feature); return true; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("arm", true) .Case("aarch32", true) .Case("softfloat", SoftFloat) .Case("thumb", isThumb()) .Case("neon", (FPU & NeonFPU) && !SoftFloat) .Case("hwdiv", HWDiv & HWDivThumb) .Case("hwdiv-arm", HWDiv & HWDivARM) .Default(false); } bool setCPU(const std::string &Name) override { if (Name != "generic") setArchInfo(llvm::ARM::parseCPUArch(Name)); if (ArchKind == llvm::ARM::AK_INVALID) return false; setAtomic(); CPU = Name; return true; } bool setFPMath(StringRef Name) override; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__arm"); Builder.defineMacro("__arm__"); // For bare-metal none-eabi. if (getTriple().getOS() == llvm::Triple::UnknownOS && getTriple().getEnvironment() == llvm::Triple::EABI) Builder.defineMacro("__ELF__"); // Target properties. Builder.defineMacro("__REGISTER_PREFIX__", ""); // Unfortunately, __ARM_ARCH_7K__ is now more of an ABI descriptor. The CPU // happens to be Cortex-A7 though, so it should still get __ARM_ARCH_7A__. if (getTriple().isWatchABI()) Builder.defineMacro("__ARM_ARCH_7K__", "2"); if (!CPUAttr.empty()) Builder.defineMacro("__ARM_ARCH_" + CPUAttr + "__"); // ACLE 6.4.1 ARM/Thumb instruction set architecture // __ARM_ARCH is defined as an integer value indicating the current ARM ISA Builder.defineMacro("__ARM_ARCH", Twine(ArchVersion)); if (ArchVersion >= 8) { // ACLE 6.5.7 Crypto Extension if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); // ACLE 6.5.8 CRC32 Extension if (CRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); // ACLE 6.5.10 Numeric Maximum and Minimum Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); // ACLE 6.5.9 Directed Rounding Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); } // __ARM_ARCH_ISA_ARM is defined to 1 if the core supports the ARM ISA. It // is not defined for the M-profile. // NOTE that the default profile is assumed to be 'A' if (CPUProfile.empty() || ArchProfile != llvm::ARM::PK_M) Builder.defineMacro("__ARM_ARCH_ISA_ARM", "1"); // __ARM_ARCH_ISA_THUMB is defined to 1 if the core supports the original // Thumb ISA (including v6-M and v8-M Baseline). It is set to 2 if the // core supports the Thumb-2 ISA as found in the v6T2 architecture and all // v7 and v8 architectures excluding v8-M Baseline. if (supportsThumb2()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "2"); else if (supportsThumb()) Builder.defineMacro("__ARM_ARCH_ISA_THUMB", "1"); // __ARM_32BIT_STATE is defined to 1 if code is being generated for a 32-bit // instruction set such as ARM or Thumb. Builder.defineMacro("__ARM_32BIT_STATE", "1"); // ACLE 6.4.2 Architectural Profile (A, R, M or pre-Cortex) // __ARM_ARCH_PROFILE is defined as 'A', 'R', 'M' or 'S', or unset. if (!CPUProfile.empty()) Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); // ACLE 6.4.3 Unaligned access supported in hardware if (Unaligned) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); // ACLE 6.4.4 LDREX/STREX if (LDREX) Builder.defineMacro("__ARM_FEATURE_LDREX", "0x" + llvm::utohexstr(LDREX)); // ACLE 6.4.5 CLZ if (ArchVersion == 5 || (ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6) Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); // ACLE 6.5.1 Hardware Floating Point if (HW_FP) Builder.defineMacro("__ARM_FP", "0x" + llvm::utohexstr(HW_FP)); // ACLE predefines. Builder.defineMacro("__ARM_ACLE", "200"); // FP16 support (we currently only support IEEE format). Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); Builder.defineMacro("__ARM_FP16_ARGS", "1"); // ACLE 6.5.3 Fused multiply-accumulate (FMA) if (ArchVersion >= 7 && (FPU & VFP4FPU)) Builder.defineMacro("__ARM_FEATURE_FMA", "1"); // Subtarget options. // FIXME: It's more complicated than this and we don't really support // interworking. // Windows on ARM does not "support" interworking if (5 <= ArchVersion && ArchVersion <= 8 && !getTriple().isOSWindows()) Builder.defineMacro("__THUMB_INTERWORK__"); if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { // Embedded targets on Darwin follow AAPCS, but not EABI. // Windows on ARM follows AAPCS VFP, but does not conform to EABI. if (!getTriple().isOSBinFormatMachO() && !getTriple().isOSWindows()) Builder.defineMacro("__ARM_EABI__"); Builder.defineMacro("__ARM_PCS", "1"); } if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp" || ABI == "aapcs16") Builder.defineMacro("__ARM_PCS_VFP", "1"); if (SoftFloat) Builder.defineMacro("__SOFTFP__"); if (CPU == "xscale") Builder.defineMacro("__XSCALE__"); if (isThumb()) { Builder.defineMacro("__THUMBEL__"); Builder.defineMacro("__thumb__"); if (supportsThumb2()) Builder.defineMacro("__thumb2__"); } // ACLE 6.4.9 32-bit SIMD instructions if (ArchVersion >= 6 && (CPUProfile != "M" || CPUAttr == "7EM")) Builder.defineMacro("__ARM_FEATURE_SIMD32", "1"); // ACLE 6.4.10 Hardware Integer Divide if (((HWDiv & HWDivThumb) && isThumb()) || ((HWDiv & HWDivARM) && !isThumb())) { Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); Builder.defineMacro("__ARM_ARCH_EXT_IDIV__", "1"); } // Note, this is always on in gcc, even though it doesn't make sense. Builder.defineMacro("__APCS_32__"); if (FPUModeIsVFP((FPUMode) FPU)) { Builder.defineMacro("__VFP_FP__"); if (FPU & VFP2FPU) Builder.defineMacro("__ARM_VFPV2__"); if (FPU & VFP3FPU) Builder.defineMacro("__ARM_VFPV3__"); if (FPU & VFP4FPU) Builder.defineMacro("__ARM_VFPV4__"); } // This only gets set when Neon instructions are actually available, unlike // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. if ((FPU & NeonFPU) && !SoftFloat && ArchVersion >= 7) { Builder.defineMacro("__ARM_NEON", "1"); Builder.defineMacro("__ARM_NEON__"); // current AArch32 NEON implementations do not support double-precision // floating-point even when it is present in VFP. Builder.defineMacro("__ARM_NEON_FP", "0x" + llvm::utohexstr(HW_FP & ~HW_FP_DP)); } Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (ArchVersion >= 6 && CPUAttr != "6M" && CPUAttr != "8M_BASE") { Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } // ACLE 6.4.7 DSP instructions if (DSP) { Builder.defineMacro("__ARM_FEATURE_DSP", "1"); } // ACLE 6.4.8 Saturation instructions bool SAT = false; if ((ArchVersion == 6 && CPUProfile != "M") || ArchVersion > 6 ) { Builder.defineMacro("__ARM_FEATURE_SAT", "1"); SAT = true; } // ACLE 6.4.6 Q (saturation) flag if (DSP || SAT) Builder.defineMacro("__ARM_FEATURE_QBIT", "1"); if (Opts.UnsafeFPMath) Builder.defineMacro("__ARM_FP_FAST", "1"); if (ArchKind == llvm::ARM::AK_ARMV8_1A) Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::ARM::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool isCLZForZeroUndef() const override { return false; } BuiltinVaListKind getBuiltinVaListKind() const override { return IsAAPCS ? AAPCSABIBuiltinVaList : (getTriple().isWatchABI() ? TargetInfo::CharPtrBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList); } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: break; case 'l': // r0-r7 case 'h': // r8-r15 case 't': // VFP Floating point register single precision case 'w': // VFP Floating point register double precision Info.setAllowsRegister(); return true; case 'I': case 'J': case 'K': case 'L': case 'M': // FIXME return true; case 'Q': // A memory address that is a single base register. Info.setAllowsMemory(); return true; case 'U': // a memory reference... switch (Name[1]) { case 'q': // ...ARMV4 ldrsb case 'v': // ...VFP load/store (reg+constant offset) case 'y': // ...iWMMXt load/store case 't': // address valid for load/store opaque types wider // than 128-bits case 'n': // valid address for Neon doubleword vector load/store case 'm': // valid address for Neon element and structure load/store case 's': // valid address for non-offset loads/stores of quad-word // values in four ARM registers Info.setAllowsMemory(); Name++; return true; } } return false; } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'U': // Two-character constraint; add "^" hint for later parsing. R = std::string("^") + std::string(Constraint, 2); Constraint++; break; case 'p': // 'p' should be translated to 'r' by default. R = std::string("r"); break; default: return std::string(1, *Constraint); } return R; } bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, std::string &SuggestedModifier) const override { bool isOutput = (Constraint[0] == '='); bool isInOut = (Constraint[0] == '+'); // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); switch (Constraint[0]) { default: break; case 'r': { switch (Modifier) { default: return (isInOut || isOutput || Size <= 64); case 'q': // A register of size 32 cannot fit a vector type. return false; } } } return true; } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_AAPCS: case CC_AAPCS_VFP: case CC_Swift: return CCCR_OK; default: return CCCR_Warning; } } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } bool hasSjLjLowering() const override { return true; } }; bool ARMTargetInfo::setFPMath(StringRef Name) { if (Name == "neon") { FPMath = FP_Neon; return true; } else if (Name == "vfp" || Name == "vfp2" || Name == "vfp3" || Name == "vfp4") { FPMath = FP_VFP; return true; } return false; } const char * const ARMTargetInfo::GCCRegNames[] = { // Integer registers "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", // Float registers "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", // Double registers "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", // Quad registers "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15" }; ArrayRef ARMTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias ARMTargetInfo::GCCRegAliases[] = { { { "a1" }, "r0" }, { { "a2" }, "r1" }, { { "a3" }, "r2" }, { { "a4" }, "r3" }, { { "v1" }, "r4" }, { { "v2" }, "r5" }, { { "v3" }, "r6" }, { { "v4" }, "r7" }, { { "v5" }, "r8" }, { { "v6", "rfp" }, "r9" }, { { "sl" }, "r10" }, { { "fp" }, "r11" }, { { "ip" }, "r12" }, { { "r13" }, "sp" }, { { "r14" }, "lr" }, { { "r15" }, "pc" }, // The S, D and Q registers overlap, but aren't really aliases; we // don't want to substitute one of these for a different-sized one. }; ArrayRef ARMTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info ARMTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LANGBUILTIN(ID, TYPE, ATTRS, LANG) \ { #ID, TYPE, ATTRS, nullptr, LANG, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsARM.def" }; class ARMleTargetInfo : public ARMTargetInfo { public: ARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : ARMTargetInfo(Triple, Opts, /*BigEndian=*/false) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEL__"); ARMTargetInfo::getTargetDefines(Opts, Builder); } }; class ARMbeTargetInfo : public ARMTargetInfo { public: ARMbeTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : ARMTargetInfo(Triple, Opts, /*BigEndian=*/true) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEB__"); Builder.defineMacro("__ARM_BIG_ENDIAN"); ARMTargetInfo::getTargetDefines(Opts, Builder); } }; class WindowsARMTargetInfo : public WindowsTargetInfo { const llvm::Triple Triple; public: WindowsARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsTargetInfo(Triple, Opts), Triple(Triple) { WCharType = UnsignedShort; SizeType = UnsignedInt; } void getVisualStudioDefines(const LangOptions &Opts, MacroBuilder &Builder) const { WindowsTargetInfo::getVisualStudioDefines(Opts, Builder); // FIXME: this is invalid for WindowsCE Builder.defineMacro("_M_ARM_NT", "1"); Builder.defineMacro("_M_ARMT", "_M_ARM"); Builder.defineMacro("_M_THUMB", "_M_ARM"); assert((Triple.getArch() == llvm::Triple::arm || Triple.getArch() == llvm::Triple::thumb) && "invalid architecture for Windows ARM target info"); unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; Builder.defineMacro("_M_ARM", Triple.getArchName().substr(Offset)); // TODO map the complete set of values // 31: VFPv3 40: VFPv4 Builder.defineMacro("_M_ARM_FP", "31"); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: case CC_X86VectorCall: return CCCR_Ignore; case CC_C: return CCCR_OK; default: return CCCR_Warning; } } }; // Windows ARM + Itanium C++ ABI Target class ItaniumWindowsARMleTargetInfo : public WindowsARMTargetInfo { public: ItaniumWindowsARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsARMTargetInfo(Triple, Opts) { TheCXXABI.set(TargetCXXABI::GenericARM); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); if (Opts.MSVCCompat) WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); } }; // Windows ARM, MS (C++) ABI class MicrosoftARMleTargetInfo : public WindowsARMTargetInfo { public: MicrosoftARMleTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsARMTargetInfo(Triple, Opts) { TheCXXABI.set(TargetCXXABI::Microsoft); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); } }; // ARM MinGW target class MinGWARMTargetInfo : public WindowsARMTargetInfo { public: MinGWARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : WindowsARMTargetInfo(Triple, Opts) { TheCXXABI.set(TargetCXXABI::GenericARM); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsARMTargetInfo::getTargetDefines(Opts, Builder); DefineStd(Builder, "WIN32", Opts); DefineStd(Builder, "WINNT", Opts); Builder.defineMacro("_ARM_"); addMinGWDefines(Opts, Builder); } }; // ARM Cygwin target class CygwinARMTargetInfo : public ARMleTargetInfo { public: CygwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : ARMleTargetInfo(Triple, Opts) { TLSSupported = false; WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; resetDataLayout("e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { ARMleTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("_ARM_"); Builder.defineMacro("__CYGWIN__"); Builder.defineMacro("__CYGWIN32__"); DefineStd(Builder, "unix", Opts); if (Opts.CPlusPlus) Builder.defineMacro("_GNU_SOURCE"); } }; class DarwinARMTargetInfo : public DarwinTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: DarwinARMTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { HasAlignMac68kSupport = true; // iOS always has 64-bit atomic instructions. // FIXME: This should be based off of the target features in // ARMleTargetInfo. MaxAtomicInlineWidth = 64; if (Triple.isWatchABI()) { // Darwin on iOS uses a variant of the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::WatchOS); // The 32-bit ABI is silent on what ptrdiff_t should be, but given that // size_t is long, it's a bit weird for it to be int. PtrDiffType = SignedLong; // BOOL should be a real boolean on the new ABI UseSignedCharForObjCBool = false; } else TheCXXABI.set(TargetCXXABI::iOS); } }; class AArch64TargetInfo : public TargetInfo { virtual void setDataLayout() = 0; static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char *const GCCRegNames[]; enum FPUModeEnum { FPUMode, NeonMode }; unsigned FPU; unsigned CRC; unsigned Crypto; unsigned Unaligned; unsigned V8_1A; static const Builtin::Info BuiltinInfo[]; std::string ABI; public: AArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple), ABI("aapcs") { if (getTriple().getOS() == llvm::Triple::NetBSD) { WCharType = SignedInt; // NetBSD apparently prefers consistency across ARM targets to consistency // across 64-bit targets. Int64Type = SignedLongLong; IntMaxType = SignedLongLong; } else { WCharType = UnsignedInt; Int64Type = SignedLong; IntMaxType = SignedLong; } LongWidth = LongAlign = PointerWidth = PointerAlign = 64; MaxVectorAlign = 128; MaxAtomicInlineWidth = 128; MaxAtomicPromoteWidth = 128; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; // AAPCS gives rules for bitfields. 7.1.7 says: "The container type // contributes to the alignment of the containing aggregate in the same way // a plain (non bit-field) member of that type would, without exception for // zero-sized or anonymous bit-fields." assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); UseZeroLengthBitfieldAlignment = true; // AArch64 targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericAArch64); if (Triple.getOS() == llvm::Triple::Linux || Triple.getOS() == llvm::Triple::UnknownOS) this->MCountName = Opts.EABIVersion == "gnu" ? "\01_mcount" : "mcount"; } StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { if (Name != "aapcs" && Name != "darwinpcs") return false; ABI = Name; return true; } bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch(Name) .Case("generic", true) .Cases("cortex-a53", "cortex-a57", "cortex-a72", "cortex-a35", "exynos-m1", true) .Case("cortex-a73", true) .Case("cyclone", true) .Case("kryo", true) .Case("vulcan", true) .Default(false); return CPUKnown; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__aarch64__"); // Target properties. Builder.defineMacro("_LP64"); Builder.defineMacro("__LP64__"); // ACLE predefines. Many can only have one possible value on v8 AArch64. Builder.defineMacro("__ARM_ACLE", "200"); Builder.defineMacro("__ARM_ARCH", "8"); Builder.defineMacro("__ARM_ARCH_PROFILE", "'A'"); Builder.defineMacro("__ARM_64BIT_STATE", "1"); Builder.defineMacro("__ARM_PCS_AAPCS64", "1"); Builder.defineMacro("__ARM_ARCH_ISA_A64", "1"); Builder.defineMacro("__ARM_FEATURE_CLZ", "1"); Builder.defineMacro("__ARM_FEATURE_FMA", "1"); Builder.defineMacro("__ARM_FEATURE_LDREX", "0xF"); Builder.defineMacro("__ARM_FEATURE_IDIV", "1"); // As specified in ACLE Builder.defineMacro("__ARM_FEATURE_DIV"); // For backwards compatibility Builder.defineMacro("__ARM_FEATURE_NUMERIC_MAXMIN", "1"); Builder.defineMacro("__ARM_FEATURE_DIRECTED_ROUNDING", "1"); Builder.defineMacro("__ARM_ALIGN_MAX_STACK_PWR", "4"); // 0xe implies support for half, single and double precision operations. Builder.defineMacro("__ARM_FP", "0xE"); // PCS specifies this for SysV variants, which is all we support. Other ABIs // may choose __ARM_FP16_FORMAT_ALTERNATIVE. Builder.defineMacro("__ARM_FP16_FORMAT_IEEE", "1"); Builder.defineMacro("__ARM_FP16_ARGS", "1"); if (Opts.UnsafeFPMath) Builder.defineMacro("__ARM_FP_FAST", "1"); Builder.defineMacro("__ARM_SIZEOF_WCHAR_T", Opts.ShortWChar ? "2" : "4"); Builder.defineMacro("__ARM_SIZEOF_MINIMAL_ENUM", Opts.ShortEnums ? "1" : "4"); if (FPU == NeonMode) { Builder.defineMacro("__ARM_NEON", "1"); // 64-bit NEON supports half, single and double precision operations. Builder.defineMacro("__ARM_NEON_FP", "0xE"); } if (CRC) Builder.defineMacro("__ARM_FEATURE_CRC32", "1"); if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO", "1"); if (Unaligned) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); if (V8_1A) Builder.defineMacro("__ARM_FEATURE_QRDMX", "1"); // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return Feature == "aarch64" || Feature == "arm64" || Feature == "arm" || (Feature == "neon" && FPU == NeonMode); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { FPU = FPUMode; CRC = 0; Crypto = 0; Unaligned = 1; V8_1A = 0; for (const auto &Feature : Features) { if (Feature == "+neon") FPU = NeonMode; if (Feature == "+crc") CRC = 1; if (Feature == "+crypto") Crypto = 1; if (Feature == "+strict-align") Unaligned = 0; if (Feature == "+v8.1a") V8_1A = 1; } setDataLayout(); return true; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_C: case CC_Swift: case CC_PreserveMost: case CC_PreserveAll: return CCCR_OK; default: return CCCR_Warning; } } bool isCLZForZeroUndef() const override { return false; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::AArch64ABIBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'w': // Floating point and SIMD registers (V0-V31) Info.setAllowsRegister(); return true; case 'I': // Constant that can be used with an ADD instruction case 'J': // Constant that can be used with a SUB instruction case 'K': // Constant that can be used with a 32-bit logical instruction case 'L': // Constant that can be used with a 64-bit logical instruction case 'M': // Constant that can be used as a 32-bit MOV immediate case 'N': // Constant that can be used as a 64-bit MOV immediate case 'Y': // Floating point constant zero case 'Z': // Integer constant zero return true; case 'Q': // A memory reference with base register and no offset Info.setAllowsMemory(); return true; case 'S': // A symbolic address Info.setAllowsRegister(); return true; case 'U': // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. // Utf: A memory address suitable for ldp/stp in TF mode. // Usa: An absolute symbolic address. // Ush: The high part (bits 32:12) of a pc-relative symbolic address. llvm_unreachable("FIXME: Unimplemented support for U* constraints."); case 'z': // Zero register, wzr or xzr Info.setAllowsRegister(); return true; case 'x': // Floating point and SIMD registers (V0-V15) Info.setAllowsRegister(); return true; } return false; } bool validateConstraintModifier(StringRef Constraint, char Modifier, unsigned Size, std::string &SuggestedModifier) const override { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); switch (Constraint[0]) { default: return true; case 'z': case 'r': { switch (Modifier) { case 'x': case 'w': // For now assume that the person knows what they're // doing with the modifier. return true; default: // By default an 'r' constraint will be in the 'x' // registers. if (Size == 64) return true; SuggestedModifier = "w"; return false; } } } } const char *getClobbers() const override { return ""; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 0; if (RegNo == 1) return 1; return -1; } }; const char *const AArch64TargetInfo::GCCRegNames[] = { // 32-bit Integer registers "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w24", "w25", "w26", "w27", "w28", "w29", "w30", "wsp", // 64-bit Integer registers "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24", "x25", "x26", "x27", "x28", "fp", "lr", "sp", // 32-bit floating point regsisters "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", // 64-bit floating point regsisters "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", // Vector registers "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" }; ArrayRef AArch64TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias AArch64TargetInfo::GCCRegAliases[] = { { { "w31" }, "wsp" }, { { "x29" }, "fp" }, { { "x30" }, "lr" }, { { "x31" }, "sp" }, // The S/D/Q and W/X registers overlap, but aren't really aliases; we // don't want to substitute one of these for a different-sized one. }; ArrayRef AArch64TargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info AArch64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsNEON.def" #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsAArch64.def" }; class AArch64leTargetInfo : public AArch64TargetInfo { void setDataLayout() override { if (getTriple().isOSBinFormatMachO()) resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); else resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); } public: AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : AArch64TargetInfo(Triple, Opts) { BigEndian = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64EL__"); AArch64TargetInfo::getTargetDefines(Opts, Builder); } }; class AArch64beTargetInfo : public AArch64TargetInfo { void setDataLayout() override { assert(!getTriple().isOSBinFormatMachO()); resetDataLayout("E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); } public: AArch64beTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : AArch64TargetInfo(Triple, Opts) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64EB__"); Builder.defineMacro("__AARCH_BIG_ENDIAN"); Builder.defineMacro("__ARM_BIG_ENDIAN"); AArch64TargetInfo::getTargetDefines(Opts, Builder); } }; class DarwinAArch64TargetInfo : public DarwinTargetInfo { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const override { Builder.defineMacro("__AARCH64_SIMD__"); Builder.defineMacro("__ARM64_ARCH_8__"); Builder.defineMacro("__ARM_NEON__"); Builder.defineMacro("__LITTLE_ENDIAN__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); Builder.defineMacro("__arm64", "1"); Builder.defineMacro("__arm64__", "1"); getDarwinDefines(Builder, Opts, Triple, PlatformName, PlatformMinVersion); } public: DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo(Triple, Opts) { Int64Type = SignedLongLong; WCharType = SignedInt; UseSignedCharForObjCBool = false; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; TheCXXABI.set(TargetCXXABI::iOS64); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } }; // Hexagon abstract base class class HexagonTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char * const GCCRegNames[]; static const TargetInfo::GCCRegAlias GCCRegAliases[]; std::string CPU; bool HasHVX, HasHVXDouble; public: HexagonTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { BigEndian = false; // Specify the vector alignment explicitly. For v512x1, the calculated // alignment would be 512*alignment(i1), which is 512 bytes, instead of // the required minimum of 64 bytes. resetDataLayout("e-m:e-p:32:32:32-a:0-n16:32-" "i64:64:64-i32:32:32-i16:16:16-i1:8:8-f32:32:32-f64:64:64-" "v32:32:32-v64:64:64-v512:512:512-v1024:1024:1024-v2048:2048:2048"); SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; // {} in inline assembly are packet specifiers, not assembly variant // specifiers. NoAsmVariants = true; LargeArrayMinWidth = 64; LargeArrayAlign = 64; UseBitFieldTypeAlignment = true; ZeroLengthBitfieldBoundary = 32; HasHVX = HasHVXDouble = false; } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Hexagon::LastTSBuiltin-Builtin::FirstTSBuiltin); } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { case 'v': case 'q': if (HasHVX) { Info.setAllowsRegister(); return true; } break; case 's': // Relocatable constant. return true; } return false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; bool isCLZForZeroUndef() const override { return false; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("hexagon", true) .Case("hvx", HasHVX) .Case("hvx-double", HasHVXDouble) .Default(false); } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override; bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; const char *getClobbers() const override { return ""; } static const char *getHexagonCPUSuffix(StringRef Name) { return llvm::StringSwitch(Name) .Case("hexagonv4", "4") .Case("hexagonv5", "5") .Case("hexagonv55", "55") .Case("hexagonv60", "60") .Default(nullptr); } bool setCPU(const std::string &Name) override { if (!getHexagonCPUSuffix(Name)) return false; CPU = Name; return true; } int getEHDataRegisterNumber(unsigned RegNo) const override { return RegNo < 2 ? RegNo : -1; } }; void HexagonTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__qdsp6__", "1"); Builder.defineMacro("__hexagon__", "1"); if (CPU == "hexagonv4") { Builder.defineMacro("__HEXAGON_V4__"); Builder.defineMacro("__HEXAGON_ARCH__", "4"); if (Opts.HexagonQdsp6Compat) { Builder.defineMacro("__QDSP6_V4__"); Builder.defineMacro("__QDSP6_ARCH__", "4"); } } else if (CPU == "hexagonv5") { Builder.defineMacro("__HEXAGON_V5__"); Builder.defineMacro("__HEXAGON_ARCH__", "5"); if(Opts.HexagonQdsp6Compat) { Builder.defineMacro("__QDSP6_V5__"); Builder.defineMacro("__QDSP6_ARCH__", "5"); } } else if (CPU == "hexagonv55") { Builder.defineMacro("__HEXAGON_V55__"); Builder.defineMacro("__HEXAGON_ARCH__", "55"); Builder.defineMacro("__QDSP6_V55__"); Builder.defineMacro("__QDSP6_ARCH__", "55"); } else if (CPU == "hexagonv60") { Builder.defineMacro("__HEXAGON_V60__"); Builder.defineMacro("__HEXAGON_ARCH__", "60"); Builder.defineMacro("__QDSP6_V60__"); Builder.defineMacro("__QDSP6_ARCH__", "60"); } if (hasFeature("hvx")) { Builder.defineMacro("__HVX__"); if (hasFeature("hvx-double")) Builder.defineMacro("__HVXDBL__"); } } bool HexagonTargetInfo::handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) { for (auto &F : Features) { if (F == "+hvx") HasHVX = true; else if (F == "-hvx") HasHVX = HasHVXDouble = false; else if (F == "+hvx-double") HasHVX = HasHVXDouble = true; else if (F == "-hvx-double") HasHVXDouble = false; } return true; } bool HexagonTargetInfo::initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const { // Default for v60: -hvx, -hvx-double. Features["hvx"] = false; Features["hvx-double"] = false; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } const char *const HexagonTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3", "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" }; ArrayRef HexagonTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias HexagonTargetInfo::GCCRegAliases[] = { { { "sp" }, "r29" }, { { "fp" }, "r30" }, { { "lr" }, "r31" }, }; ArrayRef HexagonTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsHexagon.def" }; class LanaiTargetInfo : public TargetInfo { // Class for Lanai (32-bit). // The CPU profiles supported by the Lanai backend enum CPUKind { CK_NONE, CK_V11, } CPU; static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char *const GCCRegNames[]; public: LanaiTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { // Description string has to be kept in sync with backend. resetDataLayout("E" // Big endian "-m:e" // ELF name manging "-p:32:32" // 32 bit pointers, 32 bit aligned "-i64:64" // 64 bit integers, 64 bit aligned "-a:0:32" // 32 bit alignment of objects of aggregate type "-n32" // 32 bit native integer width "-S64" // 64 bit natural stack alignment ); // Setting RegParmMax equal to what mregparm was set to in the old // toolchain RegParmMax = 4; // Set the default CPU to V11 CPU = CK_V11; // Temporary approach to make everything at least word-aligned and allow for // safely casting between pointers with different alignment requirements. // TODO: Remove this when there are no more cast align warnings on the // firmware. MinGlobalAlign = 32; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { // Define __lanai__ when building for target lanai. Builder.defineMacro("__lanai__"); // Set define for the CPU specified. switch (CPU) { case CK_V11: Builder.defineMacro("__LANAI_V11__"); break; case CK_NONE: llvm_unreachable("Unhandled target CPU"); } } bool setCPU(const std::string &Name) override { CPU = llvm::StringSwitch(Name) .Case("v11", CK_V11) .Default(CK_NONE); return CPU != CK_NONE; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature).Case("lanai", true).Default(false); } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getTargetBuiltins() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return false; } const char *getClobbers() const override { return ""; } }; const char *const LanaiTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; ArrayRef LanaiTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias LanaiTargetInfo::GCCRegAliases[] = { {{"pc"}, "r2"}, {{"sp"}, "r4"}, {{"fp"}, "r5"}, {{"rv"}, "r8"}, {{"rr1"}, "r10"}, {{"rr2"}, "r11"}, {{"rca"}, "r15"}, }; ArrayRef LanaiTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } // Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; bool SoftFloat; public: SparcTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple), SoftFloat(false) {} int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 24; if (RegNo == 1) return 25; return -1; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { // Check if software floating point is enabled auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); if (Feature != Features.end()) { SoftFloat = true; } return true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "sparc", Opts); Builder.defineMacro("__REGISTER_PREFIX__", ""); if (SoftFloat) Builder.defineMacro("SOFT_FLOAT", "1"); } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("softfloat", SoftFloat) .Case("sparc", true) .Default(false); } bool hasSjLjLowering() const override { return true; } ArrayRef getTargetBuiltins() const override { // FIXME: Implement! return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: Implement! switch (*Name) { case 'I': // Signed 13-bit constant case 'J': // Zero case 'K': // 32-bit constant with the low 12 bits clear case 'L': // A constant in the range supported by movcc (11-bit signed imm) case 'M': // A constant in the range supported by movrcc (19-bit signed imm) case 'N': // Same as 'K' but zext (required for SIMode) case 'O': // The constant 4096 return true; } return false; } const char *getClobbers() const override { // FIXME: Implement! return ""; } // No Sparc V7 for now, the backend doesn't support it anyway. enum CPUKind { CK_GENERIC, CK_V8, CK_SUPERSPARC, CK_SPARCLITE, CK_F934, CK_HYPERSPARC, CK_SPARCLITE86X, CK_SPARCLET, CK_TSC701, CK_V9, CK_ULTRASPARC, CK_ULTRASPARC3, CK_NIAGARA, CK_NIAGARA2, CK_NIAGARA3, CK_NIAGARA4, CK_MYRIAD2_1, CK_MYRIAD2_2, CK_LEON2, CK_LEON2_AT697E, CK_LEON2_AT697F, CK_LEON3, CK_LEON3_UT699, CK_LEON3_GR712RC, CK_LEON4, CK_LEON4_GR740 } CPU = CK_GENERIC; enum CPUGeneration { CG_V8, CG_V9, }; CPUGeneration getCPUGeneration(CPUKind Kind) const { switch (Kind) { case CK_GENERIC: case CK_V8: case CK_SUPERSPARC: case CK_SPARCLITE: case CK_F934: case CK_HYPERSPARC: case CK_SPARCLITE86X: case CK_SPARCLET: case CK_TSC701: case CK_MYRIAD2_1: case CK_MYRIAD2_2: case CK_LEON2: case CK_LEON2_AT697E: case CK_LEON2_AT697F: case CK_LEON3: case CK_LEON3_UT699: case CK_LEON3_GR712RC: case CK_LEON4: case CK_LEON4_GR740: return CG_V8; case CK_V9: case CK_ULTRASPARC: case CK_ULTRASPARC3: case CK_NIAGARA: case CK_NIAGARA2: case CK_NIAGARA3: case CK_NIAGARA4: return CG_V9; } llvm_unreachable("Unexpected CPU kind"); } CPUKind getCPUKind(StringRef Name) const { return llvm::StringSwitch(Name) .Case("v8", CK_V8) .Case("supersparc", CK_SUPERSPARC) .Case("sparclite", CK_SPARCLITE) .Case("f934", CK_F934) .Case("hypersparc", CK_HYPERSPARC) .Case("sparclite86x", CK_SPARCLITE86X) .Case("sparclet", CK_SPARCLET) .Case("tsc701", CK_TSC701) .Case("v9", CK_V9) .Case("ultrasparc", CK_ULTRASPARC) .Case("ultrasparc3", CK_ULTRASPARC3) .Case("niagara", CK_NIAGARA) .Case("niagara2", CK_NIAGARA2) .Case("niagara3", CK_NIAGARA3) .Case("niagara4", CK_NIAGARA4) .Case("myriad2", CK_MYRIAD2_1) .Case("myriad2.1", CK_MYRIAD2_1) .Case("myriad2.2", CK_MYRIAD2_2) .Case("leon2", CK_LEON2) .Case("at697e", CK_LEON2_AT697E) .Case("at697f", CK_LEON2_AT697F) .Case("leon3", CK_LEON3) .Case("ut699", CK_LEON3_UT699) .Case("gr712rc", CK_LEON3_GR712RC) .Case("leon4", CK_LEON4) .Case("gr740", CK_LEON4_GR740) .Default(CK_GENERIC); } bool setCPU(const std::string &Name) override { CPU = getCPUKind(Name); return CPU != CK_GENERIC; } }; const char * const SparcTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" }; ArrayRef SparcTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } const TargetInfo::GCCRegAlias SparcTargetInfo::GCCRegAliases[] = { { { "g0" }, "r0" }, { { "g1" }, "r1" }, { { "g2" }, "r2" }, { { "g3" }, "r3" }, { { "g4" }, "r4" }, { { "g5" }, "r5" }, { { "g6" }, "r6" }, { { "g7" }, "r7" }, { { "o0" }, "r8" }, { { "o1" }, "r9" }, { { "o2" }, "r10" }, { { "o3" }, "r11" }, { { "o4" }, "r12" }, { { "o5" }, "r13" }, { { "o6", "sp" }, "r14" }, { { "o7" }, "r15" }, { { "l0" }, "r16" }, { { "l1" }, "r17" }, { { "l2" }, "r18" }, { { "l3" }, "r19" }, { { "l4" }, "r20" }, { { "l5" }, "r21" }, { { "l6" }, "r22" }, { { "l7" }, "r23" }, { { "i0" }, "r24" }, { { "i1" }, "r25" }, { { "i2" }, "r26" }, { { "i3" }, "r27" }, { { "i4" }, "r28" }, { { "i5" }, "r29" }, { { "i6", "fp" }, "r30" }, { { "i7" }, "r31" }, }; ArrayRef SparcTargetInfo::getGCCRegAliases() const { return llvm::makeArrayRef(GCCRegAliases); } // SPARC v8 is the 32-bit mode selected by Triple::sparc. class SparcV8TargetInfo : public SparcTargetInfo { public: SparcV8TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SparcTargetInfo(Triple, Opts) { resetDataLayout("E-m:e-p:32:32-i64:64-f128:64-n32-S64"); // NetBSD / OpenBSD use long (same as llvm default); everyone else uses int. switch (getTriple().getOS()) { default: SizeType = UnsignedInt; IntPtrType = SignedInt; PtrDiffType = SignedInt; break; case llvm::Triple::NetBSD: case llvm::Triple::OpenBSD: SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; break; } MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { SparcTargetInfo::getTargetDefines(Opts, Builder); switch (getCPUGeneration(CPU)) { case CG_V8: Builder.defineMacro("__sparcv8"); if (getTriple().getOS() != llvm::Triple::Solaris) Builder.defineMacro("__sparcv8__"); break; case CG_V9: Builder.defineMacro("__sparcv9"); if (getTriple().getOS() != llvm::Triple::Solaris) { Builder.defineMacro("__sparcv9__"); Builder.defineMacro("__sparc_v9__"); } break; } if (getTriple().getVendor() == llvm::Triple::Myriad) { switch (CPU) { case CK_MYRIAD2_1: Builder.defineMacro("__myriad2", "1"); Builder.defineMacro("__myriad2__", "1"); break; case CK_MYRIAD2_2: Builder.defineMacro("__myriad2", "2"); Builder.defineMacro("__myriad2__", "2"); break; default: break; } } } bool hasSjLjLowering() const override { return true; } }; // SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. class SparcV8elTargetInfo : public SparcV8TargetInfo { public: SparcV8elTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SparcV8TargetInfo(Triple, Opts) { resetDataLayout("e-m:e-p:32:32-i64:64-f128:64-n32-S64"); BigEndian = false; } }; // SPARC v9 is the 64-bit mode selected by Triple::sparcv9. class SparcV9TargetInfo : public SparcTargetInfo { public: SparcV9TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SparcTargetInfo(Triple, Opts) { // FIXME: Support Sparc quad-precision long double? resetDataLayout("E-m:e-i64:64-n32:64-S128"); // This is an LP64 platform. LongWidth = LongAlign = PointerWidth = PointerAlign = 64; // OpenBSD uses long long for int64_t and intmax_t. if (getTriple().getOS() == llvm::Triple::OpenBSD) IntMaxType = SignedLongLong; else IntMaxType = SignedLong; Int64Type = IntMaxType; // The SPARCv8 System V ABI has long double 128-bits in size, but 64-bit // aligned. The SPARCv9 SCD 2.4.1 says 16-byte aligned. LongDoubleWidth = 128; LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { SparcTargetInfo::getTargetDefines(Opts, Builder); Builder.defineMacro("__sparcv9"); Builder.defineMacro("__arch64__"); // Solaris doesn't need these variants, but the BSDs do. if (getTriple().getOS() != llvm::Triple::Solaris) { Builder.defineMacro("__sparc64__"); Builder.defineMacro("__sparc_v9__"); Builder.defineMacro("__sparcv9__"); } } bool setCPU(const std::string &Name) override { if (!SparcTargetInfo::setCPU(Name)) return false; return getCPUGeneration(CPU) == CG_V9; } }; class SystemZTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char *const GCCRegNames[]; std::string CPU; bool HasTransactionalExecution; bool HasVector; public: SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), HasVector(false) { IntMaxType = SignedLong; Int64Type = SignedLong; TLSSupported = true; IntWidth = IntAlign = 32; LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; PointerWidth = PointerAlign = 64; LongDoubleWidth = 128; LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEquad; DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"); MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__s390__"); Builder.defineMacro("__s390x__"); Builder.defineMacro("__zarch__"); Builder.defineMacro("__LONG_DOUBLE_128__"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); if (HasTransactionalExecution) Builder.defineMacro("__HTM__"); if (Opts.ZVector) Builder.defineMacro("__VEC__", "10301"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin); } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override; const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::SystemZBuiltinVaList; } bool setCPU(const std::string &Name) override { CPU = Name; bool CPUKnown = llvm::StringSwitch(Name) .Case("z10", true) .Case("z196", true) .Case("zEC12", true) .Case("z13", true) .Default(false); return CPUKnown; } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU == "zEC12") Features["transactional-execution"] = true; if (CPU == "z13") { Features["transactional-execution"] = true; Features["vector"] = true; } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { HasTransactionalExecution = false; for (const auto &Feature : Features) { if (Feature == "+transactional-execution") HasTransactionalExecution = true; else if (Feature == "+vector") HasVector = true; } // If we use the vector ABI, vector types are 64-bit aligned. if (HasVector) { MaxVectorAlign = 64; resetDataLayout("E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" "-v128:64-a:8:16-n32:64"); } return true; } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("systemz", true) .Case("htm", HasTransactionalExecution) .Case("vx", HasVector) .Default(false); } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { case CC_C: case CC_Swift: return CCCR_OK; default: return CCCR_Warning; } } StringRef getABI() const override { if (HasVector) return "vector"; return ""; } bool useFloat128ManglingForLongDouble() const override { return true; } }; const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, FEATURE }, #include "clang/Basic/BuiltinsSystemZ.def" }; const char *const SystemZTargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "f0", "f2", "f4", "f6", "f1", "f3", "f5", "f7", "f8", "f10", "f12", "f14", "f9", "f11", "f13", "f15" }; ArrayRef SystemZTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } bool SystemZTargetInfo:: validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; case 'a': // Address register case 'd': // Data register (equivalent to 'r') case 'f': // Floating-point register Info.setAllowsRegister(); return true; case 'I': // Unsigned 8-bit constant case 'J': // Unsigned 12-bit constant case 'K': // Signed 16-bit constant case 'L': // Signed 20-bit displacement (on all targets we support) case 'M': // 0x7fffffff return true; case 'Q': // Memory with base and unsigned 12-bit displacement case 'R': // Likewise, plus an index case 'S': // Memory with base and signed 20-bit displacement case 'T': // Likewise, plus an index Info.setAllowsMemory(); return true; } } class MSP430TargetInfo : public TargetInfo { static const char *const GCCRegNames[]; public: MSP430TargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { BigEndian = false; TLSSupported = false; IntWidth = 16; IntAlign = 16; LongWidth = 32; LongLongWidth = 64; LongAlign = LongLongAlign = 16; PointerWidth = 16; PointerAlign = 16; SuitableAlign = 16; SizeType = UnsignedInt; IntMaxType = SignedLongLong; IntPtrType = SignedInt; PtrDiffType = SignedInt; SigAtomicType = SignedLong; resetDataLayout("e-m:e-p:16:16-i32:16:32-a:16-n8:16"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("MSP430"); Builder.defineMacro("__MSP430__"); // FIXME: defines for different 'flavours' of MCU } ArrayRef getTargetBuiltins() const override { // FIXME: Implement. return None; } bool hasFeature(StringRef Feature) const override { return Feature == "msp430"; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override { // No aliases. return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: implement switch (*Name) { case 'K': // the constant 1 case 'L': // constant -1^20 .. 1^19 case 'M': // constant 1-4: return true; } // No target constraints for now. return false; } const char *getClobbers() const override { // FIXME: Is this really right? return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { // FIXME: implement return TargetInfo::CharPtrBuiltinVaList; } }; const char *const MSP430TargetInfo::GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}; ArrayRef MSP430TargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } // LLVM and Clang cannot be used directly to output native binaries for // target, but is used to compile C code to llvm bitcode with correct // type and alignment information. // // TCE uses the llvm bitcode as input and uses it for generating customized // target processor and program binary. TCE co-design environment is // publicly available in http://tce.cs.tut.fi static const unsigned TCEOpenCLAddrSpaceMap[] = { 3, // opencl_global 4, // opencl_local 5, // opencl_constant // FIXME: generic has to be added to the target 0, // opencl_generic 0, // cuda_device 0, // cuda_constant 0 // cuda_shared }; class TCETargetInfo : public TargetInfo { public: TCETargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { TLSSupported = false; IntWidth = 32; LongWidth = LongLongWidth = 32; PointerWidth = 32; IntAlign = 32; LongAlign = LongLongAlign = 32; PointerAlign = 32; SuitableAlign = 32; SizeType = UnsignedInt; IntMaxType = SignedLong; IntPtrType = SignedInt; PtrDiffType = SignedInt; FloatWidth = 32; FloatAlign = 32; DoubleWidth = 32; DoubleAlign = 32; LongDoubleWidth = 32; LongDoubleAlign = 32; FloatFormat = &llvm::APFloat::IEEEsingle; DoubleFormat = &llvm::APFloat::IEEEsingle; LongDoubleFormat = &llvm::APFloat::IEEEsingle; resetDataLayout("E-p:32:32-i8:8:32-i16:16:32-i64:32" "-f64:32-v64:32-v128:32-a:0:32-n32"); AddrSpaceMap = &TCEOpenCLAddrSpaceMap; UseAddrSpaceMapMangling = true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "tce", Opts); Builder.defineMacro("__TCE__"); Builder.defineMacro("__TCE_V1__"); } bool hasFeature(StringRef Feature) const override { return Feature == "tce"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } }; class BPFTargetInfo : public TargetInfo { public: BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; SizeType = UnsignedLong; PtrDiffType = SignedLong; IntPtrType = SignedLong; IntMaxType = SignedLong; Int64Type = SignedLong; RegParmMax = 5; if (Triple.getArch() == llvm::Triple::bpfeb) { BigEndian = true; resetDataLayout("E-m:e-p:64:64-i64:64-n32:64-S128"); } else { BigEndian = false; resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); } MaxAtomicPromoteWidth = 64; MaxAtomicInlineWidth = 64; TLSSupported = false; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "bpf", Opts); Builder.defineMacro("__BPF__"); } bool hasFeature(StringRef Feature) const override { return Feature == "bpf"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } }; class MipsTargetInfo : public TargetInfo { void setDataLayout() { StringRef Layout; if (ABI == "o32") Layout = "m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"; else if (ABI == "n32") Layout = "m:e-p:32:32-i8:8:32-i16:16:32-i64:64-n32:64-S128"; else if (ABI == "n64") Layout = "m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"; else llvm_unreachable("Invalid ABI"); if (BigEndian) resetDataLayout(("E-" + Layout).str()); else resetDataLayout(("e-" + Layout).str()); } static const Builtin::Info BuiltinInfo[]; std::string CPU; bool IsMips16; bool IsMicromips; bool IsNan2008; bool IsSingleFloat; enum MipsFloatABI { HardFloat, SoftFloat } FloatABI; enum DspRevEnum { NoDSP, DSP1, DSP2 } DspRev; bool HasMSA; protected: bool HasFP64; std::string ABI; public: MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple), IsMips16(false), IsMicromips(false), IsNan2008(false), IsSingleFloat(false), FloatABI(HardFloat), DspRev(NoDSP), HasMSA(false), HasFP64(false) { TheCXXABI.set(TargetCXXABI::GenericMIPS); BigEndian = getTriple().getArch() == llvm::Triple::mips || getTriple().getArch() == llvm::Triple::mips64; setABI((getTriple().getArch() == llvm::Triple::mips || getTriple().getArch() == llvm::Triple::mipsel) ? "o32" : "n64"); CPU = ABI == "o32" ? "mips32r2" : "mips64r2"; } bool isNaN2008Default() const { return CPU == "mips32r6" || CPU == "mips64r6"; } bool isFP64Default() const { return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; } bool isNan2008() const override { return IsNan2008; } bool processorSupportsGPR64() const { return llvm::StringSwitch(CPU) .Case("mips3", true) .Case("mips4", true) .Case("mips5", true) .Case("mips64", true) .Case("mips64r2", true) .Case("mips64r3", true) .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) .Default(false); return false; } StringRef getABI() const override { return ABI; } bool setABI(const std::string &Name) override { if (Name == "o32") { setO32ABITypes(); ABI = Name; return true; } if (Name == "n32") { setN32ABITypes(); ABI = Name; return true; } if (Name == "n64") { setN64ABITypes(); ABI = Name; return true; } return false; } void setO32ABITypes() { Int64Type = SignedLongLong; IntMaxType = Int64Type; LongDoubleFormat = &llvm::APFloat::IEEEdouble; LongDoubleWidth = LongDoubleAlign = 64; LongWidth = LongAlign = 32; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; PointerWidth = PointerAlign = 32; PtrDiffType = SignedInt; SizeType = UnsignedInt; SuitableAlign = 64; } void setN32N64ABITypes() { LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; if (getTriple().getOS() == llvm::Triple::FreeBSD) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; SuitableAlign = 128; } void setN64ABITypes() { setN32N64ABITypes(); Int64Type = SignedLong; IntMaxType = Int64Type; LongWidth = LongAlign = 64; PointerWidth = PointerAlign = 64; PtrDiffType = SignedLong; SizeType = UnsignedLong; } void setN32ABITypes() { setN32N64ABITypes(); Int64Type = SignedLongLong; IntMaxType = Int64Type; LongWidth = LongAlign = 32; PointerWidth = PointerAlign = 32; PtrDiffType = SignedInt; SizeType = UnsignedInt; } bool setCPU(const std::string &Name) override { CPU = Name; return llvm::StringSwitch(Name) .Case("mips1", true) .Case("mips2", true) .Case("mips3", true) .Case("mips4", true) .Case("mips5", true) .Case("mips32", true) .Case("mips32r2", true) .Case("mips32r3", true) .Case("mips32r5", true) .Case("mips32r6", true) .Case("mips64", true) .Case("mips64r2", true) .Case("mips64r3", true) .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) .Case("p5600", true) .Default(false); } const std::string& getCPU() const { return CPU; } bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU.empty()) CPU = getCPU(); if (CPU == "octeon") Features["mips64r2"] = Features["cnmips"] = true; else Features[CPU] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { if (BigEndian) { DefineStd(Builder, "MIPSEB", Opts); Builder.defineMacro("_MIPSEB"); } else { DefineStd(Builder, "MIPSEL", Opts); Builder.defineMacro("_MIPSEL"); } Builder.defineMacro("__mips__"); Builder.defineMacro("_mips"); if (Opts.GNUMode) Builder.defineMacro("mips"); if (ABI == "o32") { Builder.defineMacro("__mips", "32"); Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS32"); } else { Builder.defineMacro("__mips", "64"); Builder.defineMacro("__mips64"); Builder.defineMacro("__mips64__"); Builder.defineMacro("_MIPS_ISA", "_MIPS_ISA_MIPS64"); } const std::string ISARev = llvm::StringSwitch(getCPU()) .Cases("mips32", "mips64", "1") .Cases("mips32r2", "mips64r2", "2") .Cases("mips32r3", "mips64r3", "3") .Cases("mips32r5", "mips64r5", "5") .Cases("mips32r6", "mips64r6", "6") .Default(""); if (!ISARev.empty()) Builder.defineMacro("__mips_isa_rev", ISARev); if (ABI == "o32") { Builder.defineMacro("__mips_o32"); Builder.defineMacro("_ABIO32", "1"); Builder.defineMacro("_MIPS_SIM", "_ABIO32"); } else if (ABI == "n32") { Builder.defineMacro("__mips_n32"); Builder.defineMacro("_ABIN32", "2"); Builder.defineMacro("_MIPS_SIM", "_ABIN32"); } else if (ABI == "n64") { Builder.defineMacro("__mips_n64"); Builder.defineMacro("_ABI64", "3"); Builder.defineMacro("_MIPS_SIM", "_ABI64"); } else llvm_unreachable("Invalid ABI."); Builder.defineMacro("__REGISTER_PREFIX__", ""); switch (FloatABI) { case HardFloat: Builder.defineMacro("__mips_hard_float", Twine(1)); break; case SoftFloat: Builder.defineMacro("__mips_soft_float", Twine(1)); break; } if (IsSingleFloat) Builder.defineMacro("__mips_single_float", Twine(1)); Builder.defineMacro("__mips_fpr", HasFP64 ? Twine(64) : Twine(32)); Builder.defineMacro("_MIPS_FPSET", Twine(32 / (HasFP64 || IsSingleFloat ? 1 : 2))); if (IsMips16) Builder.defineMacro("__mips16", Twine(1)); if (IsMicromips) Builder.defineMacro("__mips_micromips", Twine(1)); if (IsNan2008) Builder.defineMacro("__mips_nan2008", Twine(1)); switch (DspRev) { default: break; case DSP1: Builder.defineMacro("__mips_dsp_rev", Twine(1)); Builder.defineMacro("__mips_dsp", Twine(1)); break; case DSP2: Builder.defineMacro("__mips_dsp_rev", Twine(2)); Builder.defineMacro("__mips_dspr2", Twine(1)); Builder.defineMacro("__mips_dsp", Twine(1)); break; } if (HasMSA) Builder.defineMacro("__mips_msa", Twine(1)); Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); // These shouldn't be defined for MIPS-I but there's no need to check // for that since MIPS-I isn't supported. Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); // 32-bit MIPS processors don't have the necessary lld/scd instructions // found in 64-bit processors. In the case of O32 on a 64-bit processor, // the instructions exist but using them violates the ABI since they // require 64-bit GPRs and O32 only supports 32-bit GPRs. if (ABI == "n32" || ABI == "n64") Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Mips::LastTSBuiltin - Builtin::FirstTSBuiltin); } bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch(Feature) .Case("mips", true) .Case("fp64", HasFP64) .Default(false); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const override { static const char *const GCCRegNames[] = { // CPU register names // Must match second column of GCCRegAliases "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", // Floating point register names "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31", // Hi/lo and condition register names "hi", "lo", "", "$fcc0","$fcc1","$fcc2","$fcc3","$fcc4", "$fcc5","$fcc6","$fcc7","$ac1hi","$ac1lo","$ac2hi","$ac2lo", "$ac3hi","$ac3lo", // MSA register names "$w0", "$w1", "$w2", "$w3", "$w4", "$w5", "$w6", "$w7", "$w8", "$w9", "$w10", "$w11", "$w12", "$w13", "$w14", "$w15", "$w16", "$w17", "$w18", "$w19", "$w20", "$w21", "$w22", "$w23", "$w24", "$w25", "$w26", "$w27", "$w28", "$w29", "$w30", "$w31", // MSA control register names "$msair", "$msacsr", "$msaaccess", "$msasave", "$msamodify", "$msarequest", "$msamap", "$msaunmap" }; return llvm::makeArrayRef(GCCRegNames); } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; case 'r': // CPU registers. case 'd': // Equivalent to "r" unless generating MIPS16 code. case 'y': // Equivalent to "r", backward compatibility only. case 'f': // floating-point registers. case 'c': // $25 for indirect jumps case 'l': // lo register case 'x': // hilo register pair Info.setAllowsRegister(); return true; case 'I': // Signed 16-bit constant case 'J': // Integer 0 case 'K': // Unsigned 16-bit constant case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) case 'M': // Constants not loadable via lui, addiu, or ori case 'N': // Constant -1 to -65535 case 'O': // A signed 15-bit constant case 'P': // A constant between 1 go 65535 return true; case 'R': // An address that can be used in a non-macro load or store Info.setAllowsMemory(); return true; case 'Z': if (Name[1] == 'C') { // An address usable by ll, and sc. Info.setAllowsMemory(); Name++; // Skip over 'Z'. return true; } return false; } } std::string convertConstraint(const char *&Constraint) const override { std::string R; switch (*Constraint) { case 'Z': // Two-character constraint; add "^" hint for later parsing. if (Constraint[1] == 'C') { R = std::string("^") + std::string(Constraint, 2); Constraint++; return R; } break; } return TargetInfo::convertConstraint(Constraint); } const char *getClobbers() const override { // In GCC, $1 is not widely used in generated code (it's used only in a few // specific situations), so there is no real need for users to add it to // the clobbers list if they want to use it in their inline assembly code. // // In LLVM, $1 is treated as a normal GPR and is always allocatable during // code generation, so using it in inline assembly without adding it to the // clobbers list can cause conflicts between the inline assembly code and // the surrounding generated code. // // Another problem is that LLVM is allowed to choose $1 for inline assembly // operands, which will conflict with the ".set at" assembler option (which // we use only for inline assembly, in order to maintain compatibility with // GCC) and will also conflict with the user's usage of $1. // // The easiest way to avoid these conflicts and keep $1 as an allocatable // register for generated code is to automatically clobber $1 for all inline // assembly code. // // FIXME: We should automatically clobber $1 only for inline assembly code // which actually uses it. This would allow LLVM to use $1 for inline // assembly operands if the user's assembly code doesn't use it. return "~{$1}"; } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) override { IsMips16 = false; IsMicromips = false; IsNan2008 = isNaN2008Default(); IsSingleFloat = false; FloatABI = HardFloat; DspRev = NoDSP; HasFP64 = isFP64Default(); for (const auto &Feature : Features) { if (Feature == "+single-float") IsSingleFloat = true; else if (Feature == "+soft-float") FloatABI = SoftFloat; else if (Feature == "+mips16") IsMips16 = true; else if (Feature == "+micromips") IsMicromips = true; else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); else if (Feature == "+dspr2") DspRev = std::max(DspRev, DSP2); else if (Feature == "+msa") HasMSA = true; else if (Feature == "+fp64") HasFP64 = true; else if (Feature == "-fp64") HasFP64 = false; else if (Feature == "+nan2008") IsNan2008 = true; else if (Feature == "-nan2008") IsNan2008 = false; } setDataLayout(); return true; } int getEHDataRegisterNumber(unsigned RegNo) const override { if (RegNo == 0) return 4; if (RegNo == 1) return 5; return -1; } bool isCLZForZeroUndef() const override { return false; } ArrayRef getGCCRegAliases() const override { static const TargetInfo::GCCRegAlias O32RegAliases[] = { {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, {{"a3"}, "$7"}, {{"t0"}, "$8"}, {{"t1"}, "$9"}, {{"t2"}, "$10"}, {{"t3"}, "$11"}, {{"t4"}, "$12"}, {{"t5"}, "$13"}, {{"t6"}, "$14"}, {{"t7"}, "$15"}, {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, {{"ra"}, "$31"}}; static const TargetInfo::GCCRegAlias NewABIRegAliases[] = { {{"at"}, "$1"}, {{"v0"}, "$2"}, {{"v1"}, "$3"}, {{"a0"}, "$4"}, {{"a1"}, "$5"}, {{"a2"}, "$6"}, {{"a3"}, "$7"}, {{"a4"}, "$8"}, {{"a5"}, "$9"}, {{"a6"}, "$10"}, {{"a7"}, "$11"}, {{"t0"}, "$12"}, {{"t1"}, "$13"}, {{"t2"}, "$14"}, {{"t3"}, "$15"}, {{"s0"}, "$16"}, {{"s1"}, "$17"}, {{"s2"}, "$18"}, {{"s3"}, "$19"}, {{"s4"}, "$20"}, {{"s5"}, "$21"}, {{"s6"}, "$22"}, {{"s7"}, "$23"}, {{"t8"}, "$24"}, {{"t9"}, "$25"}, {{"k0"}, "$26"}, {{"k1"}, "$27"}, {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"}, {{"ra"}, "$31"}}; if (ABI == "o32") return llvm::makeArrayRef(O32RegAliases); return llvm::makeArrayRef(NewABIRegAliases); } bool hasInt128Type() const override { return ABI == "n32" || ABI == "n64"; } bool validateTarget(DiagnosticsEngine &Diags) const override { // FIXME: It's valid to use O32 on a 64-bit CPU but the backend can't handle // this yet. It's better to fail here than on the backend assertion. if (processorSupportsGPR64() && ABI == "o32") { Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; return false; } // 64-bit ABI's require 64-bit CPU's. if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) { Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU; return false; } // FIXME: It's valid to use O32 on a mips64/mips64el triple but the backend // can't handle this yet. It's better to fail here than on the // backend assertion. if ((getTriple().getArch() == llvm::Triple::mips64 || getTriple().getArch() == llvm::Triple::mips64el) && ABI == "o32") { Diags.Report(diag::err_target_unsupported_abi_for_triple) << ABI << getTriple().str(); return false; } // FIXME: It's valid to use N32/N64 on a mips/mipsel triple but the backend // can't handle this yet. It's better to fail here than on the // backend assertion. if ((getTriple().getArch() == llvm::Triple::mips || getTriple().getArch() == llvm::Triple::mipsel) && (ABI == "n32" || ABI == "n64")) { Diags.Report(diag::err_target_unsupported_abi_for_triple) << ABI << getTriple().str(); return false; } return true; } }; const Builtin::Info MipsTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsMips.def" }; class PNaClTargetInfo : public TargetInfo { public: PNaClTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : TargetInfo(Triple) { BigEndian = false; this->LongAlign = 32; this->LongWidth = 32; this->PointerAlign = 32; this->PointerWidth = 32; this->IntMaxType = TargetInfo::SignedLongLong; this->Int64Type = TargetInfo::SignedLongLong; this->DoubleAlign = 64; this->LongDoubleWidth = 64; this->LongDoubleAlign = 64; this->SizeType = TargetInfo::UnsignedInt; this->PtrDiffType = TargetInfo::SignedInt; this->IntPtrType = TargetInfo::SignedInt; this->RegParmMax = 0; // Disallow regparm } void getArchDefines(const LangOptions &Opts, MacroBuilder &Builder) const { Builder.defineMacro("__le32__"); Builder.defineMacro("__pnacl__"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { getArchDefines(Opts, Builder); } bool hasFeature(StringRef Feature) const override { return Feature == "pnacl"; } ArrayRef getTargetBuiltins() const override { return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } ArrayRef getGCCRegNames() const override; ArrayRef getGCCRegAliases() const override; bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } const char *getClobbers() const override { return ""; } }; ArrayRef PNaClTargetInfo::getGCCRegNames() const { return None; } ArrayRef PNaClTargetInfo::getGCCRegAliases() const { return None; } // We attempt to use PNaCl (le32) frontend and Mips32EL backend. class NaClMips32TargetInfo : public MipsTargetInfo { public: NaClMips32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : MipsTargetInfo(Triple, Opts) {} BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } }; class Le64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; public: Le64TargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { BigEndian = false; NoAsmVariants = true; LongWidth = LongAlign = PointerWidth = PointerAlign = 64; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; resetDataLayout("e-m:e-v128:32-v16:16-v32:32-v96:32-n8:16:32:64-S128"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "unix", Opts); defineCPUMacros(Builder, "le64", /*Tuning=*/false); Builder.defineMacro("__ELF__"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::Le64::LastTSBuiltin - Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::PNaClABIBuiltinVaList; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { return None; } ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } bool hasProtectedVisibility() const override { return false; } }; class WebAssemblyTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; enum SIMDEnum { NoSIMD, SIMD128, } SIMDLevel; public: explicit WebAssemblyTargetInfo(const llvm::Triple &T, const TargetOptions &) : TargetInfo(T), SIMDLevel(NoSIMD) { BigEndian = false; NoAsmVariants = true; SuitableAlign = 128; LargeArrayMinWidth = 128; LargeArrayAlign = 128; SimdDefaultAlign = 128; SigAtomicType = SignedLong; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { defineCPUMacros(Builder, "wasm", /*Tuning=*/false); if (SIMDLevel >= SIMD128) Builder.defineMacro("__wasm_simd128__"); } private: bool initFeatureMap(llvm::StringMap &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector &FeaturesVec) const override { if (CPU == "bleeding-edge") Features["simd128"] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool hasFeature(StringRef Feature) const final { return llvm::StringSwitch(Feature) .Case("simd128", SIMDLevel >= SIMD128) .Default(false); } bool handleTargetFeatures(std::vector &Features, DiagnosticsEngine &Diags) final { for (const auto &Feature : Features) { if (Feature == "+simd128") { SIMDLevel = std::max(SIMDLevel, SIMD128); continue; } if (Feature == "-simd128") { SIMDLevel = std::min(SIMDLevel, SIMDEnum(SIMD128 - 1)); continue; } Diags.Report(diag::err_opt_not_valid_with_opt) << Feature << "-target-feature"; return false; } return true; } bool setCPU(const std::string &Name) final { return llvm::StringSwitch(Name) .Case("mvp", true) .Case("bleeding-edge", true) .Case("generic", true) .Default(false); } ArrayRef getTargetBuiltins() const final { return llvm::makeArrayRef(BuiltinInfo, clang::WebAssembly::LastTSBuiltin - Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const final { return VoidPtrBuiltinVaList; } ArrayRef getGCCRegNames() const final { return None; } ArrayRef getGCCRegAliases() const final { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const final { return false; } const char *getClobbers() const final { return ""; } bool isCLZForZeroUndef() const final { return false; } bool hasInt128Type() const final { return true; } IntType getIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { // WebAssembly prefers long long for explicitly 64-bit integers. return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) : TargetInfo::getIntTypeByWidth(BitWidth, IsSigned); } IntType getLeastIntTypeByWidth(unsigned BitWidth, bool IsSigned) const final { // WebAssembly uses long long for int_least64_t and int_fast64_t. return BitWidth == 64 ? (IsSigned ? SignedLongLong : UnsignedLongLong) : TargetInfo::getLeastIntTypeByWidth(BitWidth, IsSigned); } }; const Builtin::Info WebAssemblyTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsWebAssembly.def" }; class WebAssembly32TargetInfo : public WebAssemblyTargetInfo { public: explicit WebAssembly32TargetInfo(const llvm::Triple &T, const TargetOptions &Opts) : WebAssemblyTargetInfo(T, Opts) { MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; resetDataLayout("e-m:e-p:32:32-i64:64-n32:64-S128"); } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); defineCPUMacros(Builder, "wasm32", /*Tuning=*/false); } }; class WebAssembly64TargetInfo : public WebAssemblyTargetInfo { public: explicit WebAssembly64TargetInfo(const llvm::Triple &T, const TargetOptions &Opts) : WebAssemblyTargetInfo(T, Opts) { LongAlign = LongWidth = 64; PointerAlign = PointerWidth = 64; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; resetDataLayout("e-m:e-p:64:64-i64:64-n32:64-S128"); } protected: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WebAssemblyTargetInfo::getTargetDefines(Opts, Builder); defineCPUMacros(Builder, "wasm64", /*Tuning=*/false); } }; const Builtin::Info Le64TargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsLe64.def" }; static const unsigned SPIRAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local 2, // opencl_constant 4, // opencl_generic 0, // cuda_device 0, // cuda_constant 0 // cuda_shared }; class SPIRTargetInfo : public TargetInfo { public: SPIRTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { assert(getTriple().getOS() == llvm::Triple::UnknownOS && "SPIR target must use unknown OS"); assert(getTriple().getEnvironment() == llvm::Triple::UnknownEnvironment && "SPIR target must use unknown environment type"); BigEndian = false; TLSSupported = false; LongWidth = LongAlign = 64; AddrSpaceMap = &SPIRAddrSpaceMap; UseAddrSpaceMapMangling = true; // Define available target features // These must be defined in sorted order! NoAsmVariants = true; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR", Opts); } bool hasFeature(StringRef Feature) const override { return Feature == "spir"; } ArrayRef getTargetBuiltins() const override { return None; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { return true; } ArrayRef getGCCRegAliases() const override { return None; } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { return (CC == CC_SpirFunction || CC == CC_OpenCLKernel) ? CCCR_OK : CCCR_Warning; } CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { return CC_SpirFunction; } void setSupportedOpenCLOpts() override { // Assume all OpenCL extensions and optional core features are supported // for SPIR since it is a generic target. getSupportedOpenCLOpts().setAll(); } }; class SPIR32TargetInfo : public SPIRTargetInfo { public: SPIR32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRTargetInfo(Triple, Opts) { PointerWidth = PointerAlign = 32; SizeType = TargetInfo::UnsignedInt; PtrDiffType = IntPtrType = TargetInfo::SignedInt; resetDataLayout("e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-" "v96:128-v192:256-v256:256-v512:512-v1024:1024"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR32", Opts); } }; class SPIR64TargetInfo : public SPIRTargetInfo { public: SPIR64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : SPIRTargetInfo(Triple, Opts) { PointerWidth = PointerAlign = 64; SizeType = TargetInfo::UnsignedLong; PtrDiffType = IntPtrType = TargetInfo::SignedLong; resetDataLayout("e-i64:64-v16:16-v24:32-v32:32-v48:64-" "v96:128-v192:256-v256:256-v512:512-v1024:1024"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { DefineStd(Builder, "SPIR64", Opts); } }; class XCoreTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; public: XCoreTargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { BigEndian = false; NoAsmVariants = true; LongLongAlign = 32; SuitableAlign = 32; DoubleAlign = LongDoubleAlign = 32; SizeType = UnsignedInt; PtrDiffType = SignedInt; IntPtrType = SignedInt; WCharType = UnsignedChar; WIntType = UnsignedInt; UseZeroLengthBitfieldAlignment = true; resetDataLayout("e-m:e-p:32:32-i1:8:32-i8:8:32-i16:16:32-i64:32" "-f64:32-a:0:32-n32"); } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__XS1B__"); } ArrayRef getTargetBuiltins() const override { return llvm::makeArrayRef(BuiltinInfo, clang::XCore::LastTSBuiltin-Builtin::FirstTSBuiltin); } BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } const char *getClobbers() const override { return ""; } ArrayRef getGCCRegNames() const override { static const char * const GCCRegNames[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "cp", "dp", "sp", "lr" }; return llvm::makeArrayRef(GCCRegNames); } ArrayRef getGCCRegAliases() const override { return None; } bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const override { return false; } int getEHDataRegisterNumber(unsigned RegNo) const override { // R0=ExceptionPointerRegister R1=ExceptionSelectorRegister return (RegNo < 2)? RegNo : -1; } bool allowsLargerPreferedTypeAlignment() const override { return false; } }; const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) \ { #ID, TYPE, ATTRS, nullptr, ALL_LANGUAGES, nullptr }, #define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) \ { #ID, TYPE, ATTRS, HEADER, ALL_LANGUAGES, nullptr }, #include "clang/Basic/BuiltinsXCore.def" }; // x86_32 Android target class AndroidX86_32TargetInfo : public LinuxTargetInfo { public: AndroidX86_32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : LinuxTargetInfo(Triple, Opts) { SuitableAlign = 32; LongDoubleWidth = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } }; // x86_64 Android target class AndroidX86_64TargetInfo : public LinuxTargetInfo { public: AndroidX86_64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : LinuxTargetInfo(Triple, Opts) { LongDoubleFormat = &llvm::APFloat::IEEEquad; } bool useFloat128ManglingForLongDouble() const override { return true; } }; // 32-bit RenderScript is armv7 with width and align of 'long' set to 8-bytes class RenderScript32TargetInfo : public ARMleTargetInfo { public: RenderScript32TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : ARMleTargetInfo(llvm::Triple("armv7", Triple.getVendorName(), Triple.getOSName(), Triple.getEnvironmentName()), Opts) { LongWidth = LongAlign = 64; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__RENDERSCRIPT__"); ARMleTargetInfo::getTargetDefines(Opts, Builder); } }; // 64-bit RenderScript is aarch64 class RenderScript64TargetInfo : public AArch64leTargetInfo { public: RenderScript64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : AArch64leTargetInfo(llvm::Triple("aarch64", Triple.getVendorName(), Triple.getOSName(), Triple.getEnvironmentName()), Opts) {} void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__RENDERSCRIPT__"); AArch64leTargetInfo::getTargetDefines(Opts, Builder); } }; } // end anonymous namespace //===----------------------------------------------------------------------===// // Driver code //===----------------------------------------------------------------------===// static TargetInfo *AllocateTarget(const llvm::Triple &Triple, const TargetOptions &Opts) { llvm::Triple::OSType os = Triple.getOS(); switch (Triple.getArch()) { default: return nullptr; case llvm::Triple::xcore: return new XCoreTargetInfo(Triple, Opts); case llvm::Triple::hexagon: return new HexagonTargetInfo(Triple, Opts); case llvm::Triple::lanai: return new LanaiTargetInfo(Triple, Opts); case llvm::Triple::aarch64: if (Triple.isOSDarwin()) return new DarwinAArch64TargetInfo(Triple, Opts); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); default: return new AArch64leTargetInfo(Triple, Opts); } case llvm::Triple::aarch64_be: switch (os) { case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); default: return new AArch64beTargetInfo(Triple, Opts); } case llvm::Triple::arm: case llvm::Triple::thumb: if (Triple.isOSBinFormatMachO()) return new DarwinARMTargetInfo(Triple, Opts); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::Bitrig: return new BitrigTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); case llvm::Triple::Win32: switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinARMTargetInfo(Triple, Opts); case llvm::Triple::GNU: return new MinGWARMTargetInfo(Triple, Opts); case llvm::Triple::Itanium: return new ItaniumWindowsARMleTargetInfo(Triple, Opts); case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftARMleTargetInfo(Triple, Opts); } default: return new ARMleTargetInfo(Triple, Opts); } case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (Triple.isOSDarwin()) return new DarwinARMTargetInfo(Triple, Opts); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::Bitrig: return new BitrigTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); default: return new ARMbeTargetInfo(Triple, Opts); } case llvm::Triple::bpfeb: case llvm::Triple::bpfel: return new BPFTargetInfo(Triple, Opts); case llvm::Triple::msp430: return new MSP430TargetInfo(Triple, Opts); case llvm::Triple::mips: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); default: return new MipsTargetInfo(Triple, Opts); } case llvm::Triple::mipsel: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); default: return new MipsTargetInfo(Triple, Opts); } case llvm::Triple::mips64: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); default: return new MipsTargetInfo(Triple, Opts); } case llvm::Triple::mips64el: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); default: return new MipsTargetInfo(Triple, Opts); } case llvm::Triple::le32: switch (os) { case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); default: return nullptr; } case llvm::Triple::le64: return new Le64TargetInfo(Triple, Opts); case llvm::Triple::ppc: if (Triple.isOSDarwin()) return new DarwinPPC32TargetInfo(Triple, Opts); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); default: return new PPC32TargetInfo(Triple, Opts); } case llvm::Triple::ppc64: if (Triple.isOSDarwin()) return new DarwinPPC64TargetInfo(Triple, Opts); switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::Lv2: return new PS3PPUTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); default: return new PPC64TargetInfo(Triple, Opts); } case llvm::Triple::ppc64le: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); default: return new PPC64TargetInfo(Triple, Opts); } case llvm::Triple::nvptx: return new NVPTX32TargetInfo(Triple, Opts); case llvm::Triple::nvptx64: return new NVPTX64TargetInfo(Triple, Opts); case llvm::Triple::amdgcn: case llvm::Triple::r600: return new AMDGPUTargetInfo(Triple, Opts); case llvm::Triple::sparc: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); default: return new SparcV8TargetInfo(Triple, Opts); } // The 'sparcel' architecture copies all the above cases except for Solaris. case llvm::Triple::sparcel: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSTargetInfo(Triple, Opts); default: return new SparcV8elTargetInfo(Triple, Opts); } case llvm::Triple::sparcv9: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDTargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); default: return new SparcV9TargetInfo(Triple, Opts); } case llvm::Triple::systemz: switch (os) { case llvm::Triple::Linux: return new LinuxTargetInfo(Triple, Opts); default: return new SystemZTargetInfo(Triple, Opts); } case llvm::Triple::tce: return new TCETargetInfo(Triple, Opts); case llvm::Triple::x86: if (Triple.isOSDarwin()) return new DarwinI386TargetInfo(Triple, Opts); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::Linux: { switch (Triple.getEnvironment()) { default: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::Android: return new AndroidX86_32TargetInfo(Triple, Opts); } } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDI386TargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDI386TargetInfo(Triple, Opts); case llvm::Triple::Bitrig: return new BitrigI386TargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::KFreeBSD: return new KFreeBSDTargetInfo(Triple, Opts); case llvm::Triple::Minix: return new MinixTargetInfo(Triple, Opts); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple, Opts); case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinX86_32TargetInfo(Triple, Opts); case llvm::Triple::GNU: return new MinGWX86_32TargetInfo(Triple, Opts); case llvm::Triple::Itanium: case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftX86_32TargetInfo(Triple, Opts); } } case llvm::Triple::Haiku: return new HaikuX86_32TargetInfo(Triple, Opts); case llvm::Triple::RTEMS: return new RTEMSX86_32TargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); case llvm::Triple::ELFIAMCU: return new MCUX86_32TargetInfo(Triple, Opts); default: return new X86_32TargetInfo(Triple, Opts); } case llvm::Triple::x86_64: if (Triple.isOSDarwin() || Triple.isOSBinFormatMachO()) return new DarwinX86_64TargetInfo(Triple, Opts); switch (os) { case llvm::Triple::CloudABI: return new CloudABITargetInfo(Triple, Opts); case llvm::Triple::Linux: { switch (Triple.getEnvironment()) { default: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::Android: return new AndroidX86_64TargetInfo(Triple, Opts); } } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); case llvm::Triple::OpenBSD: return new OpenBSDX86_64TargetInfo(Triple, Opts); case llvm::Triple::Bitrig: return new BitrigX86_64TargetInfo(Triple, Opts); case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo(Triple, Opts); case llvm::Triple::KFreeBSD: return new KFreeBSDTargetInfo(Triple, Opts); case llvm::Triple::Solaris: return new SolarisTargetInfo(Triple, Opts); case llvm::Triple::Win32: { switch (Triple.getEnvironment()) { case llvm::Triple::Cygnus: return new CygwinX86_64TargetInfo(Triple, Opts); case llvm::Triple::GNU: return new MinGWX86_64TargetInfo(Triple, Opts); case llvm::Triple::MSVC: default: // Assume MSVC for unknown environments return new MicrosoftX86_64TargetInfo(Triple, Opts); } } case llvm::Triple::Haiku: return new HaikuTargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); case llvm::Triple::PS4: return new PS4OSTargetInfo(Triple, Opts); default: return new X86_64TargetInfo(Triple, Opts); } case llvm::Triple::spir: { if (Triple.getOS() != llvm::Triple::UnknownOS || Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) return nullptr; return new SPIR32TargetInfo(Triple, Opts); } case llvm::Triple::spir64: { if (Triple.getOS() != llvm::Triple::UnknownOS || Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) return nullptr; return new SPIR64TargetInfo(Triple, Opts); } case llvm::Triple::wasm32: if (!(Triple == llvm::Triple("wasm32-unknown-unknown"))) return nullptr; return new WebAssemblyOSTargetInfo(Triple, Opts); case llvm::Triple::wasm64: if (!(Triple == llvm::Triple("wasm64-unknown-unknown"))) return nullptr; return new WebAssemblyOSTargetInfo(Triple, Opts); case llvm::Triple::renderscript32: return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::renderscript64: return new LinuxTargetInfo(Triple, Opts); } } /// CreateTargetInfo - Return the target info object for the specified target /// options. TargetInfo * TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr &Opts) { llvm::Triple Triple(Opts->Triple); // Construct the target std::unique_ptr Target(AllocateTarget(Triple, *Opts)); if (!Target) { Diags.Report(diag::err_target_unknown_triple) << Triple.str(); return nullptr; } Target->TargetOpts = Opts; // Set the target CPU if specified. if (!Opts->CPU.empty() && !Target->setCPU(Opts->CPU)) { Diags.Report(diag::err_target_unknown_cpu) << Opts->CPU; return nullptr; } // Set the target ABI if specified. if (!Opts->ABI.empty() && !Target->setABI(Opts->ABI)) { Diags.Report(diag::err_target_unknown_abi) << Opts->ABI; return nullptr; } // Set the fp math unit. if (!Opts->FPMath.empty() && !Target->setFPMath(Opts->FPMath)) { Diags.Report(diag::err_target_unknown_fpmath) << Opts->FPMath; return nullptr; } // Compute the default target features, we need the target to handle this // because features may have dependencies on one another. llvm::StringMap Features; if (!Target->initFeatureMap(Features, Diags, Opts->CPU, Opts->FeaturesAsWritten)) return nullptr; // Add the features to the compile options. Opts->Features.clear(); for (const auto &F : Features) Opts->Features.push_back((F.getValue() ? "+" : "-") + F.getKey().str()); if (!Target->handleTargetFeatures(Opts->Features, Diags)) return nullptr; Target->setSupportedOpenCLOpts(); if (!Target->validateTarget(Diags)) return nullptr; return Target.release(); } diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 8937685fdc7b..d214340bdafe 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -1,3672 +1,3660 @@ //===--- CGStmtOpenMP.cpp - Emit LLVM Code from Statements ----------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This contains code to emit OpenMP nodes as LLVM code. // //===----------------------------------------------------------------------===// #include "CGCleanup.h" #include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/DeclOpenMP.h" #include "llvm/IR/CallSite.h" using namespace clang; using namespace CodeGen; namespace { /// Lexical scope for OpenMP executable constructs, that handles correct codegen /// for captured expressions. class OMPLexicalScope final : public CodeGenFunction::LexicalScope { void emitPreInitStmt(CodeGenFunction &CGF, const OMPExecutableDirective &S) { for (const auto *C : S.clauses()) { if (auto *CPI = OMPClauseWithPreInit::get(C)) { if (auto *PreInit = cast_or_null(CPI->getPreInitStmt())) { for (const auto *I : PreInit->decls()) { if (!I->hasAttr()) CGF.EmitVarDecl(cast(*I)); else { CodeGenFunction::AutoVarEmission Emission = CGF.EmitAutoVarAlloca(cast(*I)); CGF.EmitAutoVarCleanups(Emission); } } } } } } CodeGenFunction::OMPPrivateScope InlinedShareds; static bool isCapturedVar(CodeGenFunction &CGF, const VarDecl *VD) { return CGF.LambdaCaptureFields.lookup(VD) || (CGF.CapturedStmtInfo && CGF.CapturedStmtInfo->lookup(VD)) || (CGF.CurCodeDecl && isa(CGF.CurCodeDecl)); } public: OMPLexicalScope(CodeGenFunction &CGF, const OMPExecutableDirective &S, bool AsInlined = false) : CodeGenFunction::LexicalScope(CGF, S.getSourceRange()), InlinedShareds(CGF) { emitPreInitStmt(CGF, S); if (AsInlined) { if (S.hasAssociatedStmt()) { auto *CS = cast(S.getAssociatedStmt()); for (auto &C : CS->captures()) { if (C.capturesVariable() || C.capturesVariableByCopy()) { auto *VD = C.getCapturedVar(); DeclRefExpr DRE(const_cast(VD), isCapturedVar(CGF, VD) || (CGF.CapturedStmtInfo && InlinedShareds.isGlobalVarCaptured(VD)), VD->getType().getNonReferenceType(), VK_LValue, SourceLocation()); InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address { return CGF.EmitLValue(&DRE).getAddress(); }); } } (void)InlinedShareds.Privatize(); } } } }; /// Private scope for OpenMP loop-based directives, that supports capturing /// of used expression from loop statement. class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { void emitPreInitStmt(CodeGenFunction &CGF, const OMPLoopDirective &S) { if (auto *LD = dyn_cast(&S)) { if (auto *PreInits = cast_or_null(LD->getPreInits())) { for (const auto *I : PreInits->decls()) CGF.EmitVarDecl(cast(*I)); } } } public: OMPLoopScope(CodeGenFunction &CGF, const OMPLoopDirective &S) : CodeGenFunction::RunCleanupsScope(CGF) { emitPreInitStmt(CGF, S); } }; } // namespace llvm::Value *CodeGenFunction::getTypeSize(QualType Ty) { auto &C = getContext(); llvm::Value *Size = nullptr; auto SizeInChars = C.getTypeSizeInChars(Ty); if (SizeInChars.isZero()) { // getTypeSizeInChars() returns 0 for a VLA. while (auto *VAT = C.getAsVariableArrayType(Ty)) { llvm::Value *ArraySize; std::tie(ArraySize, Ty) = getVLASize(VAT); Size = Size ? Builder.CreateNUWMul(Size, ArraySize) : ArraySize; } SizeInChars = C.getTypeSizeInChars(Ty); if (SizeInChars.isZero()) return llvm::ConstantInt::get(SizeTy, /*V=*/0); Size = Builder.CreateNUWMul(Size, CGM.getSize(SizeInChars)); } else Size = CGM.getSize(SizeInChars); return Size; } void CodeGenFunction::GenerateOpenMPCapturedVars( const CapturedStmt &S, SmallVectorImpl &CapturedVars) { const RecordDecl *RD = S.getCapturedRecordDecl(); auto CurField = RD->field_begin(); auto CurCap = S.captures().begin(); for (CapturedStmt::const_capture_init_iterator I = S.capture_init_begin(), E = S.capture_init_end(); I != E; ++I, ++CurField, ++CurCap) { if (CurField->hasCapturedVLAType()) { auto VAT = CurField->getCapturedVLAType(); auto *Val = VLASizeMap[VAT->getSizeExpr()]; CapturedVars.push_back(Val); } else if (CurCap->capturesThis()) CapturedVars.push_back(CXXThisValue); else if (CurCap->capturesVariableByCopy()) { llvm::Value *CV = EmitLoadOfLValue(EmitLValue(*I), SourceLocation()).getScalarVal(); // If the field is not a pointer, we need to save the actual value // and load it as a void pointer. if (!CurField->getType()->isAnyPointerType()) { auto &Ctx = getContext(); auto DstAddr = CreateMemTemp( Ctx.getUIntPtrType(), Twine(CurCap->getCapturedVar()->getName()) + ".casted"); LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType()); auto *SrcAddrVal = EmitScalarConversion( DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()), Ctx.getPointerType(CurField->getType()), SourceLocation()); LValue SrcLV = MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType()); // Store the value using the source type pointer. EmitStoreThroughLValue(RValue::get(CV), SrcLV); // Load the value using the destination type pointer. CV = EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal(); } CapturedVars.push_back(CV); } else { assert(CurCap->capturesVariable() && "Expected capture by reference."); CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer()); } } } static Address castValueFromUintptr(CodeGenFunction &CGF, QualType DstType, StringRef Name, LValue AddrLV, bool isReferenceType = false) { ASTContext &Ctx = CGF.getContext(); auto *CastedPtr = CGF.EmitScalarConversion( AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(), Ctx.getPointerType(DstType), SourceLocation()); auto TmpAddr = CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType)) .getAddress(); // If we are dealing with references we need to return the address of the // reference instead of the reference of the value. if (isReferenceType) { QualType RefType = Ctx.getLValueReferenceType(DstType); auto *RefVal = TmpAddr.getPointer(); TmpAddr = CGF.CreateMemTemp(RefType, Twine(Name) + ".ref"); auto TmpLVal = CGF.MakeAddrLValue(TmpAddr, RefType); CGF.EmitScalarInit(RefVal, TmpLVal); } return TmpAddr; } llvm::Function * CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { assert( CapturedStmtInfo && "CapturedStmtInfo should be set when generating the captured function"); const CapturedDecl *CD = S.getCapturedDecl(); const RecordDecl *RD = S.getCapturedRecordDecl(); assert(CD->hasBody() && "missing CapturedDecl body"); // Build the argument list. ASTContext &Ctx = CGM.getContext(); FunctionArgList Args; Args.append(CD->param_begin(), std::next(CD->param_begin(), CD->getContextParamPosition())); auto I = S.captures().begin(); for (auto *FD : RD->fields()) { QualType ArgType = FD->getType(); IdentifierInfo *II = nullptr; VarDecl *CapVar = nullptr; // If this is a capture by copy and the type is not a pointer, the outlined // function argument type should be uintptr and the value properly casted to // uintptr. This is necessary given that the runtime library is only able to // deal with pointers. We can pass in the same way the VLA type sizes to the // outlined function. if ((I->capturesVariableByCopy() && !ArgType->isAnyPointerType()) || I->capturesVariableArrayType()) ArgType = Ctx.getUIntPtrType(); if (I->capturesVariable() || I->capturesVariableByCopy()) { CapVar = I->getCapturedVar(); II = CapVar->getIdentifier(); } else if (I->capturesThis()) II = &getContext().Idents.get("this"); else { assert(I->capturesVariableArrayType()); II = &getContext().Idents.get("vla"); } if (ArgType->isVariablyModifiedType()) { bool IsReference = ArgType->isLValueReferenceType(); ArgType = getContext().getCanonicalParamType(ArgType.getNonReferenceType()); if (IsReference && !ArgType->isPointerType()) { ArgType = getContext().getLValueReferenceType( ArgType, /*SpelledAsLValue=*/false); } } Args.push_back(ImplicitParamDecl::Create(getContext(), nullptr, FD->getLocation(), II, ArgType)); ++I; } Args.append( std::next(CD->param_begin(), CD->getContextParamPosition() + 1), CD->param_end()); // Create the function declaration. FunctionType::ExtInfo ExtInfo; const CGFunctionInfo &FuncInfo = CGM.getTypes().arrangeBuiltinFunctionDeclaration(Ctx.VoidTy, Args); llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo); llvm::Function *F = llvm::Function::Create( FuncLLVMTy, llvm::GlobalValue::InternalLinkage, CapturedStmtInfo->getHelperName(), &CGM.getModule()); CGM.SetInternalFunctionAttributes(CD, F, FuncInfo); if (CD->isNothrow()) F->addFnAttr(llvm::Attribute::NoUnwind); // Generate the function. StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getLocation(), CD->getBody()->getLocStart()); unsigned Cnt = CD->getContextParamPosition(); I = S.captures().begin(); for (auto *FD : RD->fields()) { // If we are capturing a pointer by copy we don't need to do anything, just // use the value that we get from the arguments. if (I->capturesVariableByCopy() && FD->getType()->isAnyPointerType()) { setAddrOfLocalVar(I->getCapturedVar(), GetAddrOfLocalVar(Args[Cnt])); ++Cnt; ++I; continue; } LValue ArgLVal = MakeAddrLValue(GetAddrOfLocalVar(Args[Cnt]), Args[Cnt]->getType(), AlignmentSource::Decl); if (FD->hasCapturedVLAType()) { LValue CastedArgLVal = MakeAddrLValue(castValueFromUintptr(*this, FD->getType(), Args[Cnt]->getName(), ArgLVal), FD->getType(), AlignmentSource::Decl); auto *ExprArg = EmitLoadOfLValue(CastedArgLVal, SourceLocation()).getScalarVal(); auto VAT = FD->getCapturedVLAType(); VLASizeMap[VAT->getSizeExpr()] = ExprArg; } else if (I->capturesVariable()) { auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); Address ArgAddr = ArgLVal.getAddress(); if (!VarTy->isReferenceType()) { if (ArgLVal.getType()->isLValueReferenceType()) { ArgAddr = EmitLoadOfReference( ArgAddr, ArgLVal.getType()->castAs()); } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) { assert(ArgLVal.getType()->isPointerType()); ArgAddr = EmitLoadOfPointer( ArgAddr, ArgLVal.getType()->castAs()); } } setAddrOfLocalVar( Var, Address(ArgAddr.getPointer(), getContext().getDeclAlign(Var))); } else if (I->capturesVariableByCopy()) { assert(!FD->getType()->isAnyPointerType() && "Not expecting a captured pointer."); auto *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); setAddrOfLocalVar(Var, castValueFromUintptr(*this, FD->getType(), Args[Cnt]->getName(), ArgLVal, VarTy->isReferenceType())); } else { // If 'this' is captured, load it into CXXThisValue. assert(I->capturesThis()); CXXThisValue = EmitLoadOfLValue(ArgLVal, Args[Cnt]->getLocation()).getScalarVal(); } ++Cnt; ++I; } PGO.assignRegionCounters(GlobalDecl(CD), F); CapturedStmtInfo->EmitBody(*this, CD->getBody()); FinishFunction(CD->getBodyRBrace()); return F; } //===----------------------------------------------------------------------===// // OpenMP Directive Emission //===----------------------------------------------------------------------===// void CodeGenFunction::EmitOMPAggregateAssign( Address DestAddr, Address SrcAddr, QualType OriginalType, const llvm::function_ref &CopyGen) { // Perform element-by-element initialization. QualType ElementTy; // Drill down to the base element type on both arrays. auto ArrayTy = OriginalType->getAsArrayTypeUnsafe(); auto NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr); SrcAddr = Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType()); auto SrcBegin = SrcAddr.getPointer(); auto DestBegin = DestAddr.getPointer(); // Cast from pointer to array type to pointer to single element. auto DestEnd = Builder.CreateGEP(DestBegin, NumElements); // The basic structure here is a while-do loop. auto BodyBB = createBasicBlock("omp.arraycpy.body"); auto DoneBB = createBasicBlock("omp.arraycpy.done"); auto IsEmpty = Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arraycpy.isempty"); Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Enter the loop body, making that address the current address. auto EntryBB = Builder.GetInsertBlock(); EmitBlock(BodyBB); CharUnits ElementSize = getContext().getTypeSizeInChars(ElementTy); llvm::PHINode *SrcElementPHI = Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast"); SrcElementPHI->addIncoming(SrcBegin, EntryBB); Address SrcElementCurrent = Address(SrcElementPHI, SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize)); llvm::PHINode *DestElementPHI = Builder.CreatePHI(DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); DestElementPHI->addIncoming(DestBegin, EntryBB); Address DestElementCurrent = Address(DestElementPHI, DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); // Emit copy. CopyGen(DestElementCurrent, SrcElementCurrent); // Shift the address forward by one element. auto DestElementNext = Builder.CreateConstGEP1_32( DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element"); auto SrcElementNext = Builder.CreateConstGEP1_32( SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.src.element"); // Check whether we've reached the end. auto Done = Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done"); Builder.CreateCondBr(Done, DoneBB, BodyBB); DestElementPHI->addIncoming(DestElementNext, Builder.GetInsertBlock()); SrcElementPHI->addIncoming(SrcElementNext, Builder.GetInsertBlock()); // Done. EmitBlock(DoneBB, /*IsFinished=*/true); } /// Check if the combiner is a call to UDR combiner and if it is so return the /// UDR decl used for reduction. static const OMPDeclareReductionDecl * getReductionInit(const Expr *ReductionOp) { if (auto *CE = dyn_cast(ReductionOp)) if (auto *OVE = dyn_cast(CE->getCallee())) if (auto *DRE = dyn_cast(OVE->getSourceExpr()->IgnoreImpCasts())) if (auto *DRD = dyn_cast(DRE->getDecl())) return DRD; return nullptr; } static void emitInitWithReductionInitializer(CodeGenFunction &CGF, const OMPDeclareReductionDecl *DRD, const Expr *InitOp, Address Private, Address Original, QualType Ty) { if (DRD->getInitializer()) { std::pair Reduction = CGF.CGM.getOpenMPRuntime().getUserDefinedReduction(DRD); auto *CE = cast(InitOp); auto *OVE = cast(CE->getCallee()); const Expr *LHS = CE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); const Expr *RHS = CE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); auto *LHSDRE = cast(cast(LHS)->getSubExpr()); auto *RHSDRE = cast(cast(RHS)->getSubExpr()); CodeGenFunction::OMPPrivateScope PrivateScope(CGF); PrivateScope.addPrivate(cast(LHSDRE->getDecl()), [=]() -> Address { return Private; }); PrivateScope.addPrivate(cast(RHSDRE->getDecl()), [=]() -> Address { return Original; }); (void)PrivateScope.Privatize(); RValue Func = RValue::get(Reduction.second); CodeGenFunction::OpaqueValueMapping Map(CGF, OVE, Func); CGF.EmitIgnoredExpr(InitOp); } else { llvm::Constant *Init = CGF.CGM.EmitNullConstant(Ty); auto *GV = new llvm::GlobalVariable( CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, ".init"); LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty); RValue InitRVal; switch (CGF.getEvaluationKind(Ty)) { case TEK_Scalar: InitRVal = CGF.EmitLoadOfLValue(LV, SourceLocation()); break; case TEK_Complex: InitRVal = RValue::getComplex(CGF.EmitLoadOfComplex(LV, SourceLocation())); break; case TEK_Aggregate: InitRVal = RValue::getAggregate(LV.getAddress()); break; } OpaqueValueExpr OVE(SourceLocation(), Ty, VK_RValue); CodeGenFunction::OpaqueValueMapping OpaqueMap(CGF, &OVE, InitRVal); CGF.EmitAnyExprToMem(&OVE, Private, Ty.getQualifiers(), /*IsInitializer=*/false); } } /// \brief Emit initialization of arrays of complex types. /// \param DestAddr Address of the array. /// \param Type Type of array. /// \param Init Initial expression of array. /// \param SrcAddr Address of the original array. static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, QualType Type, const Expr *Init, Address SrcAddr = Address::invalid()) { auto *DRD = getReductionInit(Init); // Perform element-by-element initialization. QualType ElementTy; // Drill down to the base element type on both arrays. auto ArrayTy = Type->getAsArrayTypeUnsafe(); auto NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, DestAddr); DestAddr = CGF.Builder.CreateElementBitCast(DestAddr, DestAddr.getElementType()); if (DRD) SrcAddr = CGF.Builder.CreateElementBitCast(SrcAddr, DestAddr.getElementType()); llvm::Value *SrcBegin = nullptr; if (DRD) SrcBegin = SrcAddr.getPointer(); auto DestBegin = DestAddr.getPointer(); // Cast from pointer to array type to pointer to single element. auto DestEnd = CGF.Builder.CreateGEP(DestBegin, NumElements); // The basic structure here is a while-do loop. auto BodyBB = CGF.createBasicBlock("omp.arrayinit.body"); auto DoneBB = CGF.createBasicBlock("omp.arrayinit.done"); auto IsEmpty = CGF.Builder.CreateICmpEQ(DestBegin, DestEnd, "omp.arrayinit.isempty"); CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Enter the loop body, making that address the current address. auto EntryBB = CGF.Builder.GetInsertBlock(); CGF.EmitBlock(BodyBB); CharUnits ElementSize = CGF.getContext().getTypeSizeInChars(ElementTy); llvm::PHINode *SrcElementPHI = nullptr; Address SrcElementCurrent = Address::invalid(); if (DRD) { SrcElementPHI = CGF.Builder.CreatePHI(SrcBegin->getType(), 2, "omp.arraycpy.srcElementPast"); SrcElementPHI->addIncoming(SrcBegin, EntryBB); SrcElementCurrent = Address(SrcElementPHI, SrcAddr.getAlignment().alignmentOfArrayElement(ElementSize)); } llvm::PHINode *DestElementPHI = CGF.Builder.CreatePHI( DestBegin->getType(), 2, "omp.arraycpy.destElementPast"); DestElementPHI->addIncoming(DestBegin, EntryBB); Address DestElementCurrent = Address(DestElementPHI, DestAddr.getAlignment().alignmentOfArrayElement(ElementSize)); // Emit copy. { CodeGenFunction::RunCleanupsScope InitScope(CGF); if (DRD && (DRD->getInitializer() || !Init)) { emitInitWithReductionInitializer(CGF, DRD, Init, DestElementCurrent, SrcElementCurrent, ElementTy); } else CGF.EmitAnyExprToMem(Init, DestElementCurrent, ElementTy.getQualifiers(), /*IsInitializer=*/false); } if (DRD) { // Shift the address forward by one element. auto SrcElementNext = CGF.Builder.CreateConstGEP1_32( SrcElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element"); SrcElementPHI->addIncoming(SrcElementNext, CGF.Builder.GetInsertBlock()); } // Shift the address forward by one element. auto DestElementNext = CGF.Builder.CreateConstGEP1_32( DestElementPHI, /*Idx0=*/1, "omp.arraycpy.dest.element"); // Check whether we've reached the end. auto Done = CGF.Builder.CreateICmpEQ(DestElementNext, DestEnd, "omp.arraycpy.done"); CGF.Builder.CreateCondBr(Done, DoneBB, BodyBB); DestElementPHI->addIncoming(DestElementNext, CGF.Builder.GetInsertBlock()); // Done. CGF.EmitBlock(DoneBB, /*IsFinished=*/true); } void CodeGenFunction::EmitOMPCopy(QualType OriginalType, Address DestAddr, Address SrcAddr, const VarDecl *DestVD, const VarDecl *SrcVD, const Expr *Copy) { if (OriginalType->isArrayType()) { auto *BO = dyn_cast(Copy); if (BO && BO->getOpcode() == BO_Assign) { // Perform simple memcpy for simple copying. EmitAggregateAssign(DestAddr, SrcAddr, OriginalType); } else { // For arrays with complex element types perform element by element // copying. EmitOMPAggregateAssign( DestAddr, SrcAddr, OriginalType, [this, Copy, SrcVD, DestVD](Address DestElement, Address SrcElement) { // Working with the single array element, so have to remap // destination and source variables to corresponding array // elements. CodeGenFunction::OMPPrivateScope Remap(*this); Remap.addPrivate(DestVD, [DestElement]() -> Address { return DestElement; }); Remap.addPrivate( SrcVD, [SrcElement]() -> Address { return SrcElement; }); (void)Remap.Privatize(); EmitIgnoredExpr(Copy); }); } } else { // Remap pseudo source variable to private copy. CodeGenFunction::OMPPrivateScope Remap(*this); Remap.addPrivate(SrcVD, [SrcAddr]() -> Address { return SrcAddr; }); Remap.addPrivate(DestVD, [DestAddr]() -> Address { return DestAddr; }); (void)Remap.Privatize(); // Emit copying of the whole variable. EmitIgnoredExpr(Copy); } } bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return false; bool FirstprivateIsLastprivate = false; llvm::DenseSet Lastprivates; for (const auto *C : D.getClausesOfKind()) { for (const auto *D : C->varlists()) Lastprivates.insert( cast(cast(D)->getDecl())->getCanonicalDecl()); } llvm::DenseSet EmittedAsFirstprivate; CGCapturedStmtInfo CapturesInfo(cast(*D.getAssociatedStmt())); for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto InitsRef = C->inits().begin(); for (auto IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); bool ThisFirstprivateIsLastprivate = Lastprivates.count(OrigVD->getCanonicalDecl()) > 0; auto *CapFD = CapturesInfo.lookup(OrigVD); auto *FD = CapturedStmtInfo->lookup(OrigVD); if (!ThisFirstprivateIsLastprivate && FD && (FD == CapFD) && !FD->getType()->isReferenceType()) { EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl()); ++IRef; ++InitsRef; continue; } FirstprivateIsLastprivate = FirstprivateIsLastprivate || ThisFirstprivateIsLastprivate; if (EmittedAsFirstprivate.insert(OrigVD->getCanonicalDecl()).second) { auto *VD = cast(cast(IInit)->getDecl()); auto *VDInit = cast(cast(*InitsRef)->getDecl()); bool IsRegistered; DeclRefExpr DRE(const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/FD != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); Address OriginalAddr = EmitLValue(&DRE).getAddress(); QualType Type = VD->getType(); if (Type->isArrayType()) { // Emit VarDecl with copy init for arrays. // Get the address of the original variable captured in current // captured region. IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { auto Emission = EmitAutoVarAlloca(*VD); auto *Init = VD->getInit(); if (!isa(Init) || isTrivialInitializer(Init)) { // Perform simple memcpy. EmitAggregateAssign(Emission.getAllocatedAddress(), OriginalAddr, Type); } else { EmitOMPAggregateAssign( Emission.getAllocatedAddress(), OriginalAddr, Type, [this, VDInit, Init](Address DestElement, Address SrcElement) { // Clean up any temporaries needed by the initialization. RunCleanupsScope InitScope(*this); // Emit initialization for single element. setAddrOfLocalVar(VDInit, SrcElement); EmitAnyExprToMem(Init, DestElement, Init->getType().getQualifiers(), /*IsInitializer*/ false); LocalDeclMap.erase(VDInit); }); } EmitAutoVarCleanups(Emission); return Emission.getAllocatedAddress(); }); } else { IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. // Remap temp VDInit variable to the address of the original // variable // (for proper handling of captured global variables). setAddrOfLocalVar(VDInit, OriginalAddr); EmitDecl(*VD); LocalDeclMap.erase(VDInit); return GetAddrOfLocalVar(VD); }); } assert(IsRegistered && "firstprivate var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; } ++IRef; ++InitsRef; } } return FirstprivateIsLastprivate && !EmittedAsFirstprivate.empty(); } void CodeGenFunction::EmitOMPPrivateClause( const OMPExecutableDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return; llvm::DenseSet EmittedAsPrivate; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); for (auto IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { auto VD = cast(cast(IInit)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. EmitDecl(*VD); return GetAddrOfLocalVar(VD); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; } ++IRef; } } } bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { if (!HaveInsertPoint()) return false; // threadprivate_var1 = master_threadprivate_var1; // operator=(threadprivate_var2, master_threadprivate_var2); // ... // __kmpc_barrier(&loc, global_tid); llvm::DenseSet CopiedVars; llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr; for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto ISrcRef = C->source_exprs().begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *AssignOp : C->assignment_ops()) { auto *VD = cast(cast(*IRef)->getDecl()); QualType Type = VD->getType(); if (CopiedVars.insert(VD->getCanonicalDecl()).second) { // Get the address of the master variable. If we are emitting code with // TLS support, the address is passed from the master as field in the // captured declaration. Address MasterAddr = Address::invalid(); if (getLangOpts().OpenMPUseTLS && getContext().getTargetInfo().isTLSSupported()) { assert(CapturedStmtInfo->lookup(VD) && "Copyin threadprivates should have been captured!"); DeclRefExpr DRE(const_cast(VD), true, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); MasterAddr = EmitLValue(&DRE).getAddress(); LocalDeclMap.erase(VD); } else { MasterAddr = Address(VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) : CGM.GetAddrOfGlobal(VD), getContext().getDeclAlign(VD)); } // Get the address of the threadprivate variable. Address PrivateAddr = EmitLValue(*IRef).getAddress(); if (CopiedVars.size() == 1) { // At first check if current thread is a master thread. If it is, no // need to copy data. CopyBegin = createBasicBlock("copyin.not.master"); CopyEnd = createBasicBlock("copyin.not.master.end"); Builder.CreateCondBr( Builder.CreateICmpNE( Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy), Builder.CreatePtrToInt(PrivateAddr.getPointer(), CGM.IntPtrTy)), CopyBegin, CopyEnd); EmitBlock(CopyBegin); } auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); auto *DestVD = cast(cast(*IDestRef)->getDecl()); EmitOMPCopy(Type, PrivateAddr, MasterAddr, DestVD, SrcVD, AssignOp); } ++IRef; ++ISrcRef; ++IDestRef; } } if (CopyEnd) { // Exit out of copying procedure for non-master thread. EmitBlock(CopyEnd, /*IsFinished=*/true); return true; } return false; } bool CodeGenFunction::EmitOMPLastprivateClauseInit( const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return false; bool HasAtLeastOneLastprivate = false; llvm::DenseSet SIMDLCVs; if (isOpenMPSimdDirective(D.getDirectiveKind())) { auto *LoopDirective = cast(&D); for (auto *C : LoopDirective->counters()) { SIMDLCVs.insert( cast(cast(C)->getDecl())->getCanonicalDecl()); } } llvm::DenseSet AlreadyEmittedVars; for (const auto *C : D.getClausesOfKind()) { HasAtLeastOneLastprivate = true; if (isOpenMPTaskLoopDirective(D.getDirectiveKind())) break; auto IRef = C->varlist_begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *IInit : C->private_copies()) { // Keep the address of the original variable for future update at the end // of the loop. auto *OrigVD = cast(cast(*IRef)->getDecl()); // Taskloops do not require additional initialization, it is done in // runtime support library. if (AlreadyEmittedVars.insert(OrigVD->getCanonicalDecl()).second) { auto *DestVD = cast(cast(*IDestRef)->getDecl()); PrivateScope.addPrivate(DestVD, [this, OrigVD, IRef]() -> Address { DeclRefExpr DRE( const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/CapturedStmtInfo->lookup( OrigVD) != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); return EmitLValue(&DRE).getAddress(); }); // Check if the variable is also a firstprivate: in this case IInit is // not generated. Initialization of this variable will happen in codegen // for 'firstprivate' clause. if (IInit && !SIMDLCVs.count(OrigVD->getCanonicalDecl())) { auto *VD = cast(cast(IInit)->getDecl()); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { // Emit private VarDecl with copy init. EmitDecl(*VD); return GetAddrOfLocalVar(VD); }); assert(IsRegistered && "lastprivate var already registered as private"); (void)IsRegistered; } } ++IRef; ++IDestRef; } } return HasAtLeastOneLastprivate; } void CodeGenFunction::EmitOMPLastprivateClauseFinal( const OMPExecutableDirective &D, bool NoFinals, llvm::Value *IsLastIterCond) { if (!HaveInsertPoint()) return; // Emit following code: // if () { // orig_var1 = private_orig_var1; // ... // orig_varn = private_orig_varn; // } llvm::BasicBlock *ThenBB = nullptr; llvm::BasicBlock *DoneBB = nullptr; if (IsLastIterCond) { ThenBB = createBasicBlock(".omp.lastprivate.then"); DoneBB = createBasicBlock(".omp.lastprivate.done"); Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB); EmitBlock(ThenBB); } llvm::DenseSet AlreadyEmittedVars; llvm::DenseMap LoopCountersAndUpdates; if (auto *LoopDirective = dyn_cast(&D)) { auto IC = LoopDirective->counters().begin(); for (auto F : LoopDirective->finals()) { auto *D = cast(cast(*IC)->getDecl())->getCanonicalDecl(); if (NoFinals) AlreadyEmittedVars.insert(D); else LoopCountersAndUpdates[D] = F; ++IC; } } for (const auto *C : D.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto ISrcRef = C->source_exprs().begin(); auto IDestRef = C->destination_exprs().begin(); for (auto *AssignOp : C->assignment_ops()) { auto *PrivateVD = cast(cast(*IRef)->getDecl()); QualType Type = PrivateVD->getType(); auto *CanonicalVD = PrivateVD->getCanonicalDecl(); if (AlreadyEmittedVars.insert(CanonicalVD).second) { // If lastprivate variable is a loop control variable for loop-based // directive, update its value before copyin back to original // variable. if (auto *FinalExpr = LoopCountersAndUpdates.lookup(CanonicalVD)) EmitIgnoredExpr(FinalExpr); auto *SrcVD = cast(cast(*ISrcRef)->getDecl()); auto *DestVD = cast(cast(*IDestRef)->getDecl()); // Get the address of the original variable. Address OriginalAddr = GetAddrOfLocalVar(DestVD); // Get the address of the private variable. Address PrivateAddr = GetAddrOfLocalVar(PrivateVD); if (auto RefTy = PrivateVD->getType()->getAs()) PrivateAddr = Address(Builder.CreateLoad(PrivateAddr), getNaturalTypeAlignment(RefTy->getPointeeType())); EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp); } ++IRef; ++ISrcRef; ++IDestRef; } if (auto *PostUpdate = C->getPostUpdateExpr()) EmitIgnoredExpr(PostUpdate); } if (IsLastIterCond) EmitBlock(DoneBB, /*IsFinished=*/true); } static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, LValue BaseLV, llvm::Value *Addr) { Address Tmp = Address::invalid(); Address TopTmp = Address::invalid(); Address MostTopTmp = Address::invalid(); BaseTy = BaseTy.getNonReferenceType(); while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) && !CGF.getContext().hasSameType(BaseTy, ElTy)) { Tmp = CGF.CreateMemTemp(BaseTy); if (TopTmp.isValid()) CGF.Builder.CreateStore(Tmp.getPointer(), TopTmp); else MostTopTmp = Tmp; TopTmp = Tmp; BaseTy = BaseTy->getPointeeType(); } llvm::Type *Ty = BaseLV.getPointer()->getType(); if (Tmp.isValid()) Ty = Tmp.getElementType(); Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Addr, Ty); if (Tmp.isValid()) { CGF.Builder.CreateStore(Addr, Tmp); return MostTopTmp; } return Address(Addr, BaseLV.getAlignment()); } static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, LValue BaseLV) { BaseTy = BaseTy.getNonReferenceType(); while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) && !CGF.getContext().hasSameType(BaseTy, ElTy)) { if (auto *PtrTy = BaseTy->getAs()) BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy); else { BaseLV = CGF.EmitLoadOfReferenceLValue(BaseLV.getAddress(), BaseTy->castAs()); } BaseTy = BaseTy->getPointeeType(); } return CGF.MakeAddrLValue( Address( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( BaseLV.getPointer(), CGF.ConvertTypeForMem(ElTy)->getPointerTo()), BaseLV.getAlignment()), BaseLV.getType(), BaseLV.getAlignmentSource()); } void CodeGenFunction::EmitOMPReductionClauseInit( const OMPExecutableDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return; for (const auto *C : D.getClausesOfKind()) { auto ILHS = C->lhs_exprs().begin(); auto IRHS = C->rhs_exprs().begin(); auto IPriv = C->privates().begin(); auto IRed = C->reduction_ops().begin(); for (auto IRef : C->varlists()) { auto *LHSVD = cast(cast(*ILHS)->getDecl()); auto *RHSVD = cast(cast(*IRHS)->getDecl()); auto *PrivateVD = cast(cast(*IPriv)->getDecl()); auto *DRD = getReductionInit(*IRed); if (auto *OASE = dyn_cast(IRef)) { auto *Base = OASE->getBase()->IgnoreParenImpCasts(); while (auto *TempOASE = dyn_cast(Base)) Base = TempOASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); auto *DE = cast(Base); auto *OrigVD = cast(DE->getDecl()); auto OASELValueLB = EmitOMPArraySectionExpr(OASE); auto OASELValueUB = EmitOMPArraySectionExpr(OASE, /*IsLowerBound=*/false); auto OriginalBaseLValue = EmitLValue(DE); LValue BaseLValue = loadToBegin(*this, OrigVD->getType(), OASELValueLB.getType(), OriginalBaseLValue); // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [this, OASELValueLB]() -> Address { return OASELValueLB.getAddress(); }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate( OrigVD, [this, OrigVD, PrivateVD, BaseLValue, OASELValueLB, OASELValueUB, OriginalBaseLValue, DRD, IRed]() -> Address { // Emit VarDecl with copy init for arrays. // Get the address of the original variable captured in current // captured region. auto *Size = Builder.CreatePtrDiff(OASELValueUB.getPointer(), OASELValueLB.getPointer()); Size = Builder.CreateNUWAdd( Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1)); CodeGenFunction::OpaqueValueMapping OpaqueMap( *this, cast( getContext() .getAsVariableArrayType(PrivateVD->getType()) ->getSizeExpr()), RValue::get(Size)); EmitVariablyModifiedType(PrivateVD->getType()); auto Emission = EmitAutoVarAlloca(*PrivateVD); auto Addr = Emission.getAllocatedAddress(); auto *Init = PrivateVD->getInit(); EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), DRD ? *IRed : Init, OASELValueLB.getAddress()); EmitAutoVarCleanups(Emission); // Emit private VarDecl with reduction init. auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(), OASELValueLB.getPointer()); auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset); return castToBase(*this, OrigVD->getType(), OASELValueLB.getType(), OriginalBaseLValue, Ptr); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); } else if (auto *ASE = dyn_cast(IRef)) { auto *Base = ASE->getBase()->IgnoreParenImpCasts(); while (auto *TempASE = dyn_cast(Base)) Base = TempASE->getBase()->IgnoreParenImpCasts(); auto *DE = cast(Base); auto *OrigVD = cast(DE->getDecl()); auto ASELValue = EmitLValue(ASE); auto OriginalBaseLValue = EmitLValue(DE); LValue BaseLValue = loadToBegin( *this, OrigVD->getType(), ASELValue.getType(), OriginalBaseLValue); // Store the address of the original variable associated with the LHS // implicit variable. PrivateScope.addPrivate(LHSVD, [this, ASELValue]() -> Address { return ASELValue.getAddress(); }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate( OrigVD, [this, OrigVD, PrivateVD, BaseLValue, ASELValue, OriginalBaseLValue, DRD, IRed]() -> Address { // Emit private VarDecl with reduction init. AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD); auto Addr = Emission.getAllocatedAddress(); if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(*this, DRD, *IRed, Addr, ASELValue.getAddress(), ASELValue.getType()); } else EmitAutoVarInit(Emission); EmitAutoVarCleanups(Emission); auto *Offset = Builder.CreatePtrDiff(BaseLValue.getPointer(), ASELValue.getPointer()); auto *Ptr = Builder.CreateGEP(Addr.getPointer(), Offset); return castToBase(*this, OrigVD->getType(), ASELValue.getType(), OriginalBaseLValue, Ptr); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address { return Builder.CreateElementBitCast( GetAddrOfLocalVar(PrivateVD), ConvertTypeForMem(RHSVD->getType()), "rhs.begin"); }); } else { auto *OrigVD = cast(cast(IRef)->getDecl()); QualType Type = PrivateVD->getType(); if (getContext().getAsArrayType(Type)) { // Store the address of the original variable associated with the LHS // implicit variable. DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, IRef->getType(), VK_LValue, IRef->getExprLoc()); Address OriginalAddr = EmitLValue(&DRE).getAddress(); PrivateScope.addPrivate(LHSVD, [this, &OriginalAddr, LHSVD]() -> Address { OriginalAddr = Builder.CreateElementBitCast( OriginalAddr, ConvertTypeForMem(LHSVD->getType()), "lhs.begin"); return OriginalAddr; }); bool IsRegistered = PrivateScope.addPrivate(OrigVD, [&]() -> Address { if (Type->isVariablyModifiedType()) { CodeGenFunction::OpaqueValueMapping OpaqueMap( *this, cast( getContext() .getAsVariableArrayType(PrivateVD->getType()) ->getSizeExpr()), RValue::get( getTypeSize(OrigVD->getType().getNonReferenceType()))); EmitVariablyModifiedType(Type); } auto Emission = EmitAutoVarAlloca(*PrivateVD); auto Addr = Emission.getAllocatedAddress(); auto *Init = PrivateVD->getInit(); EmitOMPAggregateInit(*this, Addr, PrivateVD->getType(), DRD ? *IRed : Init, OriginalAddr); EmitAutoVarCleanups(Emission); return Emission.getAllocatedAddress(); }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() -> Address { return Builder.CreateElementBitCast( GetAddrOfLocalVar(PrivateVD), ConvertTypeForMem(RHSVD->getType()), "rhs.begin"); }); } else { // Store the address of the original variable associated with the LHS // implicit variable. Address OriginalAddr = Address::invalid(); PrivateScope.addPrivate(LHSVD, [this, OrigVD, IRef, &OriginalAddr]() -> Address { DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, IRef->getType(), VK_LValue, IRef->getExprLoc()); OriginalAddr = EmitLValue(&DRE).getAddress(); return OriginalAddr; }); // Emit reduction copy. bool IsRegistered = PrivateScope.addPrivate( OrigVD, [this, PrivateVD, OriginalAddr, DRD, IRed]() -> Address { // Emit private VarDecl with reduction init. AutoVarEmission Emission = EmitAutoVarAlloca(*PrivateVD); auto Addr = Emission.getAllocatedAddress(); if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(*this, DRD, *IRed, Addr, OriginalAddr, PrivateVD->getType()); } else EmitAutoVarInit(Emission); EmitAutoVarCleanups(Emission); return Addr; }); assert(IsRegistered && "private var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; PrivateScope.addPrivate(RHSVD, [this, PrivateVD]() -> Address { return GetAddrOfLocalVar(PrivateVD); }); } } ++ILHS; ++IRHS; ++IPriv; ++IRed; } } } void CodeGenFunction::EmitOMPReductionClauseFinal( const OMPExecutableDirective &D) { if (!HaveInsertPoint()) return; llvm::SmallVector Privates; llvm::SmallVector LHSExprs; llvm::SmallVector RHSExprs; llvm::SmallVector ReductionOps; bool HasAtLeastOneReduction = false; for (const auto *C : D.getClausesOfKind()) { HasAtLeastOneReduction = true; Privates.append(C->privates().begin(), C->privates().end()); LHSExprs.append(C->lhs_exprs().begin(), C->lhs_exprs().end()); RHSExprs.append(C->rhs_exprs().begin(), C->rhs_exprs().end()); ReductionOps.append(C->reduction_ops().begin(), C->reduction_ops().end()); } if (HasAtLeastOneReduction) { // Emit nowait reduction if nowait clause is present or directive is a // parallel directive (it always has implicit barrier). CGM.getOpenMPRuntime().emitReduction( *this, D.getLocEnd(), Privates, LHSExprs, RHSExprs, ReductionOps, D.getSingleClause() || isOpenMPParallelDirective(D.getDirectiveKind()) || D.getDirectiveKind() == OMPD_simd, D.getDirectiveKind() == OMPD_simd); } } static void emitPostUpdateForReductionClause( CodeGenFunction &CGF, const OMPExecutableDirective &D, const llvm::function_ref &CondGen) { if (!CGF.HaveInsertPoint()) return; llvm::BasicBlock *DoneBB = nullptr; for (const auto *C : D.getClausesOfKind()) { if (auto *PostUpdate = C->getPostUpdateExpr()) { if (!DoneBB) { if (auto *Cond = CondGen(CGF)) { // If the first post-update expression is found, emit conditional // block if it was requested. auto *ThenBB = CGF.createBasicBlock(".omp.reduction.pu"); DoneBB = CGF.createBasicBlock(".omp.reduction.pu.done"); CGF.Builder.CreateCondBr(Cond, ThenBB, DoneBB); CGF.EmitBlock(ThenBB); } } CGF.EmitIgnoredExpr(PostUpdate); } } if (DoneBB) CGF.EmitBlock(DoneBB, /*IsFinished=*/true); } static void emitCommonOMPParallelDirective(CodeGenFunction &CGF, const OMPExecutableDirective &S, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { auto CS = cast(S.getAssociatedStmt()); auto OutlinedFn = CGF.CGM.getOpenMPRuntime(). emitParallelOrTeamsOutlinedFunction(S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen); if (const auto *NumThreadsClause = S.getSingleClause()) { CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF); auto NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(), /*IgnoreResultAssign*/ true); CGF.CGM.getOpenMPRuntime().emitNumThreadsClause( CGF, NumThreads, NumThreadsClause->getLocStart()); } if (const auto *ProcBindClause = S.getSingleClause()) { CodeGenFunction::RunCleanupsScope ProcBindScope(CGF); CGF.CGM.getOpenMPRuntime().emitProcBindClause( CGF, ProcBindClause->getProcBindKind(), ProcBindClause->getLocStart()); } const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_parallel) { IfCond = C->getCondition(); break; } } OMPLexicalScope Scope(CGF, S); llvm::SmallVector CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn, CapturedVars, IfCond); } void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { // Emit parallel region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPPrivateScope PrivateScope(CGF); bool Copyins = CGF.EmitOMPCopyinClause(S); (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); if (Copyins) { // Emit implicit barrier to synchronize threads and avoid data races on // propagation master's thread values of threadprivate variables to local // instances of that variables of all other implicit threads. CGF.CGM.getOpenMPRuntime().emitBarrierCall( CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } CGF.EmitOMPPrivateClause(S, PrivateScope); CGF.EmitOMPReductionClauseInit(S, PrivateScope); (void)PrivateScope.Privatize(); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); CGF.EmitOMPReductionClauseFinal(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_parallel, CodeGen); emitPostUpdateForReductionClause( *this, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit) { RunCleanupsScope BodyScope(*this); // Update counters values on current iteration. for (auto I : D.updates()) { EmitIgnoredExpr(I); } // Update the linear variables. for (const auto *C : D.getClausesOfKind()) { for (auto *U : C->updates()) EmitIgnoredExpr(U); } // On a continue in the body, jump to the end. auto Continue = getJumpDestInCurrentScope("omp.body.continue"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); // Emit loop body. EmitStmt(D.getBody()); // The end (updates/cleanups). EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); } void CodeGenFunction::EmitOMPInnerLoop( const Stmt &S, bool RequiresCleanup, const Expr *LoopCond, const Expr *IncExpr, const llvm::function_ref &BodyGen, const llvm::function_ref &PostIncGen) { auto LoopExit = getJumpDestInCurrentScope("omp.inner.for.end"); // Start the loop with a block that tests the condition. auto CondBlock = createBasicBlock("omp.inner.for.cond"); EmitBlock(CondBlock); LoopStack.push(CondBlock, Builder.getCurrentDebugLocation()); // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. auto ExitBlock = LoopExit.getBlock(); if (RequiresCleanup) ExitBlock = createBasicBlock("omp.inner.for.cond.cleanup"); auto LoopBody = createBasicBlock("omp.inner.for.body"); // Emit condition. EmitBranchOnBoolExpr(LoopCond, LoopBody, ExitBlock, getProfileCount(&S)); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } EmitBlock(LoopBody); incrementProfileCounter(&S); // Create a block for the increment. auto Continue = getJumpDestInCurrentScope("omp.inner.for.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); BodyGen(*this); // Emit "IV = IV + 1" and a back-edge to the condition block. EmitBlock(Continue.getBlock()); EmitIgnoredExpr(IncExpr); PostIncGen(*this); BreakContinueStack.pop_back(); EmitBranch(CondBlock); LoopStack.pop(); // Emit the fall-through block. EmitBlock(LoopExit.getBlock()); } void CodeGenFunction::EmitOMPLinearClauseInit(const OMPLoopDirective &D) { if (!HaveInsertPoint()) return; // Emit inits for the linear variables. for (const auto *C : D.getClausesOfKind()) { for (auto *Init : C->inits()) { auto *VD = cast(cast(Init)->getDecl()); if (auto *Ref = dyn_cast(VD->getInit()->IgnoreImpCasts())) { AutoVarEmission Emission = EmitAutoVarAlloca(*VD); auto *OrigVD = cast(Ref->getDecl()); DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, VD->getInit()->getType(), VK_LValue, VD->getInit()->getExprLoc()); EmitExprAsInit(&DRE, VD, MakeAddrLValue(Emission.getAllocatedAddress(), VD->getType()), /*capturedByInit=*/false); EmitAutoVarCleanups(Emission); } else EmitVarDecl(*VD); } // Emit the linear steps for the linear clauses. // If a step is not constant, it is pre-calculated before the loop. if (auto CS = cast_or_null(C->getCalcStep())) if (auto SaveRef = cast(CS->getLHS())) { EmitVarDecl(*cast(SaveRef->getDecl())); // Emit calculation of the linear step. EmitIgnoredExpr(CS); } } } void CodeGenFunction::EmitOMPLinearClauseFinal( const OMPLoopDirective &D, const llvm::function_ref &CondGen) { if (!HaveInsertPoint()) return; llvm::BasicBlock *DoneBB = nullptr; // Emit the final values of the linear variables. for (const auto *C : D.getClausesOfKind()) { auto IC = C->varlist_begin(); for (auto *F : C->finals()) { if (!DoneBB) { if (auto *Cond = CondGen(*this)) { // If the first post-update expression is found, emit conditional // block if it was requested. auto *ThenBB = createBasicBlock(".omp.linear.pu"); DoneBB = createBasicBlock(".omp.linear.pu.done"); Builder.CreateCondBr(Cond, ThenBB, DoneBB); EmitBlock(ThenBB); } } auto *OrigVD = cast(cast(*IC)->getDecl()); DeclRefExpr DRE(const_cast(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); Address OrigAddr = EmitLValue(&DRE).getAddress(); CodeGenFunction::OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); (void)VarScope.Privatize(); EmitIgnoredExpr(F); ++IC; } if (auto *PostUpdate = C->getPostUpdateExpr()) EmitIgnoredExpr(PostUpdate); } if (DoneBB) EmitBlock(DoneBB, /*IsFinished=*/true); } static void emitAlignedClause(CodeGenFunction &CGF, const OMPExecutableDirective &D) { if (!CGF.HaveInsertPoint()) return; for (const auto *Clause : D.getClausesOfKind()) { unsigned ClauseAlignment = 0; if (auto AlignmentExpr = Clause->getAlignment()) { auto AlignmentCI = cast(CGF.EmitScalarExpr(AlignmentExpr)); ClauseAlignment = static_cast(AlignmentCI->getZExtValue()); } for (auto E : Clause->varlists()) { unsigned Alignment = ClauseAlignment; if (Alignment == 0) { // OpenMP [2.8.1, Description] // If no optional parameter is specified, implementation-defined default // alignments for SIMD instructions on the target platforms are assumed. Alignment = CGF.getContext() .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign( E->getType()->getPointeeType())) .getQuantity(); } assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) && "alignment is not power of 2"); if (Alignment != 0) { llvm::Value *PtrValue = CGF.EmitScalarExpr(E); CGF.EmitAlignmentAssumption(PtrValue, Alignment); } } } } void CodeGenFunction::EmitOMPPrivateLoopCounters( const OMPLoopDirective &S, CodeGenFunction::OMPPrivateScope &LoopScope) { if (!HaveInsertPoint()) return; auto I = S.private_counters().begin(); for (auto *E : S.counters()) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*I)->getDecl()); (void)LoopScope.addPrivate(VD, [&]() -> Address { // Emit var without initialization. if (!LocalDeclMap.count(PrivateVD)) { auto VarEmission = EmitAutoVarAlloca(*PrivateVD); EmitAutoVarCleanups(VarEmission); } DeclRefExpr DRE(const_cast(PrivateVD), /*RefersToEnclosingVariableOrCapture=*/false, (*I)->getType(), VK_LValue, (*I)->getExprLoc()); return EmitLValue(&DRE).getAddress(); }); if (LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD) || VD->hasGlobalStorage()) { (void)LoopScope.addPrivate(PrivateVD, [&]() -> Address { DeclRefExpr DRE(const_cast(VD), LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD), E->getType(), VK_LValue, E->getExprLoc()); return EmitLValue(&DRE).getAddress(); }); } ++I; } } static void emitPreCond(CodeGenFunction &CGF, const OMPLoopDirective &S, const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock, uint64_t TrueCount) { if (!CGF.HaveInsertPoint()) return; { CodeGenFunction::OMPPrivateScope PreCondScope(CGF); CGF.EmitOMPPrivateLoopCounters(S, PreCondScope); (void)PreCondScope.Privatize(); // Get initial values of real counters. for (auto I : S.inits()) { CGF.EmitIgnoredExpr(I); } } // Check that loop is executed at least one time. CGF.EmitBranchOnBoolExpr(Cond, TrueBlock, FalseBlock, TrueCount); } void CodeGenFunction::EmitOMPLinearClause( const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope) { if (!HaveInsertPoint()) return; llvm::DenseSet SIMDLCVs; if (isOpenMPSimdDirective(D.getDirectiveKind())) { auto *LoopDirective = cast(&D); for (auto *C : LoopDirective->counters()) { SIMDLCVs.insert( cast(cast(C)->getDecl())->getCanonicalDecl()); } } for (const auto *C : D.getClausesOfKind()) { auto CurPrivate = C->privates().begin(); for (auto *E : C->varlists()) { auto *VD = cast(cast(E)->getDecl()); auto *PrivateVD = cast(cast(*CurPrivate)->getDecl()); if (!SIMDLCVs.count(VD->getCanonicalDecl())) { bool IsRegistered = PrivateScope.addPrivate(VD, [&]() -> Address { // Emit private VarDecl with copy init. EmitVarDecl(*PrivateVD); return GetAddrOfLocalVar(PrivateVD); }); assert(IsRegistered && "linear var already registered as private"); // Silence the warning about unused variable. (void)IsRegistered; } else EmitVarDecl(*PrivateVD); ++CurPrivate; } } } static void emitSimdlenSafelenClause(CodeGenFunction &CGF, const OMPExecutableDirective &D, bool IsMonotonic) { if (!CGF.HaveInsertPoint()) return; if (const auto *C = D.getSingleClause()) { RValue Len = CGF.EmitAnyExpr(C->getSimdlen(), AggValueSlot::ignored(), /*ignoreResult=*/true); llvm::ConstantInt *Val = cast(Len.getScalarVal()); CGF.LoopStack.setVectorizeWidth(Val->getZExtValue()); // In presence of finite 'safelen', it may be unsafe to mark all // the memory instructions parallel, because loop-carried // dependences of 'safelen' iterations are possible. if (!IsMonotonic) CGF.LoopStack.setParallel(!D.getSingleClause()); } else if (const auto *C = D.getSingleClause()) { RValue Len = CGF.EmitAnyExpr(C->getSafelen(), AggValueSlot::ignored(), /*ignoreResult=*/true); llvm::ConstantInt *Val = cast(Len.getScalarVal()); CGF.LoopStack.setVectorizeWidth(Val->getZExtValue()); // In presence of finite 'safelen', it may be unsafe to mark all // the memory instructions parallel, because loop-carried // dependences of 'safelen' iterations are possible. CGF.LoopStack.setParallel(false); } } void CodeGenFunction::EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic) { // Walk clauses and process safelen/lastprivate. LoopStack.setParallel(!IsMonotonic); LoopStack.setVectorizeEnable(true); emitSimdlenSafelenClause(*this, D, IsMonotonic); } void CodeGenFunction::EmitOMPSimdFinal( const OMPLoopDirective &D, const llvm::function_ref &CondGen) { if (!HaveInsertPoint()) return; llvm::BasicBlock *DoneBB = nullptr; auto IC = D.counters().begin(); auto IPC = D.private_counters().begin(); for (auto F : D.finals()) { auto *OrigVD = cast(cast((*IC))->getDecl()); auto *PrivateVD = cast(cast((*IPC))->getDecl()); auto *CED = dyn_cast(OrigVD); if (LocalDeclMap.count(OrigVD) || CapturedStmtInfo->lookup(OrigVD) || OrigVD->hasGlobalStorage() || CED) { if (!DoneBB) { if (auto *Cond = CondGen(*this)) { // If the first post-update expression is found, emit conditional // block if it was requested. auto *ThenBB = createBasicBlock(".omp.final.then"); DoneBB = createBasicBlock(".omp.final.done"); Builder.CreateCondBr(Cond, ThenBB, DoneBB); EmitBlock(ThenBB); } } Address OrigAddr = Address::invalid(); if (CED) OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(); else { DeclRefExpr DRE(const_cast(PrivateVD), /*RefersToEnclosingVariableOrCapture=*/false, (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc()); OrigAddr = EmitLValue(&DRE).getAddress(); } OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() -> Address { return OrigAddr; }); (void)VarScope.Privatize(); EmitIgnoredExpr(F); } ++IC; ++IPC; } if (DoneBB) EmitBlock(DoneBB, /*IsFinished=*/true); } void CodeGenFunction::EmitOMPSimdDirective(const OMPSimdDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); // if (PreCond) { // for (IV in 0..LastIteration) BODY; // ; // } // // Emit: if (PreCond) - begin. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return; } else { auto *ThenBlock = CGF.createBasicBlock("simd.if.then"); ContBlock = CGF.createBasicBlock("simd.if.end"); emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock, CGF.getProfileCount(&S)); CGF.EmitBlock(ThenBlock); CGF.incrementProfileCounter(&S); } // Emit the loop iteration variable. const Expr *IVExpr = S.getIterationVariable(); const VarDecl *IVDecl = cast(cast(IVExpr)->getDecl()); CGF.EmitVarDecl(*IVDecl); CGF.EmitIgnoredExpr(S.getInit()); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on // each iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { CGF.EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. CGF.EmitIgnoredExpr(S.getCalcLastIteration()); } CGF.EmitOMPSimdInit(S); emitAlignedClause(CGF, S); CGF.EmitOMPLinearClauseInit(S); { OMPPrivateScope LoopScope(CGF); CGF.EmitOMPPrivateLoopCounters(S, LoopScope); CGF.EmitOMPLinearClause(S, LoopScope); CGF.EmitOMPPrivateClause(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, JumpDest()); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); CGF.EmitOMPSimdFinal( S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); // Emit final copy of the lastprivate variables at the end of loops. if (HasLastprivateClause) CGF.EmitOMPLastprivateClauseFinal(S, /*NoFinals=*/true); CGF.EmitOMPReductionClauseFinal(S); emitPostUpdateForReductionClause( CGF, S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); } CGF.EmitOMPLinearClauseFinal( S, [](CodeGenFunction &) -> llvm::Value * { return nullptr; }); // Emit: if (PreCond) - end. if (ContBlock) { CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock, true); } }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); } void CodeGenFunction::EmitOMPOuterLoop(bool DynamicOrOrdered, bool IsMonotonic, const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) { auto &RT = CGM.getOpenMPRuntime(); const Expr *IVExpr = S.getIterationVariable(); const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); auto LoopExit = getJumpDestInCurrentScope("omp.dispatch.end"); // Start the loop with a block that tests the condition. auto CondBlock = createBasicBlock("omp.dispatch.cond"); EmitBlock(CondBlock); LoopStack.push(CondBlock, Builder.getCurrentDebugLocation()); llvm::Value *BoolCondVal = nullptr; if (!DynamicOrOrdered) { // UB = min(UB, GlobalUB) EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB EmitIgnoredExpr(S.getInit()); // IV < UB BoolCondVal = EvaluateExprAsBool(S.getCond()); } else { BoolCondVal = RT.emitForNext(*this, S.getLocStart(), IVSize, IVSigned, IL, LB, UB, ST); } // If there are any cleanups between here and the loop-exit scope, // create a block to stage a loop exit along. auto ExitBlock = LoopExit.getBlock(); if (LoopScope.requiresCleanups()) ExitBlock = createBasicBlock("omp.dispatch.cleanup"); auto LoopBody = createBasicBlock("omp.dispatch.body"); Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock); if (ExitBlock != LoopExit.getBlock()) { EmitBlock(ExitBlock); EmitBranchThroughCleanup(LoopExit); } EmitBlock(LoopBody); // Emit "IV = LB" (in case of static schedule, we have already calculated new // LB for loop condition and emitted it above). if (DynamicOrOrdered) EmitIgnoredExpr(S.getInit()); // Create a block for the increment. auto Continue = getJumpDestInCurrentScope("omp.dispatch.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); // Generate !llvm.loop.parallel metadata for loads and stores for loops // with dynamic/guided scheduling and without ordered clause. if (!isOpenMPSimdDirective(S.getDirectiveKind())) LoopStack.setParallel(!IsMonotonic); else EmitOMPSimdInit(S, IsMonotonic); SourceLocation Loc = S.getLocStart(); EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [Ordered, IVSize, IVSigned, Loc](CodeGenFunction &CGF) { if (Ordered) { CGF.CGM.getOpenMPRuntime().emitForOrderedIterationEnd( CGF, Loc, IVSize, IVSigned); } }); EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); if (!DynamicOrOrdered) { // Emit "LB = LB + Stride", "UB = UB + Stride". EmitIgnoredExpr(S.getNextLowerBound()); EmitIgnoredExpr(S.getNextUpperBound()); } EmitBranch(CondBlock); LoopStack.pop(); // Emit the fall-through block. EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&CodeGen = [DynamicOrOrdered, ELoc](CodeGenFunction &CGF) { + auto &&CodeGen = [DynamicOrOrdered, &S](CodeGenFunction &CGF) { if (!DynamicOrOrdered) - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - CodeGen(*this); - - OpenMPDirectiveKind DKind = S.getDirectiveKind(); - if (DKind == OMPD_for || DKind == OMPD_parallel_for || - DKind == OMPD_distribute_parallel_for) - OMPCancelStack.back().CodeGen = CodeGen; + OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } void CodeGenFunction::EmitOMPForOuterLoop( const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic, const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) { auto &RT = CGM.getOpenMPRuntime(); // Dynamic scheduling of the outer loop (dynamic, guided, auto, runtime). const bool DynamicOrOrdered = Ordered || RT.isDynamic(ScheduleKind.Schedule); assert((Ordered || !RT.isStaticNonchunked(ScheduleKind.Schedule, /*Chunked=*/Chunk != nullptr)) && "static non-chunked schedule does not need outer loop"); // Emit outer loop. // // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When schedule(dynamic,chunk_size) is specified, the iterations are // distributed to threads in the team in chunks as the threads request them. // Each thread executes a chunk of iterations, then requests another chunk, // until no chunks remain to be distributed. Each chunk contains chunk_size // iterations, except for the last chunk to be distributed, which may have // fewer iterations. When no chunk_size is specified, it defaults to 1. // // When schedule(guided,chunk_size) is specified, the iterations are assigned // to threads in the team in chunks as the executing threads request them. // Each thread executes a chunk of iterations, then requests another chunk, // until no chunks remain to be assigned. For a chunk_size of 1, the size of // each chunk is proportional to the number of unassigned iterations divided // by the number of threads in the team, decreasing to 1. For a chunk_size // with value k (greater than 1), the size of each chunk is determined in the // same way, with the restriction that the chunks do not contain fewer than k // iterations (except for the last chunk to be assigned, which may have fewer // than k iterations). // // When schedule(auto) is specified, the decision regarding scheduling is // delegated to the compiler and/or runtime system. The programmer gives the // implementation the freedom to choose any possible mapping of iterations to // threads in the team. // // When schedule(runtime) is specified, the decision regarding scheduling is // deferred until run time, and the schedule and chunk size are taken from the // run-sched-var ICV. If the ICV is set to auto, the schedule is // implementation defined // // while(__kmpc_dispatch_next(&LB, &UB)) { // idx = LB; // while (idx <= UB) { BODY; ++idx; // __kmpc_dispatch_fini_(4|8)[u](); // For ordered loops only. // } // inner loop // } // // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When schedule(static, chunk_size) is specified, iterations are divided into // chunks of size chunk_size, and the chunks are assigned to the threads in // the team in a round-robin fashion in the order of the thread number. // // while(UB = min(UB, GlobalUB), idx = LB, idx < UB) { // while (idx <= UB) { BODY; ++idx; } // inner loop // LB = LB + ST; // UB = UB + ST; // } // const Expr *IVExpr = S.getIterationVariable(); const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); if (DynamicOrOrdered) { llvm::Value *UBVal = EmitScalarExpr(S.getLastIteration()); RT.emitForDispatchInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, UBVal, Chunk); } else { RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, IL, LB, UB, ST, Chunk); } EmitOMPOuterLoop(DynamicOrOrdered, IsMonotonic, S, LoopScope, Ordered, LB, UB, ST, IL, Chunk); } void CodeGenFunction::EmitOMPDistributeOuterLoop( OpenMPDistScheduleClauseKind ScheduleKind, const OMPDistributeDirective &S, OMPPrivateScope &LoopScope, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk) { auto &RT = CGM.getOpenMPRuntime(); // Emit outer loop. // Same behavior as a OMPForOuterLoop, except that schedule cannot be // dynamic // const Expr *IVExpr = S.getIterationVariable(); const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, /* Ordered = */ false, IL, LB, UB, ST, Chunk); EmitOMPOuterLoop(/* DynamicOrOrdered = */ false, /* IsMonotonic = */ false, S, LoopScope, /* Ordered = */ false, LB, UB, ST, IL, Chunk); } void CodeGenFunction::EmitOMPDistributeParallelForDirective( const OMPDistributeParallelForDirective &S) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - OMPCancelStackRAII CancelRegion(*this); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_distribute_parallel_for, [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); + OMPCancelStackRAII CancelRegion(CGF, OMPD_distribute_parallel_for, + /*HasCancel=*/false); CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); }); } void CodeGenFunction::EmitOMPDistributeParallelForSimdDirective( const OMPDistributeParallelForSimdDirective &S) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_distribute_parallel_for_simd, [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); }); } void CodeGenFunction::EmitOMPDistributeSimdDirective( const OMPDistributeSimdDirective &S) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_distribute_simd, [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); }); } void CodeGenFunction::EmitOMPTargetParallelForSimdDirective( const OMPTargetParallelForSimdDirective &S) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective( *this, OMPD_target_parallel_for_simd, [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); }); } /// \brief Emit a helper variable and return corresponding lvalue. static LValue EmitOMPHelperVar(CodeGenFunction &CGF, const DeclRefExpr *Helper) { auto VDecl = cast(Helper->getDecl()); CGF.EmitVarDecl(*VDecl); return CGF.EmitLValue(Helper); } namespace { struct ScheduleKindModifiersTy { OpenMPScheduleClauseKind Kind; OpenMPScheduleClauseModifier M1; OpenMPScheduleClauseModifier M2; ScheduleKindModifiersTy(OpenMPScheduleClauseKind Kind, OpenMPScheduleClauseModifier M1, OpenMPScheduleClauseModifier M2) : Kind(Kind), M1(M1), M2(M2) {} }; } // namespace bool CodeGenFunction::EmitOMPWorksharingLoop(const OMPLoopDirective &S) { // Emit the loop iteration variable. auto IVExpr = cast(S.getIterationVariable()); auto IVDecl = cast(IVExpr->getDecl()); EmitVarDecl(*IVDecl); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on each // iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. EmitIgnoredExpr(S.getCalcLastIteration()); } auto &RT = CGM.getOpenMPRuntime(); bool HasLastprivateClause; // Check pre-condition. { OMPLoopScope PreInitScope(*this, S); // Skip the entire loop if we don't meet the precondition. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return false; } else { auto *ThenBlock = createBasicBlock("omp.precond.then"); ContBlock = createBasicBlock("omp.precond.end"); emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock, getProfileCount(&S)); EmitBlock(ThenBlock); incrementProfileCounter(&S); } bool Ordered = false; if (auto *OrderedClause = S.getSingleClause()) { if (OrderedClause->getNumForLoops()) RT.emitDoacrossInit(*this, S); else Ordered = true; } llvm::DenseSet EmittedFinals; emitAlignedClause(*this, S); EmitOMPLinearClauseInit(S); // Emit helper vars inits. LValue LB = EmitOMPHelperVar(*this, cast(S.getLowerBoundVariable())); LValue UB = EmitOMPHelperVar(*this, cast(S.getUpperBoundVariable())); LValue ST = EmitOMPHelperVar(*this, cast(S.getStrideVariable())); LValue IL = EmitOMPHelperVar(*this, cast(S.getIsLastIterVariable())); // Emit 'then' code. { OMPPrivateScope LoopScope(*this); if (EmitOMPFirstprivateClause(S, LoopScope)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables and post-update of // lastprivate variables. CGM.getOpenMPRuntime().emitBarrierCall( *this, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } EmitOMPPrivateClause(S, LoopScope); HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope); EmitOMPReductionClauseInit(S, LoopScope); EmitOMPPrivateLoopCounters(S, LoopScope); EmitOMPLinearClause(S, LoopScope); (void)LoopScope.Privatize(); // Detect the loop schedule kind and chunk. llvm::Value *Chunk = nullptr; OpenMPScheduleTy ScheduleKind; if (auto *C = S.getSingleClause()) { ScheduleKind.Schedule = C->getScheduleKind(); ScheduleKind.M1 = C->getFirstScheduleModifier(); ScheduleKind.M2 = C->getSecondScheduleModifier(); if (const auto *Ch = C->getChunkSize()) { Chunk = EmitScalarExpr(Ch); Chunk = EmitScalarConversion(Chunk, Ch->getType(), S.getIterationVariable()->getType(), S.getLocStart()); } } const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); // OpenMP 4.5, 2.7.1 Loop Construct, Description. // If the static schedule kind is specified or if the ordered clause is // specified, and if no monotonic modifier is specified, the effect will // be as if the monotonic modifier was specified. if (RT.isStaticNonchunked(ScheduleKind.Schedule, /* Chunked */ Chunk != nullptr) && !Ordered) { if (isOpenMPSimdDirective(S.getDirectiveKind())) EmitOMPSimdInit(S, /*IsMonotonic=*/true); // OpenMP [2.7.1, Loop Construct, Description, table 2-1] // When no chunk_size is specified, the iteration space is divided into // chunks that are approximately equal in size, and at most one chunk is // distributed to each thread. Note that the size of the chunks is // unspecified in this case. RT.emitForStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB; EmitIgnoredExpr(S.getInit()); // while (idx <= UB) { BODY; ++idx; } EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&CodeGen = [ELoc](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + auto &&CodeGen = [&S](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - CodeGen(*this); - OpenMPDirectiveKind DKind = S.getDirectiveKind(); - if (DKind == OMPD_for || DKind == OMPD_parallel_for || - DKind == OMPD_distribute_parallel_for) - OMPCancelStack.back().CodeGen = CodeGen; + OMPCancelStack.emitExit(*this, S.getDirectiveKind(), CodeGen); } else { const bool IsMonotonic = Ordered || ScheduleKind.Schedule == OMPC_SCHEDULE_static || ScheduleKind.Schedule == OMPC_SCHEDULE_unknown || ScheduleKind.M1 == OMPC_SCHEDULE_MODIFIER_monotonic || ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic; // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered, LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(), Chunk); } if (isOpenMPSimdDirective(S.getDirectiveKind())) { EmitOMPSimdFinal(S, [&](CodeGenFunction &CGF) -> llvm::Value * { return CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart())); }); } EmitOMPReductionClauseFinal(S); // Emit post-update of the reduction variables if IsLastIter != 0. emitPostUpdateForReductionClause( *this, S, [&](CodeGenFunction &CGF) -> llvm::Value * { return CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart())); }); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivateClause) EmitOMPLastprivateClauseFinal( S, isOpenMPSimdDirective(S.getDirectiveKind()), Builder.CreateIsNotNull(EmitLoadOfScalar(IL, S.getLocStart()))); } EmitOMPLinearClauseFinal(S, [&](CodeGenFunction &CGF) -> llvm::Value * { return CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart())); }); // We're now done with the loop, so jump to the continuation block. if (ContBlock) { EmitBranch(ContBlock); EmitBlock(ContBlock, true); } } return HasLastprivateClause; } void CodeGenFunction::EmitOMPForDirective(const OMPForDirective &S) { bool HasLastprivates = false; auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { + OMPCancelStackRAII CancelRegion(CGF, OMPD_for, S.hasCancel()); HasLastprivates = CGF.EmitOMPWorksharingLoop(S); }; { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); - OMPCancelStackRAII CancelRegion(*this); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_for, CodeGen, S.hasCancel()); } // Emit an implicit barrier at the end. if (!S.getSingleClause() || HasLastprivates) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_for); } } void CodeGenFunction::EmitOMPForSimdDirective(const OMPForSimdDirective &S) { bool HasLastprivates = false; auto &&CodeGen = [&S, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { HasLastprivates = CGF.EmitOMPWorksharingLoop(S); }; { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_simd, CodeGen); } // Emit an implicit barrier at the end. if (!S.getSingleClause() || HasLastprivates) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_for); } } static LValue createSectionLVal(CodeGenFunction &CGF, QualType Ty, const Twine &Name, llvm::Value *Init = nullptr) { auto LVal = CGF.MakeAddrLValue(CGF.CreateMemTemp(Ty, Name), Ty); if (Init) CGF.EmitScalarInit(Init, LVal); return LVal; } void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { auto *Stmt = cast(S.getAssociatedStmt())->getCapturedStmt(); auto *CS = dyn_cast(Stmt); bool HasLastprivates = false; auto &&CodeGen = [&S, Stmt, CS, &HasLastprivates](CodeGenFunction &CGF, PrePostActionTy &) { - OMPCancelStackRAII CancelRegion(CGF); auto &C = CGF.CGM.getContext(); auto KmpInt32Ty = C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); // Emit helper vars inits. LValue LB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.lb.", CGF.Builder.getInt32(0)); auto *GlobalUBVal = CS != nullptr ? CGF.Builder.getInt32(CS->size() - 1) : CGF.Builder.getInt32(0); LValue UB = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.ub.", GlobalUBVal); LValue ST = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.st.", CGF.Builder.getInt32(1)); LValue IL = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.il.", CGF.Builder.getInt32(0)); // Loop counter. LValue IV = createSectionLVal(CGF, KmpInt32Ty, ".omp.sections.iv."); OpaqueValueExpr IVRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue); CodeGenFunction::OpaqueValueMapping OpaqueIV(CGF, &IVRefExpr, IV); OpaqueValueExpr UBRefExpr(S.getLocStart(), KmpInt32Ty, VK_LValue); CodeGenFunction::OpaqueValueMapping OpaqueUB(CGF, &UBRefExpr, UB); // Generate condition for loop. BinaryOperator Cond(&IVRefExpr, &UBRefExpr, BO_LE, C.BoolTy, VK_RValue, OK_Ordinary, S.getLocStart(), /*fpContractable=*/false); // Increment for loop counter. UnaryOperator Inc(&IVRefExpr, UO_PreInc, KmpInt32Ty, VK_RValue, OK_Ordinary, S.getLocStart()); auto BodyGen = [Stmt, CS, &S, &IV](CodeGenFunction &CGF) { // Iterate through all sections and emit a switch construct: // switch (IV) { // case 0: // ; // break; // ... // case - 1: // - 1]>; // break; // } // .omp.sections.exit: auto *ExitBB = CGF.createBasicBlock(".omp.sections.exit"); auto *SwitchStmt = CGF.Builder.CreateSwitch( CGF.EmitLoadOfLValue(IV, S.getLocStart()).getScalarVal(), ExitBB, CS == nullptr ? 1 : CS->size()); if (CS) { unsigned CaseNumber = 0; for (auto *SubStmt : CS->children()) { auto CaseBB = CGF.createBasicBlock(".omp.sections.case"); CGF.EmitBlock(CaseBB); SwitchStmt->addCase(CGF.Builder.getInt32(CaseNumber), CaseBB); CGF.EmitStmt(SubStmt); CGF.EmitBranch(ExitBB); ++CaseNumber; } } else { auto CaseBB = CGF.createBasicBlock(".omp.sections.case"); CGF.EmitBlock(CaseBB); SwitchStmt->addCase(CGF.Builder.getInt32(0), CaseBB); CGF.EmitStmt(Stmt); CGF.EmitBranch(ExitBB); } CGF.EmitBlock(ExitBB, /*IsFinished=*/true); }; CodeGenFunction::OMPPrivateScope LoopScope(CGF); if (CGF.EmitOMPFirstprivateClause(S, LoopScope)) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables and post-update of lastprivate // variables. CGF.CGM.getOpenMPRuntime().emitBarrierCall( CGF, S.getLocStart(), OMPD_unknown, /*EmitChecks=*/false, /*ForceSimpleCall=*/true); } CGF.EmitOMPPrivateClause(S, LoopScope); HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); (void)LoopScope.Privatize(); // Emit static non-chunked loop. OpenMPScheduleTy ScheduleKind; ScheduleKind.Schedule = OMPC_SCHEDULE_static; CGF.CGM.getOpenMPRuntime().emitForStaticInit( CGF, S.getLocStart(), ScheduleKind, /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); // UB = min(UB, GlobalUB); auto *UBVal = CGF.EmitLoadOfScalar(UB, S.getLocStart()); auto *MinUBGlobalUB = CGF.Builder.CreateSelect( CGF.Builder.CreateICmpSLT(UBVal, GlobalUBVal), UBVal, GlobalUBVal); CGF.EmitStoreOfScalar(MinUBGlobalUB, UB); // IV = LB; CGF.EmitStoreOfScalar(CGF.EmitLoadOfScalar(LB, S.getLocStart()), IV); // while (idx <= UB) { BODY; ++idx; } CGF.EmitOMPInnerLoop(S, /*RequiresCleanup=*/false, &Cond, &Inc, BodyGen, [](CodeGenFunction &) {}); // Tell the runtime we are done. - SourceLocation ELoc = S.getLocEnd(); - auto &&FinalCodeGen = [ELoc](CodeGenFunction &CGF) { - CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, ELoc); + auto &&CodeGen = [&S](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime().emitForStaticFinish(CGF, S.getLocEnd()); }; - FinalCodeGen(CGF); - CGF.OMPCancelStack.back().CodeGen = FinalCodeGen; + CGF.OMPCancelStack.emitExit(CGF, S.getDirectiveKind(), CodeGen); CGF.EmitOMPReductionClauseFinal(S); // Emit post-update of the reduction variables if IsLastIter != 0. emitPostUpdateForReductionClause( CGF, S, [&](CodeGenFunction &CGF) -> llvm::Value * { return CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart())); }); // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivates) CGF.EmitOMPLastprivateClauseFinal( S, /*NoFinals=*/false, CGF.Builder.CreateIsNotNull( CGF.EmitLoadOfScalar(IL, S.getLocStart()))); }; bool HasCancel = false; if (auto *OSD = dyn_cast(&S)) HasCancel = OSD->hasCancel(); else if (auto *OPSD = dyn_cast(&S)) HasCancel = OPSD->hasCancel(); + OMPCancelStackRAII CancelRegion(*this, S.getDirectiveKind(), HasCancel); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_sections, CodeGen, HasCancel); // Emit barrier for lastprivates only if 'sections' directive has 'nowait' // clause. Otherwise the barrier will be generated by the codegen for the // directive. if (HasLastprivates && S.getSingleClause()) { // Emit implicit barrier to synchronize threads and avoid data races on // initialization of firstprivate variables. CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_unknown); } } void CodeGenFunction::EmitOMPSectionsDirective(const OMPSectionsDirective &S) { { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); EmitSections(S); } // Emit an implicit barrier at the end. if (!S.getSingleClause()) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_sections); } } void CodeGenFunction::EmitOMPSectionDirective(const OMPSectionDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_section, CodeGen, S.hasCancel()); } void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) { llvm::SmallVector CopyprivateVars; llvm::SmallVector DestExprs; llvm::SmallVector SrcExprs; llvm::SmallVector AssignmentOps; // Check if there are any 'copyprivate' clauses associated with this // 'single' construct. // Build a list of copyprivate variables along with helper expressions // (, , = expressions) for (const auto *C : S.getClausesOfKind()) { CopyprivateVars.append(C->varlists().begin(), C->varlists().end()); DestExprs.append(C->destination_exprs().begin(), C->destination_exprs().end()); SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end()); AssignmentOps.append(C->assignment_ops().begin(), C->assignment_ops().end()); } // Emit code for 'single' region along with 'copyprivate' clauses auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); OMPPrivateScope SingleScope(CGF); (void)CGF.EmitOMPFirstprivateClause(S, SingleScope); CGF.EmitOMPPrivateClause(S, SingleScope); (void)SingleScope.Privatize(); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitSingleRegion(*this, CodeGen, S.getLocStart(), CopyprivateVars, DestExprs, SrcExprs, AssignmentOps); } // Emit an implicit barrier at the end (to avoid data race on firstprivate // init or if no 'nowait' clause was specified and no 'copyprivate' clause). if (!S.getSingleClause() && CopyprivateVars.empty()) { CGM.getOpenMPRuntime().emitBarrierCall( *this, S.getLocStart(), S.getSingleClause() ? OMPD_unknown : OMPD_single); } } void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getLocStart()); } void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; Expr *Hint = nullptr; if (auto *HintClause = S.getSingleClause()) Hint = HintClause->getHint(); OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitCriticalRegion(*this, S.getDirectiveName().getAsString(), CodeGen, S.getLocStart(), Hint); } void CodeGenFunction::EmitOMPParallelForDirective( const OMPParallelForDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'for' directive. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { - OMPCancelStackRAII CancelRegion(CGF); + OMPCancelStackRAII CancelRegion(CGF, OMPD_parallel_for, S.hasCancel()); CGF.EmitOMPWorksharingLoop(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_for, CodeGen); } void CodeGenFunction::EmitOMPParallelForSimdDirective( const OMPParallelForSimdDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'for' directive. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitOMPWorksharingLoop(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_simd, CodeGen); } void CodeGenFunction::EmitOMPParallelSectionsDirective( const OMPParallelSectionsDirective &S) { // Emit directive as a combined directive that consists of two implicit // directives: 'parallel' with 'sections' directive. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitSections(S); }; emitCommonOMPParallelDirective(*this, S, OMPD_sections, CodeGen); } void CodeGenFunction::EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen, OMPTaskDataTy &Data) { // Emit outlined function for task construct. auto CS = cast(S.getAssociatedStmt()); auto *I = CS->getCapturedDecl()->param_begin(); auto *PartId = std::next(I); auto *TaskT = std::next(I, 4); // Check if the task is final if (const auto *Clause = S.getSingleClause()) { // If the condition constant folds and can be elided, try to avoid emitting // the condition and the dead arm of the if/else. auto *Cond = Clause->getCondition(); bool CondConstant; if (ConstantFoldsToSimpleInteger(Cond, CondConstant)) Data.Final.setInt(CondConstant); else Data.Final.setPointer(EvaluateExprAsBool(Cond)); } else { // By default the task is not final. Data.Final.setInt(/*IntVal=*/false); } // Check if the task has 'priority' clause. if (const auto *Clause = S.getSingleClause()) { // Runtime currently does not support codegen for priority clause argument. // TODO: Add codegen for priority clause arg when runtime lib support it. auto *Prio = Clause->getPriority(); Data.Priority.setInt(Prio); Data.Priority.setPointer(EmitScalarConversion( EmitScalarExpr(Prio), Prio->getType(), getContext().getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1), Prio->getExprLoc())); } // The first function argument for tasks is a thread id, the second one is a // part id (0 for tied tasks, >=0 for untied task). llvm::DenseSet EmittedAsPrivate; // Get list of private variables. for (const auto *C : S.getClausesOfKind()) { auto IRef = C->varlist_begin(); for (auto *IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { Data.PrivateVars.push_back(*IRef); Data.PrivateCopies.push_back(IInit); } ++IRef; } } EmittedAsPrivate.clear(); // Get list of firstprivate variables. for (const auto *C : S.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto IElemInitRef = C->inits().begin(); for (auto *IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { Data.FirstprivateVars.push_back(*IRef); Data.FirstprivateCopies.push_back(IInit); Data.FirstprivateInits.push_back(*IElemInitRef); } ++IRef; ++IElemInitRef; } } // Get list of lastprivate variables (for taskloops). llvm::DenseMap LastprivateDstsOrigs; for (const auto *C : S.getClausesOfKind()) { auto IRef = C->varlist_begin(); auto ID = C->destination_exprs().begin(); for (auto *IInit : C->private_copies()) { auto *OrigVD = cast(cast(*IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { Data.LastprivateVars.push_back(*IRef); Data.LastprivateCopies.push_back(IInit); } LastprivateDstsOrigs.insert( {cast(cast(*ID)->getDecl()), cast(*IRef)}); ++IRef; ++ID; } } // Build list of dependences. for (const auto *C : S.getClausesOfKind()) for (auto *IRef : C->varlists()) Data.Dependences.push_back(std::make_pair(C->getDependencyKind(), IRef)); auto &&CodeGen = [PartId, &S, &Data, CS, &BodyGen, &LastprivateDstsOrigs]( CodeGenFunction &CGF, PrePostActionTy &Action) { // Set proper addresses for generated private copies. OMPPrivateScope Scope(CGF); if (!Data.PrivateVars.empty() || !Data.FirstprivateVars.empty() || !Data.LastprivateVars.empty()) { auto *CopyFn = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(3))); auto *PrivatesPtr = CGF.Builder.CreateLoad( CGF.GetAddrOfLocalVar(CS->getCapturedDecl()->getParam(2))); // Map privates. llvm::SmallVector, 16> PrivatePtrs; llvm::SmallVector CallArgs; CallArgs.push_back(PrivatesPtr); for (auto *E : Data.PrivateVars) { auto *VD = cast(cast(E)->getDecl()); Address PrivatePtr = CGF.CreateMemTemp( CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr"); PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } for (auto *E : Data.FirstprivateVars) { auto *VD = cast(cast(E)->getDecl()); Address PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".firstpriv.ptr.addr"); PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } for (auto *E : Data.LastprivateVars) { auto *VD = cast(cast(E)->getDecl()); Address PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".lastpriv.ptr.addr"); PrivatePtrs.push_back(std::make_pair(VD, PrivatePtr)); CallArgs.push_back(PrivatePtr.getPointer()); } CGF.EmitRuntimeCall(CopyFn, CallArgs); for (auto &&Pair : LastprivateDstsOrigs) { auto *OrigVD = cast(Pair.second->getDecl()); DeclRefExpr DRE( const_cast(OrigVD), /*RefersToEnclosingVariableOrCapture=*/CGF.CapturedStmtInfo->lookup( OrigVD) != nullptr, Pair.second->getType(), VK_LValue, Pair.second->getExprLoc()); Scope.addPrivate(Pair.first, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(); }); } for (auto &&Pair : PrivatePtrs) { Address Replacement(CGF.Builder.CreateLoad(Pair.second), CGF.getContext().getDeclAlign(Pair.first)); Scope.addPrivate(Pair.first, [Replacement]() { return Replacement; }); } } (void)Scope.Privatize(); Action.Enter(CGF); BodyGen(CGF); }; auto *OutlinedFn = CGM.getOpenMPRuntime().emitTaskOutlinedFunction( S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied, Data.NumberOfParts); OMPLexicalScope Scope(*this, S); TaskGen(*this, OutlinedFn, Data); } void CodeGenFunction::EmitOMPTaskDirective(const OMPTaskDirective &S) { // Emit outlined function for task construct. auto CS = cast(S.getAssociatedStmt()); auto CapturedStruct = GenerateCapturedStmtArgument(*CS); auto SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl()); const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_task) { IfCond = C->getCondition(); break; } } OMPTaskDataTy Data; // Check if we should emit tied or untied task. Data.Tied = !S.getSingleClause(); auto &&BodyGen = [CS](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitStmt(CS->getCapturedStmt()); }; auto &&TaskGen = [&S, SharedsTy, CapturedStruct, IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn, const OMPTaskDataTy &Data) { CGF.CGM.getOpenMPRuntime().emitTaskCall(CGF, S.getLocStart(), S, OutlinedFn, SharedsTy, CapturedStruct, IfCond, Data); }; EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); } void CodeGenFunction::EmitOMPTaskyieldDirective( const OMPTaskyieldDirective &S) { CGM.getOpenMPRuntime().emitTaskyieldCall(*this, S.getLocStart()); } void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) { CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getLocStart(), OMPD_barrier); } void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) { CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getLocStart()); } void CodeGenFunction::EmitOMPTaskgroupDirective( const OMPTaskgroupDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitTaskgroupRegion(*this, CodeGen, S.getLocStart()); } void CodeGenFunction::EmitOMPFlushDirective(const OMPFlushDirective &S) { CGM.getOpenMPRuntime().emitFlush(*this, [&]() -> ArrayRef { if (const auto *FlushClause = S.getSingleClause()) { return llvm::makeArrayRef(FlushClause->varlist_begin(), FlushClause->varlist_end()); } return llvm::None; }(), S.getLocStart()); } void CodeGenFunction::EmitOMPDistributeLoop(const OMPDistributeDirective &S) { // Emit the loop iteration variable. auto IVExpr = cast(S.getIterationVariable()); auto IVDecl = cast(IVExpr->getDecl()); EmitVarDecl(*IVDecl); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on each // iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. EmitIgnoredExpr(S.getCalcLastIteration()); } auto &RT = CGM.getOpenMPRuntime(); // Check pre-condition. { OMPLoopScope PreInitScope(*this, S); // Skip the entire loop if we don't meet the precondition. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; if (ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return; } else { auto *ThenBlock = createBasicBlock("omp.precond.then"); ContBlock = createBasicBlock("omp.precond.end"); emitPreCond(*this, S, S.getPreCond(), ThenBlock, ContBlock, getProfileCount(&S)); EmitBlock(ThenBlock); incrementProfileCounter(&S); } // Emit 'then' code. { // Emit helper vars inits. LValue LB = EmitOMPHelperVar(*this, cast(S.getLowerBoundVariable())); LValue UB = EmitOMPHelperVar(*this, cast(S.getUpperBoundVariable())); LValue ST = EmitOMPHelperVar(*this, cast(S.getStrideVariable())); LValue IL = EmitOMPHelperVar(*this, cast(S.getIsLastIterVariable())); OMPPrivateScope LoopScope(*this); EmitOMPPrivateLoopCounters(S, LoopScope); (void)LoopScope.Privatize(); // Detect the distribute schedule kind and chunk. llvm::Value *Chunk = nullptr; OpenMPDistScheduleClauseKind ScheduleKind = OMPC_DIST_SCHEDULE_unknown; if (auto *C = S.getSingleClause()) { ScheduleKind = C->getDistScheduleKind(); if (const auto *Ch = C->getChunkSize()) { Chunk = EmitScalarExpr(Ch); Chunk = EmitScalarConversion(Chunk, Ch->getType(), S.getIterationVariable()->getType(), S.getLocStart()); } } const unsigned IVSize = getContext().getTypeSize(IVExpr->getType()); const bool IVSigned = IVExpr->getType()->hasSignedIntegerRepresentation(); // OpenMP [2.10.8, distribute Construct, Description] // If dist_schedule is specified, kind must be static. If specified, // iterations are divided into chunks of size chunk_size, chunks are // assigned to the teams of the league in a round-robin fashion in the // order of the team number. When no chunk_size is specified, the // iteration space is divided into chunks that are approximately equal // in size, and at most one chunk is distributed to each team of the // league. The size of the chunks is unspecified in this case. if (RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr)) { RT.emitDistributeStaticInit(*this, S.getLocStart(), ScheduleKind, IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(), LB.getAddress(), UB.getAddress(), ST.getAddress()); auto LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); // UB = min(UB, GlobalUB); EmitIgnoredExpr(S.getEnsureUpperBound()); // IV = LB; EmitIgnoredExpr(S.getInit()); // while (idx <= UB) { BODY; ++idx; } EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S, LoopExit](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. RT.emitForStaticFinish(*this, S.getLocStart()); } else { // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(), Chunk); } } // We're now done with the loop, so jump to the continuation block. if (ContBlock) { EmitBranch(ContBlock); EmitBlock(ContBlock, true); } } } void CodeGenFunction::EmitOMPDistributeDirective( const OMPDistributeDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitOMPDistributeLoop(S); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_distribute, CodeGen, false); } static llvm::Function *emitOutlinedOrderedFunction(CodeGenModule &CGM, const CapturedStmt *S) { CodeGenFunction CGF(CGM, /*suppressNewContext=*/true); CodeGenFunction::CGCapturedStmtInfo CapStmtInfo; CGF.CapturedStmtInfo = &CapStmtInfo; auto *Fn = CGF.GenerateOpenMPCapturedStmtFunction(*S); Fn->addFnAttr(llvm::Attribute::NoInline); return Fn; } void CodeGenFunction::EmitOMPOrderedDirective(const OMPOrderedDirective &S) { if (!S.getAssociatedStmt()) { for (const auto *DC : S.getClausesOfKind()) CGM.getOpenMPRuntime().emitDoacrossOrdered(*this, DC); return; } auto *C = S.getSingleClause(); auto &&CodeGen = [&S, C, this](CodeGenFunction &CGF, PrePostActionTy &Action) { if (C) { auto CS = cast(S.getAssociatedStmt()); llvm::SmallVector CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); auto *OutlinedFn = emitOutlinedOrderedFunction(CGM, CS); CGF.EmitNounwindRuntimeCall(OutlinedFn, CapturedVars); } else { Action.Enter(CGF); CGF.EmitStmt( cast(S.getAssociatedStmt())->getCapturedStmt()); } }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitOrderedRegion(*this, CodeGen, S.getLocStart(), !C); } static llvm::Value *convertToScalarValue(CodeGenFunction &CGF, RValue Val, QualType SrcType, QualType DestType, SourceLocation Loc) { assert(CGF.hasScalarEvaluationKind(DestType) && "DestType must have scalar evaluation kind."); assert(!Val.isAggregate() && "Must be a scalar or complex."); return Val.isScalar() ? CGF.EmitScalarConversion(Val.getScalarVal(), SrcType, DestType, Loc) : CGF.EmitComplexToScalarConversion(Val.getComplexVal(), SrcType, DestType, Loc); } static CodeGenFunction::ComplexPairTy convertToComplexValue(CodeGenFunction &CGF, RValue Val, QualType SrcType, QualType DestType, SourceLocation Loc) { assert(CGF.getEvaluationKind(DestType) == TEK_Complex && "DestType must have complex evaluation kind."); CodeGenFunction::ComplexPairTy ComplexVal; if (Val.isScalar()) { // Convert the input element to the element type of the complex. auto DestElementType = DestType->castAs()->getElementType(); auto ScalarVal = CGF.EmitScalarConversion(Val.getScalarVal(), SrcType, DestElementType, Loc); ComplexVal = CodeGenFunction::ComplexPairTy( ScalarVal, llvm::Constant::getNullValue(ScalarVal->getType())); } else { assert(Val.isComplex() && "Must be a scalar or complex."); auto SrcElementType = SrcType->castAs()->getElementType(); auto DestElementType = DestType->castAs()->getElementType(); ComplexVal.first = CGF.EmitScalarConversion( Val.getComplexVal().first, SrcElementType, DestElementType, Loc); ComplexVal.second = CGF.EmitScalarConversion( Val.getComplexVal().second, SrcElementType, DestElementType, Loc); } return ComplexVal; } static void emitSimpleAtomicStore(CodeGenFunction &CGF, bool IsSeqCst, LValue LVal, RValue RVal) { if (LVal.isGlobalReg()) { CGF.EmitStoreThroughGlobalRegLValue(RVal, LVal); } else { CGF.EmitAtomicStore(RVal, LVal, IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent : llvm::AtomicOrdering::Monotonic, LVal.isVolatile(), /*IsInit=*/false); } } void CodeGenFunction::emitOMPSimpleStore(LValue LVal, RValue RVal, QualType RValTy, SourceLocation Loc) { switch (getEvaluationKind(LVal.getType())) { case TEK_Scalar: EmitStoreThroughLValue(RValue::get(convertToScalarValue( *this, RVal, RValTy, LVal.getType(), Loc)), LVal); break; case TEK_Complex: EmitStoreOfComplex( convertToComplexValue(*this, RVal, RValTy, LVal.getType(), Loc), LVal, /*isInit=*/false); break; case TEK_Aggregate: llvm_unreachable("Must be a scalar or complex."); } } static void EmitOMPAtomicReadExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *V, SourceLocation Loc) { // v = x; assert(V->isLValue() && "V of 'omp atomic read' is not lvalue"); assert(X->isLValue() && "X of 'omp atomic read' is not lvalue"); LValue XLValue = CGF.EmitLValue(X); LValue VLValue = CGF.EmitLValue(V); RValue Res = XLValue.isGlobalReg() ? CGF.EmitLoadOfLValue(XLValue, Loc) : CGF.EmitAtomicLoad( XLValue, Loc, IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent : llvm::AtomicOrdering::Monotonic, XLValue.isVolatile()); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); CGF.emitOMPSimpleStore(VLValue, Res, X->getType().getNonReferenceType(), Loc); } static void EmitOMPAtomicWriteExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *E, SourceLocation Loc) { // x = expr; assert(X->isLValue() && "X of 'omp atomic write' is not lvalue"); emitSimpleAtomicStore(CGF, IsSeqCst, CGF.EmitLValue(X), CGF.EmitAnyExpr(E)); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static std::pair emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, RValue Update, BinaryOperatorKind BO, llvm::AtomicOrdering AO, bool IsXLHSInRHSPart) { auto &Context = CGF.CGM.getContext(); // Allow atomicrmw only if 'x' and 'update' are integer values, lvalue for 'x' // expression is simple and atomic is allowed for the given type for the // target platform. if (BO == BO_Comma || !Update.isScalar() || !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() || (!isa(Update.getScalarVal()) && (Update.getScalarVal()->getType() != X.getAddress().getElementType())) || !X.getAddress().getElementType()->isIntegerTy() || !Context.getTargetInfo().hasBuiltinAtomic( Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment()))) return std::make_pair(false, RValue::get(nullptr)); llvm::AtomicRMWInst::BinOp RMWOp; switch (BO) { case BO_Add: RMWOp = llvm::AtomicRMWInst::Add; break; case BO_Sub: if (!IsXLHSInRHSPart) return std::make_pair(false, RValue::get(nullptr)); RMWOp = llvm::AtomicRMWInst::Sub; break; case BO_And: RMWOp = llvm::AtomicRMWInst::And; break; case BO_Or: RMWOp = llvm::AtomicRMWInst::Or; break; case BO_Xor: RMWOp = llvm::AtomicRMWInst::Xor; break; case BO_LT: RMWOp = X.getType()->hasSignedIntegerRepresentation() ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Min : llvm::AtomicRMWInst::Max) : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMin : llvm::AtomicRMWInst::UMax); break; case BO_GT: RMWOp = X.getType()->hasSignedIntegerRepresentation() ? (IsXLHSInRHSPart ? llvm::AtomicRMWInst::Max : llvm::AtomicRMWInst::Min) : (IsXLHSInRHSPart ? llvm::AtomicRMWInst::UMax : llvm::AtomicRMWInst::UMin); break; case BO_Assign: RMWOp = llvm::AtomicRMWInst::Xchg; break; case BO_Mul: case BO_Div: case BO_Rem: case BO_Shl: case BO_Shr: case BO_LAnd: case BO_LOr: return std::make_pair(false, RValue::get(nullptr)); case BO_PtrMemD: case BO_PtrMemI: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: case BO_AddAssign: case BO_SubAssign: case BO_AndAssign: case BO_OrAssign: case BO_XorAssign: case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_ShlAssign: case BO_ShrAssign: case BO_Comma: llvm_unreachable("Unsupported atomic update operation"); } auto *UpdateVal = Update.getScalarVal(); if (auto *IC = dyn_cast(UpdateVal)) { UpdateVal = CGF.Builder.CreateIntCast( IC, X.getAddress().getElementType(), X.getType()->hasSignedIntegerRepresentation()); } auto *Res = CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO); return std::make_pair(true, RValue::get(Res)); } std::pair CodeGenFunction::EmitOMPAtomicSimpleUpdateExpr( LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, llvm::AtomicOrdering AO, SourceLocation Loc, const llvm::function_ref &CommonGen) { // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; auto Res = emitOMPAtomicRMW(*this, X, E, BO, AO, IsXLHSInRHSPart); if (!Res.first) { if (X.isGlobalReg()) { // Emit an update expression: 'xrval' binop 'expr' or 'expr' binop // 'xrval'. EmitStoreThroughLValue(CommonGen(EmitLoadOfLValue(X, Loc)), X); } else { // Perform compare-and-swap procedure. EmitAtomicUpdate(X, AO, CommonGen, X.getType().isVolatileQualified()); } } return Res; } static void EmitOMPAtomicUpdateExpr(CodeGenFunction &CGF, bool IsSeqCst, const Expr *X, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { assert(isa(UE->IgnoreImpCasts()) && "Update expr in 'atomic update' must be a binary operator."); auto *BOUE = cast(UE->IgnoreImpCasts()); // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; assert(X->isLValue() && "X of 'omp atomic update' is not lvalue"); LValue XLValue = CGF.EmitLValue(X); RValue ExprRValue = CGF.EmitAnyExpr(E); auto AO = IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent : llvm::AtomicOrdering::Monotonic; auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS; auto Gen = [&CGF, UE, ExprRValue, XRValExpr, ERValExpr](RValue XRValue) -> RValue { CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue); return CGF.EmitAnyExpr(UE); }; (void)CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static RValue convertToType(CodeGenFunction &CGF, RValue Value, QualType SourceType, QualType ResType, SourceLocation Loc) { switch (CGF.getEvaluationKind(ResType)) { case TEK_Scalar: return RValue::get( convertToScalarValue(CGF, Value, SourceType, ResType, Loc)); case TEK_Complex: { auto Res = convertToComplexValue(CGF, Value, SourceType, ResType, Loc); return RValue::getComplex(Res.first, Res.second); } case TEK_Aggregate: break; } llvm_unreachable("Must be a scalar or complex."); } static void EmitOMPAtomicCaptureExpr(CodeGenFunction &CGF, bool IsSeqCst, bool IsPostfixUpdate, const Expr *V, const Expr *X, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { assert(X->isLValue() && "X of 'omp atomic capture' is not lvalue"); assert(V->isLValue() && "V of 'omp atomic capture' is not lvalue"); RValue NewVVal; LValue VLValue = CGF.EmitLValue(V); LValue XLValue = CGF.EmitLValue(X); RValue ExprRValue = CGF.EmitAnyExpr(E); auto AO = IsSeqCst ? llvm::AtomicOrdering::SequentiallyConsistent : llvm::AtomicOrdering::Monotonic; QualType NewVValType; if (UE) { // 'x' is updated with some additional value. assert(isa(UE->IgnoreImpCasts()) && "Update expr in 'atomic capture' must be a binary operator."); auto *BOUE = cast(UE->IgnoreImpCasts()); // Update expressions are allowed to have the following forms: // x binop= expr; -> xrval + expr; // x++, ++x -> xrval + 1; // x--, --x -> xrval - 1; // x = x binop expr; -> xrval binop expr // x = expr Op x; - > expr binop xrval; auto *LHS = cast(BOUE->getLHS()->IgnoreImpCasts()); auto *RHS = cast(BOUE->getRHS()->IgnoreImpCasts()); auto *XRValExpr = IsXLHSInRHSPart ? LHS : RHS; NewVValType = XRValExpr->getType(); auto *ERValExpr = IsXLHSInRHSPart ? RHS : LHS; auto &&Gen = [&CGF, &NewVVal, UE, ExprRValue, XRValExpr, ERValExpr, IsSeqCst, IsPostfixUpdate](RValue XRValue) -> RValue { CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, XRValue); RValue Res = CGF.EmitAnyExpr(UE); NewVVal = IsPostfixUpdate ? XRValue : Res; return Res; }; auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, BOUE->getOpcode(), IsXLHSInRHSPart, AO, Loc, Gen); if (Res.first) { // 'atomicrmw' instruction was generated. if (IsPostfixUpdate) { // Use old value from 'atomicrmw'. NewVVal = Res.second; } else { // 'atomicrmw' does not provide new value, so evaluate it using old // value of 'x'. CodeGenFunction::OpaqueValueMapping MapExpr(CGF, ERValExpr, ExprRValue); CodeGenFunction::OpaqueValueMapping MapX(CGF, XRValExpr, Res.second); NewVVal = CGF.EmitAnyExpr(UE); } } } else { // 'x' is simply rewritten with some 'expr'. NewVValType = X->getType().getNonReferenceType(); ExprRValue = convertToType(CGF, ExprRValue, E->getType(), X->getType().getNonReferenceType(), Loc); auto &&Gen = [&CGF, &NewVVal, ExprRValue](RValue XRValue) -> RValue { NewVVal = XRValue; return ExprRValue; }; // Try to perform atomicrmw xchg, otherwise simple exchange. auto Res = CGF.EmitOMPAtomicSimpleUpdateExpr( XLValue, ExprRValue, /*BO=*/BO_Assign, /*IsXLHSInRHSPart=*/false, AO, Loc, Gen); if (Res.first) { // 'atomicrmw' instruction was generated. NewVVal = IsPostfixUpdate ? Res.second : ExprRValue; } } // Emit post-update store to 'v' of old/new 'x' value. CGF.emitOMPSimpleStore(VLValue, NewVVal, NewVValType, Loc); // OpenMP, 2.12.6, atomic Construct // Any atomic construct with a seq_cst clause forces the atomically // performed operation to include an implicit flush operation without a // list. if (IsSeqCst) CGF.CGM.getOpenMPRuntime().emitFlush(CGF, llvm::None, Loc); } static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, bool IsSeqCst, bool IsPostfixUpdate, const Expr *X, const Expr *V, const Expr *E, const Expr *UE, bool IsXLHSInRHSPart, SourceLocation Loc) { switch (Kind) { case OMPC_read: EmitOMPAtomicReadExpr(CGF, IsSeqCst, X, V, Loc); break; case OMPC_write: EmitOMPAtomicWriteExpr(CGF, IsSeqCst, X, E, Loc); break; case OMPC_unknown: case OMPC_update: EmitOMPAtomicUpdateExpr(CGF, IsSeqCst, X, E, UE, IsXLHSInRHSPart, Loc); break; case OMPC_capture: EmitOMPAtomicCaptureExpr(CGF, IsSeqCst, IsPostfixUpdate, V, X, E, UE, IsXLHSInRHSPart, Loc); break; case OMPC_if: case OMPC_final: case OMPC_num_threads: case OMPC_private: case OMPC_firstprivate: case OMPC_lastprivate: case OMPC_reduction: case OMPC_safelen: case OMPC_simdlen: case OMPC_collapse: case OMPC_default: case OMPC_seq_cst: case OMPC_shared: case OMPC_linear: case OMPC_aligned: case OMPC_copyin: case OMPC_copyprivate: case OMPC_flush: case OMPC_proc_bind: case OMPC_schedule: case OMPC_ordered: case OMPC_nowait: case OMPC_untied: case OMPC_threadprivate: case OMPC_depend: case OMPC_mergeable: case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: case OMPC_num_teams: case OMPC_thread_limit: case OMPC_priority: case OMPC_grainsize: case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: case OMPC_dist_schedule: case OMPC_defaultmap: case OMPC_uniform: case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) { bool IsSeqCst = S.getSingleClause(); OpenMPClauseKind Kind = OMPC_unknown; for (auto *C : S.clauses()) { // Find first clause (skip seq_cst clause, if it is first). if (C->getClauseKind() != OMPC_seq_cst) { Kind = C->getClauseKind(); break; } } const auto *CS = S.getAssociatedStmt()->IgnoreContainers(/*IgnoreCaptured=*/true); if (const auto *EWC = dyn_cast(CS)) { enterFullExpression(EWC); } // Processing for statements under 'atomic capture'. if (const auto *Compound = dyn_cast(CS)) { for (const auto *C : Compound->body()) { if (const auto *EWC = dyn_cast(C)) { enterFullExpression(EWC); } } } auto &&CodeGen = [&S, Kind, IsSeqCst, CS](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitStopPoint(CS); EmitOMPAtomicExpr(CGF, Kind, IsSeqCst, S.isPostfixUpdate(), S.getX(), S.getV(), S.getExpr(), S.getUpdateExpr(), S.isXLHSInRHSPart(), S.getLocStart()); }; OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_atomic, CodeGen); } std::pair CodeGenFunction::EmitOMPTargetDirectiveOutlinedFunction( CodeGenModule &CGM, const OMPTargetDirective &S, StringRef ParentName, bool IsOffloadEntry) { llvm::Function *OutlinedFn = nullptr; llvm::Constant *OutlinedFnID = nullptr; auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { OMPPrivateScope PrivateScope(CGF); (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); CGF.EmitOMPPrivateClause(S, PrivateScope); (void)PrivateScope.Privatize(); Action.Enter(CGF); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; // Emit target region as a standalone region. CGM.getOpenMPRuntime().emitTargetOutlinedFunction( S, ParentName, OutlinedFn, OutlinedFnID, IsOffloadEntry, CodeGen); return std::make_pair(OutlinedFn, OutlinedFnID); } void CodeGenFunction::EmitOMPTargetDirective(const OMPTargetDirective &S) { const CapturedStmt &CS = *cast(S.getAssociatedStmt()); llvm::SmallVector CapturedVars; GenerateOpenMPCapturedVars(CS, CapturedVars); llvm::Function *Fn = nullptr; llvm::Constant *FnID = nullptr; // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) { IfCond = C->getCondition(); } // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) { Device = C->getDevice(); } // Check if we have an if clause whose conditional always evaluates to false // or if we do not have any targets specified. If so the target region is not // an offload entry point. bool IsOffloadEntry = true; if (IfCond) { bool Val; if (ConstantFoldsToSimpleInteger(IfCond, Val) && !Val) IsOffloadEntry = false; } if (CGM.getLangOpts().OMPTargetTriples.empty()) IsOffloadEntry = false; assert(CurFuncDecl && "No parent declaration for target region!"); StringRef ParentName; // In case we have Ctors/Dtors we use the complete type variant to produce // the mangling of the device outlined kernel. if (auto *D = dyn_cast(CurFuncDecl)) ParentName = CGM.getMangledName(GlobalDecl(D, Ctor_Complete)); else if (auto *D = dyn_cast(CurFuncDecl)) ParentName = CGM.getMangledName(GlobalDecl(D, Dtor_Complete)); else ParentName = CGM.getMangledName(GlobalDecl(cast(CurFuncDecl))); std::tie(Fn, FnID) = EmitOMPTargetDirectiveOutlinedFunction( CGM, S, ParentName, IsOffloadEntry); OMPLexicalScope Scope(*this, S); CGM.getOpenMPRuntime().emitTargetCall(*this, S, Fn, FnID, IfCond, Device, CapturedVars); } static void emitCommonOMPTeamsDirective(CodeGenFunction &CGF, const OMPExecutableDirective &S, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { auto CS = cast(S.getAssociatedStmt()); auto OutlinedFn = CGF.CGM.getOpenMPRuntime(). emitParallelOrTeamsOutlinedFunction(S, *CS->getCapturedDecl()->param_begin(), InnermostKind, CodeGen); const OMPTeamsDirective &TD = *dyn_cast(&S); const OMPNumTeamsClause *NT = TD.getSingleClause(); const OMPThreadLimitClause *TL = TD.getSingleClause(); if (NT || TL) { Expr *NumTeams = (NT) ? NT->getNumTeams() : nullptr; Expr *ThreadLimit = (TL) ? TL->getThreadLimit() : nullptr; CGF.CGM.getOpenMPRuntime().emitNumTeamsClause(CGF, NumTeams, ThreadLimit, S.getLocStart()); } OMPLexicalScope Scope(CGF, S); llvm::SmallVector CapturedVars; CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars); CGF.CGM.getOpenMPRuntime().emitTeamsCall(CGF, S, S.getLocStart(), OutlinedFn, CapturedVars); } void CodeGenFunction::EmitOMPTeamsDirective(const OMPTeamsDirective &S) { // Emit parallel region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { OMPPrivateScope PrivateScope(CGF); (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); CGF.EmitOMPPrivateClause(S, PrivateScope); (void)PrivateScope.Privatize(); CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; emitCommonOMPTeamsDirective(*this, S, OMPD_teams, CodeGen); } void CodeGenFunction::EmitOMPCancellationPointDirective( const OMPCancellationPointDirective &S) { CGM.getOpenMPRuntime().emitCancellationPointCall(*this, S.getLocStart(), S.getCancelRegion()); } void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_cancel) { IfCond = C->getCondition(); break; } } CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), IfCond, S.getCancelRegion()); } CodeGenFunction::JumpDest CodeGenFunction::getOMPCancelDestination(OpenMPDirectiveKind Kind) { - if (Kind == OMPD_parallel || Kind == OMPD_task) + if (Kind == OMPD_parallel || Kind == OMPD_task || + Kind == OMPD_target_parallel) return ReturnBlock; assert(Kind == OMPD_for || Kind == OMPD_section || Kind == OMPD_sections || Kind == OMPD_parallel_sections || Kind == OMPD_parallel_for || - Kind == OMPD_distribute_parallel_for); - if (!OMPCancelStack.back().ExitBlock.isValid()) - OMPCancelStack.back().ExitBlock = getJumpDestInCurrentScope("cancel.exit"); - return OMPCancelStack.back().ExitBlock; + Kind == OMPD_distribute_parallel_for || + Kind == OMPD_target_parallel_for); + return OMPCancelStack.getExitBlock(); } // Generate the instructions for '#pragma omp target data' directive. void CodeGenFunction::EmitOMPTargetDataDirective( const OMPTargetDataDirective &S) { // The target data enclosed region is implemented just by emitting the // statement. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &) { CGF.EmitStmt(cast(S.getAssociatedStmt())->getCapturedStmt()); }; // If we don't have target devices, don't bother emitting the data mapping // code. if (CGM.getLangOpts().OMPTargetTriples.empty()) { OMPLexicalScope Scope(*this, S, /*AsInlined=*/true); CGM.getOpenMPRuntime().emitInlinedDirective(*this, OMPD_target_data, CodeGen); return; } // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) IfCond = C->getCondition(); // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) Device = C->getDevice(); CGM.getOpenMPRuntime().emitTargetDataCalls(*this, S, IfCond, Device, CodeGen); } void CodeGenFunction::EmitOMPTargetEnterDataDirective( const OMPTargetEnterDataDirective &S) { // If we don't have target devices, don't bother emitting the data mapping // code. if (CGM.getLangOpts().OMPTargetTriples.empty()) return; // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) IfCond = C->getCondition(); // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) Device = C->getDevice(); CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); } void CodeGenFunction::EmitOMPTargetExitDataDirective( const OMPTargetExitDataDirective &S) { // If we don't have target devices, don't bother emitting the data mapping // code. if (CGM.getLangOpts().OMPTargetTriples.empty()) return; // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) IfCond = C->getCondition(); // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) Device = C->getDevice(); CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); } void CodeGenFunction::EmitOMPTargetParallelDirective( const OMPTargetParallelDirective &S) { // TODO: codegen for target parallel. } void CodeGenFunction::EmitOMPTargetParallelForDirective( const OMPTargetParallelForDirective &S) { // TODO: codegen for target parallel for. } /// Emit a helper variable and return corresponding lvalue. static void mapParam(CodeGenFunction &CGF, const DeclRefExpr *Helper, const ImplicitParamDecl *PVD, CodeGenFunction::OMPPrivateScope &Privates) { auto *VDecl = cast(Helper->getDecl()); Privates.addPrivate( VDecl, [&CGF, PVD]() -> Address { return CGF.GetAddrOfLocalVar(PVD); }); } void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { assert(isOpenMPTaskLoopDirective(S.getDirectiveKind())); // Emit outlined function for task construct. auto CS = cast(S.getAssociatedStmt()); auto CapturedStruct = GenerateCapturedStmtArgument(*CS); auto SharedsTy = getContext().getRecordType(CS->getCapturedRecordDecl()); const Expr *IfCond = nullptr; for (const auto *C : S.getClausesOfKind()) { if (C->getNameModifier() == OMPD_unknown || C->getNameModifier() == OMPD_taskloop) { IfCond = C->getCondition(); break; } } OMPTaskDataTy Data; // Check if taskloop must be emitted without taskgroup. Data.Nogroup = S.getSingleClause(); // TODO: Check if we should emit tied or untied task. Data.Tied = true; // Set scheduling for taskloop if (const auto* Clause = S.getSingleClause()) { // grainsize clause Data.Schedule.setInt(/*IntVal=*/false); Data.Schedule.setPointer(EmitScalarExpr(Clause->getGrainsize())); } else if (const auto* Clause = S.getSingleClause()) { // num_tasks clause Data.Schedule.setInt(/*IntVal=*/true); Data.Schedule.setPointer(EmitScalarExpr(Clause->getNumTasks())); } auto &&BodyGen = [CS, &S](CodeGenFunction &CGF, PrePostActionTy &) { // if (PreCond) { // for (IV in 0..LastIteration) BODY; // ; // } // // Emit: if (PreCond) - begin. // If the condition constant folds and can be elided, avoid emitting the // whole loop. bool CondConstant; llvm::BasicBlock *ContBlock = nullptr; OMPLoopScope PreInitScope(CGF, S); if (CGF.ConstantFoldsToSimpleInteger(S.getPreCond(), CondConstant)) { if (!CondConstant) return; } else { auto *ThenBlock = CGF.createBasicBlock("taskloop.if.then"); ContBlock = CGF.createBasicBlock("taskloop.if.end"); emitPreCond(CGF, S, S.getPreCond(), ThenBlock, ContBlock, CGF.getProfileCount(&S)); CGF.EmitBlock(ThenBlock); CGF.incrementProfileCounter(&S); } if (isOpenMPSimdDirective(S.getDirectiveKind())) CGF.EmitOMPSimdInit(S); OMPPrivateScope LoopScope(CGF); // Emit helper vars inits. enum { LowerBound = 5, UpperBound, Stride, LastIter }; auto *I = CS->getCapturedDecl()->param_begin(); auto *LBP = std::next(I, LowerBound); auto *UBP = std::next(I, UpperBound); auto *STP = std::next(I, Stride); auto *LIP = std::next(I, LastIter); mapParam(CGF, cast(S.getLowerBoundVariable()), *LBP, LoopScope); mapParam(CGF, cast(S.getUpperBoundVariable()), *UBP, LoopScope); mapParam(CGF, cast(S.getStrideVariable()), *STP, LoopScope); mapParam(CGF, cast(S.getIsLastIterVariable()), *LIP, LoopScope); CGF.EmitOMPPrivateLoopCounters(S, LoopScope); bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); // Emit the loop iteration variable. const Expr *IVExpr = S.getIterationVariable(); const VarDecl *IVDecl = cast(cast(IVExpr)->getDecl()); CGF.EmitVarDecl(*IVDecl); CGF.EmitIgnoredExpr(S.getInit()); // Emit the iterations count variable. // If it is not a variable, Sema decided to calculate iterations count on // each iteration (e.g., it is foldable into a constant). if (auto LIExpr = dyn_cast(S.getLastIteration())) { CGF.EmitVarDecl(*cast(LIExpr->getDecl())); // Emit calculation of the iterations count. CGF.EmitIgnoredExpr(S.getCalcLastIteration()); } CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), [&S](CodeGenFunction &CGF) { CGF.EmitOMPLoopBody(S, JumpDest()); CGF.EmitStopPoint(&S); }, [](CodeGenFunction &) {}); // Emit: if (PreCond) - end. if (ContBlock) { CGF.EmitBranch(ContBlock); CGF.EmitBlock(ContBlock, true); } // Emit final copy of the lastprivate variables if IsLastIter != 0. if (HasLastprivateClause) { CGF.EmitOMPLastprivateClauseFinal( S, isOpenMPSimdDirective(S.getDirectiveKind()), CGF.Builder.CreateIsNotNull(CGF.EmitLoadOfScalar( CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false, (*LIP)->getType(), S.getLocStart()))); } }; auto &&TaskGen = [&S, SharedsTy, CapturedStruct, IfCond](CodeGenFunction &CGF, llvm::Value *OutlinedFn, const OMPTaskDataTy &Data) { auto &&CodeGen = [&](CodeGenFunction &CGF, PrePostActionTy &) { OMPLoopScope PreInitScope(CGF, S); CGF.CGM.getOpenMPRuntime().emitTaskLoopCall(CGF, S.getLocStart(), S, OutlinedFn, SharedsTy, CapturedStruct, IfCond, Data); }; CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop, CodeGen); }; EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); } void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) { EmitOMPTaskLoopBasedDirective(S); } void CodeGenFunction::EmitOMPTaskLoopSimdDirective( const OMPTaskLoopSimdDirective &S) { EmitOMPTaskLoopBasedDirective(S); } // Generate the instructions for '#pragma omp target update' directive. void CodeGenFunction::EmitOMPTargetUpdateDirective( const OMPTargetUpdateDirective &S) { // If we don't have target devices, don't bother emitting the data mapping // code. if (CGM.getLangOpts().OMPTargetTriples.empty()) return; // Check if we have any if clause associated with the directive. const Expr *IfCond = nullptr; if (auto *C = S.getSingleClause()) IfCond = C->getCondition(); // Check if we have any device clause associated with the directive. const Expr *Device = nullptr; if (auto *C = S.getSingleClause()) Device = C->getDevice(); CGM.getOpenMPRuntime().emitTargetDataStandAloneCall(*this, S, IfCond, Device); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index f61ba69e3a0c..fb19a2657c9c 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1,3545 +1,3604 @@ //===-- CodeGenFunction.h - Per-Function state for LLVM CodeGen -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This is the internal per-function state used for llvm translation. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H #define LLVM_CLANG_LIB_CODEGEN_CODEGENFUNCTION_H #include "CGBuilder.h" #include "CGDebugInfo.h" #include "CGLoopInfo.h" #include "CGValue.h" #include "CodeGenModule.h" #include "CodeGenPGO.h" #include "EHScopeStack.h" #include "clang/AST/CharUnits.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/Type.h" #include "clang/Basic/ABI.h" #include "clang/Basic/CapturedStmt.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/SanitizerStats.h" namespace llvm { class BasicBlock; class LLVMContext; class MDNode; class Module; class SwitchInst; class Twine; class Value; class CallSite; } namespace clang { class ASTContext; class BlockDecl; class CXXDestructorDecl; class CXXForRangeStmt; class CXXTryStmt; class Decl; class LabelDecl; class EnumConstantDecl; class FunctionDecl; class FunctionProtoType; class LabelStmt; class ObjCContainerDecl; class ObjCInterfaceDecl; class ObjCIvarDecl; class ObjCMethodDecl; class ObjCImplementationDecl; class ObjCPropertyImplDecl; class TargetInfo; class VarDecl; class ObjCForCollectionStmt; class ObjCAtTryStmt; class ObjCAtThrowStmt; class ObjCAtSynchronizedStmt; class ObjCAutoreleasePoolStmt; namespace CodeGen { class CodeGenTypes; class CGFunctionInfo; class CGRecordLayout; class CGBlockInfo; class CGCXXABI; class BlockByrefHelpers; class BlockByrefInfo; class BlockFlags; class BlockFieldFlags; class RegionCodeGenTy; class TargetCodeGenInfo; struct OMPTaskDataTy; /// The kind of evaluation to perform on values of a particular /// type. Basically, is the code in CGExprScalar, CGExprComplex, or /// CGExprAgg? /// /// TODO: should vectors maybe be split out into their own thing? enum TypeEvaluationKind { TEK_Scalar, TEK_Complex, TEK_Aggregate }; /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. class CodeGenFunction : public CodeGenTypeCache { CodeGenFunction(const CodeGenFunction &) = delete; void operator=(const CodeGenFunction &) = delete; friend class CGCXXABI; public: /// A jump destination is an abstract label, branching to which may /// require a jump out through normal cleanups. struct JumpDest { JumpDest() : Block(nullptr), ScopeDepth(), Index(0) {} JumpDest(llvm::BasicBlock *Block, EHScopeStack::stable_iterator Depth, unsigned Index) : Block(Block), ScopeDepth(Depth), Index(Index) {} bool isValid() const { return Block != nullptr; } llvm::BasicBlock *getBlock() const { return Block; } EHScopeStack::stable_iterator getScopeDepth() const { return ScopeDepth; } unsigned getDestIndex() const { return Index; } // This should be used cautiously. void setScopeDepth(EHScopeStack::stable_iterator depth) { ScopeDepth = depth; } private: llvm::BasicBlock *Block; EHScopeStack::stable_iterator ScopeDepth; unsigned Index; }; CodeGenModule &CGM; // Per-module state. const TargetInfo &Target; typedef std::pair ComplexPairTy; LoopInfoStack LoopStack; CGBuilderTy Builder; /// \brief CGBuilder insert helper. This function is called after an /// instruction is created using Builder. void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name, llvm::BasicBlock *BB, llvm::BasicBlock::iterator InsertPt) const; /// CurFuncDecl - Holds the Decl for the current outermost /// non-closure context. const Decl *CurFuncDecl; /// CurCodeDecl - This is the inner-most code context, which includes blocks. const Decl *CurCodeDecl; const CGFunctionInfo *CurFnInfo; QualType FnRetTy; llvm::Function *CurFn; /// CurGD - The GlobalDecl for the current function being compiled. GlobalDecl CurGD; /// PrologueCleanupDepth - The cleanup depth enclosing all the /// cleanups associated with the parameters. EHScopeStack::stable_iterator PrologueCleanupDepth; /// ReturnBlock - Unified return block. JumpDest ReturnBlock; /// ReturnValue - The temporary alloca to hold the return /// value. This is invalid iff the function has no return value. Address ReturnValue; /// AllocaInsertPoint - This is an instruction in the entry block before which /// we prefer to insert allocas. llvm::AssertingVH AllocaInsertPt; /// \brief API for captured statement code generation. class CGCapturedStmtInfo { public: explicit CGCapturedStmtInfo(CapturedRegionKind K = CR_Default) : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) {} explicit CGCapturedStmtInfo(const CapturedStmt &S, CapturedRegionKind K = CR_Default) : Kind(K), ThisValue(nullptr), CXXThisFieldDecl(nullptr) { RecordDecl::field_iterator Field = S.getCapturedRecordDecl()->field_begin(); for (CapturedStmt::const_capture_iterator I = S.capture_begin(), E = S.capture_end(); I != E; ++I, ++Field) { if (I->capturesThis()) CXXThisFieldDecl = *Field; else if (I->capturesVariable()) CaptureFields[I->getCapturedVar()] = *Field; else if (I->capturesVariableByCopy()) CaptureFields[I->getCapturedVar()] = *Field; } } virtual ~CGCapturedStmtInfo(); CapturedRegionKind getKind() const { return Kind; } virtual void setContextValue(llvm::Value *V) { ThisValue = V; } // \brief Retrieve the value of the context parameter. virtual llvm::Value *getContextValue() const { return ThisValue; } /// \brief Lookup the captured field decl for a variable. virtual const FieldDecl *lookup(const VarDecl *VD) const { return CaptureFields.lookup(VD); } bool isCXXThisExprCaptured() const { return getThisFieldDecl() != nullptr; } virtual FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; } static bool classof(const CGCapturedStmtInfo *) { return true; } /// \brief Emit the captured statement body. virtual void EmitBody(CodeGenFunction &CGF, const Stmt *S) { CGF.incrementProfileCounter(S); CGF.EmitStmt(S); } /// \brief Get the name of the capture helper. virtual StringRef getHelperName() const { return "__captured_stmt"; } private: /// \brief The kind of captured statement being generated. CapturedRegionKind Kind; /// \brief Keep the map between VarDecl and FieldDecl. llvm::SmallDenseMap CaptureFields; /// \brief The base address of the captured record, passed in as the first /// argument of the parallel region function. llvm::Value *ThisValue; /// \brief Captured 'this' type. FieldDecl *CXXThisFieldDecl; }; CGCapturedStmtInfo *CapturedStmtInfo; /// \brief RAII for correct setting/restoring of CapturedStmtInfo. class CGCapturedStmtRAII { private: CodeGenFunction &CGF; CGCapturedStmtInfo *PrevCapturedStmtInfo; public: CGCapturedStmtRAII(CodeGenFunction &CGF, CGCapturedStmtInfo *NewCapturedStmtInfo) : CGF(CGF), PrevCapturedStmtInfo(CGF.CapturedStmtInfo) { CGF.CapturedStmtInfo = NewCapturedStmtInfo; } ~CGCapturedStmtRAII() { CGF.CapturedStmtInfo = PrevCapturedStmtInfo; } }; /// \brief Sanitizers enabled for this function. SanitizerSet SanOpts; /// \brief True if CodeGen currently emits code implementing sanitizer checks. bool IsSanitizerScope; /// \brief RAII object to set/unset CodeGenFunction::IsSanitizerScope. class SanitizerScope { CodeGenFunction *CGF; public: SanitizerScope(CodeGenFunction *CGF); ~SanitizerScope(); }; /// In C++, whether we are code generating a thunk. This controls whether we /// should emit cleanups. bool CurFuncIsThunk; /// In ARC, whether we should autorelease the return value. bool AutoreleaseResult; /// Whether we processed a Microsoft-style asm block during CodeGen. These can /// potentially set the return value. bool SawAsmBlock; const FunctionDecl *CurSEHParent = nullptr; /// True if the current function is an outlined SEH helper. This can be a /// finally block or filter expression. bool IsOutlinedSEHHelper; const CodeGen::CGBlockInfo *BlockInfo; llvm::Value *BlockPointer; llvm::DenseMap LambdaCaptureFields; FieldDecl *LambdaThisCaptureField; /// \brief A mapping from NRVO variables to the flags used to indicate /// when the NRVO has been applied to this variable. llvm::DenseMap NRVOFlags; EHScopeStack EHStack; llvm::SmallVector LifetimeExtendedCleanupStack; llvm::SmallVector SEHTryEpilogueStack; llvm::Instruction *CurrentFuncletPad = nullptr; class CallLifetimeEnd final : public EHScopeStack::Cleanup { llvm::Value *Addr; llvm::Value *Size; public: CallLifetimeEnd(Address addr, llvm::Value *size) : Addr(addr.getPointer()), Size(size) {} void Emit(CodeGenFunction &CGF, Flags flags) override { CGF.EmitLifetimeEnd(Size, Addr); } }; /// Header for data within LifetimeExtendedCleanupStack. struct LifetimeExtendedCleanupHeader { /// The size of the following cleanup object. unsigned Size; /// The kind of cleanup to push: a value from the CleanupKind enumeration. CleanupKind Kind; size_t getSize() const { return Size; } CleanupKind getKind() const { return Kind; } }; /// i32s containing the indexes of the cleanup destinations. llvm::AllocaInst *NormalCleanupDest; unsigned NextCleanupDestIndex; /// FirstBlockInfo - The head of a singly-linked-list of block layouts. CGBlockInfo *FirstBlockInfo; /// EHResumeBlock - Unified block containing a call to llvm.eh.resume. llvm::BasicBlock *EHResumeBlock; /// The exception slot. All landing pads write the current exception pointer /// into this alloca. llvm::Value *ExceptionSlot; /// The selector slot. Under the MandatoryCleanup model, all landing pads /// write the current selector value into this alloca. llvm::AllocaInst *EHSelectorSlot; /// A stack of exception code slots. Entering an __except block pushes a slot /// on the stack and leaving pops one. The __exception_code() intrinsic loads /// a value from the top of the stack. SmallVector SEHCodeSlotStack; /// Value returned by __exception_info intrinsic. llvm::Value *SEHInfo = nullptr; /// Emits a landing pad for the current EH stack. llvm::BasicBlock *EmitLandingPad(); llvm::BasicBlock *getInvokeDestImpl(); template typename DominatingValue::saved_type saveValueInCond(T value) { return DominatingValue::save(*this, value); } public: /// ObjCEHValueStack - Stack of Objective-C exception values, used for /// rethrows. SmallVector ObjCEHValueStack; /// A class controlling the emission of a finally block. class FinallyInfo { /// Where the catchall's edge through the cleanup should go. JumpDest RethrowDest; /// A function to call to enter the catch. llvm::Constant *BeginCatchFn; /// An i1 variable indicating whether or not the @finally is /// running for an exception. llvm::AllocaInst *ForEHVar; /// An i8* variable into which the exception pointer to rethrow /// has been saved. llvm::AllocaInst *SavedExnVar; public: void enter(CodeGenFunction &CGF, const Stmt *Finally, llvm::Constant *beginCatchFn, llvm::Constant *endCatchFn, llvm::Constant *rethrowFn); void exit(CodeGenFunction &CGF); }; /// Returns true inside SEH __try blocks. bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); } /// Returns true while emitting a cleanuppad. bool isCleanupPadScope() const { return CurrentFuncletPad && isa(CurrentFuncletPad); } /// pushFullExprCleanup - Push a cleanup to be run at the end of the /// current full-expression. Safe against the possibility that /// we're currently inside a conditionally-evaluated expression. template void pushFullExprCleanup(CleanupKind kind, As... A) { // If we're not in a conditional branch, or if none of the // arguments requires saving, then use the unconditional cleanup. if (!isInConditionalBranch()) return EHStack.pushCleanup(kind, A...); // Stash values in a tuple so we can guarantee the order of saves. typedef std::tuple::saved_type...> SavedTuple; SavedTuple Saved{saveValueInCond(A)...}; typedef EHScopeStack::ConditionalCleanup CleanupType; EHStack.pushCleanupTuple(kind, Saved); initFullExprCleanup(); } /// \brief Queue a cleanup to be pushed after finishing the current /// full-expression. template void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) { assert(!isInConditionalBranch() && "can't defer conditional cleanup"); LifetimeExtendedCleanupHeader Header = { sizeof(T), Kind }; size_t OldSize = LifetimeExtendedCleanupStack.size(); LifetimeExtendedCleanupStack.resize( LifetimeExtendedCleanupStack.size() + sizeof(Header) + Header.Size); static_assert(sizeof(Header) % llvm::AlignOf::Alignment == 0, "Cleanup will be allocated on misaligned address"); char *Buffer = &LifetimeExtendedCleanupStack[OldSize]; new (Buffer) LifetimeExtendedCleanupHeader(Header); new (Buffer + sizeof(Header)) T(A...); } /// Set up the last cleaup that was pushed as a conditional /// full-expression cleanup. void initFullExprCleanup(); /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the /// given address. Does nothing if T is not a C++ class type with a /// non-trivial destructor. void PushDestructorCleanup(QualType T, Address Addr); /// PushDestructorCleanup - Push a cleanup to call the /// complete-object variant of the given destructor on the object at /// the given address. void PushDestructorCleanup(const CXXDestructorDecl *Dtor, Address Addr); /// PopCleanupBlock - Will pop the cleanup entry on the stack and /// process all branch fixups. void PopCleanupBlock(bool FallThroughIsBranchThrough = false); /// DeactivateCleanupBlock - Deactivates the given cleanup block. /// The block cannot be reactivated. Pops it if it's the top of the /// stack. /// /// \param DominatingIP - An instruction which is known to /// dominate the current IP (if set) and which lies along /// all paths of execution between the current IP and the /// the point at which the cleanup comes into scope. void DeactivateCleanupBlock(EHScopeStack::stable_iterator Cleanup, llvm::Instruction *DominatingIP); /// ActivateCleanupBlock - Activates an initially-inactive cleanup. /// Cannot be used to resurrect a deactivated cleanup. /// /// \param DominatingIP - An instruction which is known to /// dominate the current IP (if set) and which lies along /// all paths of execution between the current IP and the /// the point at which the cleanup comes into scope. void ActivateCleanupBlock(EHScopeStack::stable_iterator Cleanup, llvm::Instruction *DominatingIP); /// \brief Enters a new scope for capturing cleanups, all of which /// will be executed once the scope is exited. class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth; size_t LifetimeExtendedCleanupStackSize; bool OldDidCallStackSave; protected: bool PerformCleanup; private: RunCleanupsScope(const RunCleanupsScope &) = delete; void operator=(const RunCleanupsScope &) = delete; protected: CodeGenFunction& CGF; public: /// \brief Enter a new cleanup scope. explicit RunCleanupsScope(CodeGenFunction &CGF) : PerformCleanup(true), CGF(CGF) { CleanupStackDepth = CGF.EHStack.stable_begin(); LifetimeExtendedCleanupStackSize = CGF.LifetimeExtendedCleanupStack.size(); OldDidCallStackSave = CGF.DidCallStackSave; CGF.DidCallStackSave = false; } /// \brief Exit this cleanup scope, emitting any accumulated /// cleanups. ~RunCleanupsScope() { if (PerformCleanup) { CGF.DidCallStackSave = OldDidCallStackSave; CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize); } } /// \brief Determine whether this scope requires any cleanups. bool requiresCleanups() const { return CGF.EHStack.stable_begin() != CleanupStackDepth; } /// \brief Force the emission of cleanups now, instead of waiting /// until this object is destroyed. void ForceCleanup() { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize); PerformCleanup = false; } }; class LexicalScope : public RunCleanupsScope { SourceRange Range; SmallVector Labels; LexicalScope *ParentScope; LexicalScope(const LexicalScope &) = delete; void operator=(const LexicalScope &) = delete; public: /// \brief Enter a new cleanup scope. explicit LexicalScope(CodeGenFunction &CGF, SourceRange Range) : RunCleanupsScope(CGF), Range(Range), ParentScope(CGF.CurLexicalScope) { CGF.CurLexicalScope = this; if (CGDebugInfo *DI = CGF.getDebugInfo()) DI->EmitLexicalBlockStart(CGF.Builder, Range.getBegin()); } void addLabel(const LabelDecl *label) { assert(PerformCleanup && "adding label to dead scope?"); Labels.push_back(label); } /// \brief Exit this cleanup scope, emitting any accumulated /// cleanups. ~LexicalScope() { if (CGDebugInfo *DI = CGF.getDebugInfo()) DI->EmitLexicalBlockEnd(CGF.Builder, Range.getEnd()); // If we should perform a cleanup, force them now. Note that // this ends the cleanup scope before rescoping any labels. if (PerformCleanup) { ApplyDebugLocation DL(CGF, Range.getEnd()); ForceCleanup(); } } /// \brief Force the emission of cleanups now, instead of waiting /// until this object is destroyed. void ForceCleanup() { CGF.CurLexicalScope = ParentScope; RunCleanupsScope::ForceCleanup(); if (!Labels.empty()) rescopeLabels(); } void rescopeLabels(); }; typedef llvm::DenseMap DeclMapTy; /// \brief The scope used to remap some variables as private in the OpenMP /// loop body (or other captured region emitted without outlining), and to /// restore old vars back on exit. class OMPPrivateScope : public RunCleanupsScope { DeclMapTy SavedLocals; DeclMapTy SavedPrivates; private: OMPPrivateScope(const OMPPrivateScope &) = delete; void operator=(const OMPPrivateScope &) = delete; public: /// \brief Enter a new OpenMP private scope. explicit OMPPrivateScope(CodeGenFunction &CGF) : RunCleanupsScope(CGF) {} /// \brief Registers \a LocalVD variable as a private and apply \a /// PrivateGen function for it to generate corresponding private variable. /// \a PrivateGen returns an address of the generated private variable. /// \return true if the variable is registered as private, false if it has /// been privatized already. bool addPrivate(const VarDecl *LocalVD, llvm::function_ref PrivateGen) { assert(PerformCleanup && "adding private to dead scope"); // Only save it once. if (SavedLocals.count(LocalVD)) return false; // Copy the existing local entry to SavedLocals. auto it = CGF.LocalDeclMap.find(LocalVD); if (it != CGF.LocalDeclMap.end()) { SavedLocals.insert({LocalVD, it->second}); } else { SavedLocals.insert({LocalVD, Address::invalid()}); } // Generate the private entry. Address Addr = PrivateGen(); QualType VarTy = LocalVD->getType(); if (VarTy->isReferenceType()) { Address Temp = CGF.CreateMemTemp(VarTy); CGF.Builder.CreateStore(Addr.getPointer(), Temp); Addr = Temp; } SavedPrivates.insert({LocalVD, Addr}); return true; } /// \brief Privatizes local variables previously registered as private. /// Registration is separate from the actual privatization to allow /// initializers use values of the original variables, not the private one. /// This is important, for example, if the private variable is a class /// variable initialized by a constructor that references other private /// variables. But at initialization original variables must be used, not /// private copies. /// \return true if at least one variable was privatized, false otherwise. bool Privatize() { copyInto(SavedPrivates, CGF.LocalDeclMap); SavedPrivates.clear(); return !SavedLocals.empty(); } void ForceCleanup() { RunCleanupsScope::ForceCleanup(); copyInto(SavedLocals, CGF.LocalDeclMap); SavedLocals.clear(); } /// \brief Exit scope - all the mapped variables are restored. ~OMPPrivateScope() { if (PerformCleanup) ForceCleanup(); } /// Checks if the global variable is captured in current function. bool isGlobalVarCaptured(const VarDecl *VD) const { return !VD->isLocalVarDeclOrParm() && CGF.LocalDeclMap.count(VD) > 0; } private: /// Copy all the entries in the source map over the corresponding /// entries in the destination, which must exist. static void copyInto(const DeclMapTy &src, DeclMapTy &dest) { for (auto &pair : src) { if (!pair.second.isValid()) { dest.erase(pair.first); continue; } auto it = dest.find(pair.first); if (it != dest.end()) { it->second = pair.second; } else { dest.insert(pair); } } } }; /// \brief Takes the old cleanup stack size and emits the cleanup blocks /// that have been added. void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize); /// \brief Takes the old cleanup stack size and emits the cleanup blocks /// that have been added, then adds all lifetime-extended cleanups from /// the given position to the stack. void PopCleanupBlocks(EHScopeStack::stable_iterator OldCleanupStackSize, size_t OldLifetimeExtendedStackSize); void ResolveBranchFixups(llvm::BasicBlock *Target); /// The given basic block lies in the current EH scope, but may be a /// target of a potentially scope-crossing jump; get a stable handle /// to which we can perform this jump later. JumpDest getJumpDestInCurrentScope(llvm::BasicBlock *Target) { return JumpDest(Target, EHStack.getInnermostNormalCleanup(), NextCleanupDestIndex++); } /// The given basic block lies in the current EH scope, but may be a /// target of a potentially scope-crossing jump; get a stable handle /// to which we can perform this jump later. JumpDest getJumpDestInCurrentScope(StringRef Name = StringRef()) { return getJumpDestInCurrentScope(createBasicBlock(Name)); } /// EmitBranchThroughCleanup - Emit a branch from the current insert /// block through the normal cleanup handling code (if any) and then /// on to \arg Dest. void EmitBranchThroughCleanup(JumpDest Dest); /// isObviouslyBranchWithoutCleanups - Return true if a branch to the /// specified destination obviously has no cleanups to run. 'false' is always /// a conservatively correct answer for this method. bool isObviouslyBranchWithoutCleanups(JumpDest Dest) const; /// popCatchScope - Pops the catch scope at the top of the EHScope /// stack, emitting any required code (other than the catch handlers /// themselves). void popCatchScope(); llvm::BasicBlock *getEHResumeBlock(bool isCleanup); llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope); llvm::BasicBlock *getMSVCDispatchBlock(EHScopeStack::stable_iterator scope); /// An object to manage conditionally-evaluated expressions. class ConditionalEvaluation { llvm::BasicBlock *StartBB; public: ConditionalEvaluation(CodeGenFunction &CGF) : StartBB(CGF.Builder.GetInsertBlock()) {} void begin(CodeGenFunction &CGF) { assert(CGF.OutermostConditional != this); if (!CGF.OutermostConditional) CGF.OutermostConditional = this; } void end(CodeGenFunction &CGF) { assert(CGF.OutermostConditional != nullptr); if (CGF.OutermostConditional == this) CGF.OutermostConditional = nullptr; } /// Returns a block which will be executed prior to each /// evaluation of the conditional code. llvm::BasicBlock *getStartingBlock() const { return StartBB; } }; /// isInConditionalBranch - Return true if we're currently emitting /// one branch or the other of a conditional expression. bool isInConditionalBranch() const { return OutermostConditional != nullptr; } void setBeforeOutermostConditional(llvm::Value *value, Address addr) { assert(isInConditionalBranch()); llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back()); store->setAlignment(addr.getAlignment().getQuantity()); } /// An RAII object to record that we're evaluating a statement /// expression. class StmtExprEvaluation { CodeGenFunction &CGF; /// We have to save the outermost conditional: cleanups in a /// statement expression aren't conditional just because the /// StmtExpr is. ConditionalEvaluation *SavedOutermostConditional; public: StmtExprEvaluation(CodeGenFunction &CGF) : CGF(CGF), SavedOutermostConditional(CGF.OutermostConditional) { CGF.OutermostConditional = nullptr; } ~StmtExprEvaluation() { CGF.OutermostConditional = SavedOutermostConditional; CGF.EnsureInsertPoint(); } }; /// An object which temporarily prevents a value from being /// destroyed by aggressive peephole optimizations that assume that /// all uses of a value have been realized in the IR. class PeepholeProtection { llvm::Instruction *Inst; friend class CodeGenFunction; public: PeepholeProtection() : Inst(nullptr) {} }; /// A non-RAII class containing all the information about a bound /// opaque value. OpaqueValueMapping, below, is a RAII wrapper for /// this which makes individual mappings very simple; using this /// class directly is useful when you have a variable number of /// opaque values or don't want the RAII functionality for some /// reason. class OpaqueValueMappingData { const OpaqueValueExpr *OpaqueValue; bool BoundLValue; CodeGenFunction::PeepholeProtection Protection; OpaqueValueMappingData(const OpaqueValueExpr *ov, bool boundLValue) : OpaqueValue(ov), BoundLValue(boundLValue) {} public: OpaqueValueMappingData() : OpaqueValue(nullptr) {} static bool shouldBindAsLValue(const Expr *expr) { // gl-values should be bound as l-values for obvious reasons. // Records should be bound as l-values because IR generation // always keeps them in memory. Expressions of function type // act exactly like l-values but are formally required to be // r-values in C. return expr->isGLValue() || expr->getType()->isFunctionType() || hasAggregateEvaluationKind(expr->getType()); } static OpaqueValueMappingData bind(CodeGenFunction &CGF, const OpaqueValueExpr *ov, const Expr *e) { if (shouldBindAsLValue(ov)) return bind(CGF, ov, CGF.EmitLValue(e)); return bind(CGF, ov, CGF.EmitAnyExpr(e)); } static OpaqueValueMappingData bind(CodeGenFunction &CGF, const OpaqueValueExpr *ov, const LValue &lv) { assert(shouldBindAsLValue(ov)); CGF.OpaqueLValues.insert(std::make_pair(ov, lv)); return OpaqueValueMappingData(ov, true); } static OpaqueValueMappingData bind(CodeGenFunction &CGF, const OpaqueValueExpr *ov, const RValue &rv) { assert(!shouldBindAsLValue(ov)); CGF.OpaqueRValues.insert(std::make_pair(ov, rv)); OpaqueValueMappingData data(ov, false); // Work around an extremely aggressive peephole optimization in // EmitScalarConversion which assumes that all other uses of a // value are extant. data.Protection = CGF.protectFromPeepholes(rv); return data; } bool isValid() const { return OpaqueValue != nullptr; } void clear() { OpaqueValue = nullptr; } void unbind(CodeGenFunction &CGF) { assert(OpaqueValue && "no data to unbind!"); if (BoundLValue) { CGF.OpaqueLValues.erase(OpaqueValue); } else { CGF.OpaqueRValues.erase(OpaqueValue); CGF.unprotectFromPeepholes(Protection); } } }; /// An RAII object to set (and then clear) a mapping for an OpaqueValueExpr. class OpaqueValueMapping { CodeGenFunction &CGF; OpaqueValueMappingData Data; public: static bool shouldBindAsLValue(const Expr *expr) { return OpaqueValueMappingData::shouldBindAsLValue(expr); } /// Build the opaque value mapping for the given conditional /// operator if it's the GNU ?: extension. This is a common /// enough pattern that the convenience operator is really /// helpful. /// OpaqueValueMapping(CodeGenFunction &CGF, const AbstractConditionalOperator *op) : CGF(CGF) { if (isa(op)) // Leave Data empty. return; const BinaryConditionalOperator *e = cast(op); Data = OpaqueValueMappingData::bind(CGF, e->getOpaqueValue(), e->getCommon()); } OpaqueValueMapping(CodeGenFunction &CGF, const OpaqueValueExpr *opaqueValue, LValue lvalue) : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, lvalue)) { } OpaqueValueMapping(CodeGenFunction &CGF, const OpaqueValueExpr *opaqueValue, RValue rvalue) : CGF(CGF), Data(OpaqueValueMappingData::bind(CGF, opaqueValue, rvalue)) { } void pop() { Data.unbind(CGF); Data.clear(); } ~OpaqueValueMapping() { if (Data.isValid()) Data.unbind(CGF); } }; private: CGDebugInfo *DebugInfo; bool DisableDebugInfo; /// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid /// calling llvm.stacksave for multiple VLAs in the same scope. bool DidCallStackSave; /// IndirectBranch - The first time an indirect goto is seen we create a block /// with an indirect branch. Every time we see the address of a label taken, /// we add the label to the indirect goto. Every subsequent indirect goto is /// codegen'd as a jump to the IndirectBranch's basic block. llvm::IndirectBrInst *IndirectBranch; /// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C /// decls. DeclMapTy LocalDeclMap; /// SizeArguments - If a ParmVarDecl had the pass_object_size attribute, this /// will contain a mapping from said ParmVarDecl to its implicit "object_size" /// parameter. llvm::SmallDenseMap SizeArguments; /// Track escaped local variables with auto storage. Used during SEH /// outlining to produce a call to llvm.localescape. llvm::DenseMap EscapedLocals; /// LabelMap - This keeps track of the LLVM basic block for each C label. llvm::DenseMap LabelMap; // BreakContinueStack - This keeps track of where break and continue // statements should jump to. struct BreakContinue { BreakContinue(JumpDest Break, JumpDest Continue) : BreakBlock(Break), ContinueBlock(Continue) {} JumpDest BreakBlock; JumpDest ContinueBlock; }; SmallVector BreakContinueStack; - /// Data for exit block for proper support of OpenMP cancellation constructs. - struct OMPCancel { - JumpDest ExitBlock; - llvm::function_ref CodeGen; - OMPCancel() : CodeGen([](CodeGenFunction &CGF) {}) {} + /// Handles cancellation exit points in OpenMP-related constructs. + class OpenMPCancelExitStack { + /// Tracks cancellation exit point and join point for cancel-related exit + /// and normal exit. + struct CancelExit { + CancelExit() = default; + CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock, + JumpDest ContBlock) + : Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {} + OpenMPDirectiveKind Kind = OMPD_unknown; + /// true if the exit block has been emitted already by the special + /// emitExit() call, false if the default codegen is used. + bool HasBeenEmitted = false; + JumpDest ExitBlock; + JumpDest ContBlock; + }; + + SmallVector Stack; + + public: + OpenMPCancelExitStack() : Stack(1) {} + ~OpenMPCancelExitStack() = default; + /// Fetches the exit block for the current OpenMP construct. + JumpDest getExitBlock() const { return Stack.back().ExitBlock; } + /// Emits exit block with special codegen procedure specific for the related + /// OpenMP construct + emits code for normal construct cleanup. + void emitExit(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, + const llvm::function_ref &CodeGen) { + if (Stack.back().Kind == Kind && getExitBlock().isValid()) { + assert(CGF.getOMPCancelDestination(Kind).isValid()); + assert(CGF.HaveInsertPoint()); + assert(!Stack.back().HasBeenEmitted); + auto IP = CGF.Builder.saveAndClearIP(); + CGF.EmitBlock(Stack.back().ExitBlock.getBlock()); + CodeGen(CGF); + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + CGF.Builder.restoreIP(IP); + Stack.back().HasBeenEmitted = true; + } + CodeGen(CGF); + } + /// Enter the cancel supporting \a Kind construct. + /// \param Kind OpenMP directive that supports cancel constructs. + /// \param HasCancel true, if the construct has inner cancel directive, + /// false otherwise. + void enter(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, bool HasCancel) { + Stack.push_back({Kind, + HasCancel ? CGF.getJumpDestInCurrentScope("cancel.exit") + : JumpDest(), + HasCancel ? CGF.getJumpDestInCurrentScope("cancel.cont") + : JumpDest()}); + } + /// Emits default exit point for the cancel construct (if the special one + /// has not be used) + join point for cancel/normal exits. + void exit(CodeGenFunction &CGF) { + if (getExitBlock().isValid()) { + assert(CGF.getOMPCancelDestination(Stack.back().Kind).isValid()); + bool HaveIP = CGF.HaveInsertPoint(); + if (!Stack.back().HasBeenEmitted) { + if (HaveIP) + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + CGF.EmitBlock(Stack.back().ExitBlock.getBlock()); + CGF.EmitBranchThroughCleanup(Stack.back().ContBlock); + } + CGF.EmitBlock(Stack.back().ContBlock.getBlock()); + if (!HaveIP) { + CGF.Builder.CreateUnreachable(); + CGF.Builder.ClearInsertionPoint(); + } + } + Stack.pop_back(); + } }; - SmallVector OMPCancelStack; + OpenMPCancelExitStack OMPCancelStack; /// Controls insertion of cancellation exit blocks in worksharing constructs. class OMPCancelStackRAII { CodeGenFunction &CGF; public: - OMPCancelStackRAII(CodeGenFunction &CGF) : CGF(CGF) { - CGF.OMPCancelStack.push_back({}); - } - ~OMPCancelStackRAII() { - if (CGF.HaveInsertPoint() && - CGF.OMPCancelStack.back().ExitBlock.isValid()) { - auto CJD = CGF.getJumpDestInCurrentScope("cancel.cont"); - CGF.EmitBranchThroughCleanup(CJD); - CGF.EmitBlock(CGF.OMPCancelStack.back().ExitBlock.getBlock()); - CGF.OMPCancelStack.back().CodeGen(CGF); - CGF.EmitBranchThroughCleanup(CJD); - CGF.EmitBlock(CJD.getBlock()); - } + OMPCancelStackRAII(CodeGenFunction &CGF, OpenMPDirectiveKind Kind, + bool HasCancel) + : CGF(CGF) { + CGF.OMPCancelStack.enter(CGF, Kind, HasCancel); } + ~OMPCancelStackRAII() { CGF.OMPCancelStack.exit(CGF); } }; CodeGenPGO PGO; /// Calculate branch weights appropriate for PGO data llvm::MDNode *createProfileWeights(uint64_t TrueCount, uint64_t FalseCount); llvm::MDNode *createProfileWeights(ArrayRef Weights); llvm::MDNode *createProfileWeightsForLoop(const Stmt *Cond, uint64_t LoopCount); public: /// Increment the profiler's counter for the given statement. void incrementProfileCounter(const Stmt *S) { if (CGM.getCodeGenOpts().hasProfileClangInstr()) PGO.emitCounterIncrement(Builder, S); PGO.setCurrentStmt(S); } /// Get the profiler's count for the given statement. uint64_t getProfileCount(const Stmt *S) { Optional Count = PGO.getStmtCount(S); if (!Count.hasValue()) return 0; return *Count; } /// Set the profiler's current count. void setCurrentProfileCount(uint64_t Count) { PGO.setCurrentRegionCount(Count); } /// Get the profiler's current count. This is generally the count for the most /// recently incremented counter. uint64_t getCurrentProfileCount() { return PGO.getCurrentRegionCount(); } private: /// SwitchInsn - This is nearest current switch instruction. It is null if /// current context is not in a switch. llvm::SwitchInst *SwitchInsn; /// The branch weights of SwitchInsn when doing instrumentation based PGO. SmallVector *SwitchWeights; /// CaseRangeBlock - This block holds if condition check for last case /// statement range in current switch instruction. llvm::BasicBlock *CaseRangeBlock; /// OpaqueLValues - Keeps track of the current set of opaque value /// expressions. llvm::DenseMap OpaqueLValues; llvm::DenseMap OpaqueRValues; // VLASizeMap - This keeps track of the associated size for each VLA type. // We track this by the size expression rather than the type itself because // in certain situations, like a const qualifier applied to an VLA typedef, // multiple VLA types can share the same size expression. // FIXME: Maybe this could be a stack of maps that is pushed/popped as we // enter/leave scopes. llvm::DenseMap VLASizeMap; /// A block containing a single 'unreachable' instruction. Created /// lazily by getUnreachableBlock(). llvm::BasicBlock *UnreachableBlock; /// Counts of the number return expressions in the function. unsigned NumReturnExprs; /// Count the number of simple (constant) return expressions in the function. unsigned NumSimpleReturnExprs; /// The last regular (non-return) debug location (breakpoint) in the function. SourceLocation LastStopPoint; public: /// A scope within which we are constructing the fields of an object which /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use /// if we need to evaluate a CXXDefaultInitExpr within the evaluation. class FieldConstructionScope { public: FieldConstructionScope(CodeGenFunction &CGF, Address This) : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) { CGF.CXXDefaultInitExprThis = This; } ~FieldConstructionScope() { CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis; } private: CodeGenFunction &CGF; Address OldCXXDefaultInitExprThis; }; /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this' /// is overridden to be the object under construction. class CXXDefaultInitExprScope { public: CXXDefaultInitExprScope(CodeGenFunction &CGF) : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue), OldCXXThisAlignment(CGF.CXXThisAlignment) { CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer(); CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment(); } ~CXXDefaultInitExprScope() { CGF.CXXThisValue = OldCXXThisValue; CGF.CXXThisAlignment = OldCXXThisAlignment; } public: CodeGenFunction &CGF; llvm::Value *OldCXXThisValue; CharUnits OldCXXThisAlignment; }; class InlinedInheritingConstructorScope { public: InlinedInheritingConstructorScope(CodeGenFunction &CGF, GlobalDecl GD) : CGF(CGF), OldCurGD(CGF.CurGD), OldCurFuncDecl(CGF.CurFuncDecl), OldCurCodeDecl(CGF.CurCodeDecl), OldCXXABIThisDecl(CGF.CXXABIThisDecl), OldCXXABIThisValue(CGF.CXXABIThisValue), OldCXXThisValue(CGF.CXXThisValue), OldCXXABIThisAlignment(CGF.CXXABIThisAlignment), OldCXXThisAlignment(CGF.CXXThisAlignment), OldReturnValue(CGF.ReturnValue), OldFnRetTy(CGF.FnRetTy), OldCXXInheritedCtorInitExprArgs( std::move(CGF.CXXInheritedCtorInitExprArgs)) { CGF.CurGD = GD; CGF.CurFuncDecl = CGF.CurCodeDecl = cast(GD.getDecl()); CGF.CXXABIThisDecl = nullptr; CGF.CXXABIThisValue = nullptr; CGF.CXXThisValue = nullptr; CGF.CXXABIThisAlignment = CharUnits(); CGF.CXXThisAlignment = CharUnits(); CGF.ReturnValue = Address::invalid(); CGF.FnRetTy = QualType(); CGF.CXXInheritedCtorInitExprArgs.clear(); } ~InlinedInheritingConstructorScope() { CGF.CurGD = OldCurGD; CGF.CurFuncDecl = OldCurFuncDecl; CGF.CurCodeDecl = OldCurCodeDecl; CGF.CXXABIThisDecl = OldCXXABIThisDecl; CGF.CXXABIThisValue = OldCXXABIThisValue; CGF.CXXThisValue = OldCXXThisValue; CGF.CXXABIThisAlignment = OldCXXABIThisAlignment; CGF.CXXThisAlignment = OldCXXThisAlignment; CGF.ReturnValue = OldReturnValue; CGF.FnRetTy = OldFnRetTy; CGF.CXXInheritedCtorInitExprArgs = std::move(OldCXXInheritedCtorInitExprArgs); } private: CodeGenFunction &CGF; GlobalDecl OldCurGD; const Decl *OldCurFuncDecl; const Decl *OldCurCodeDecl; ImplicitParamDecl *OldCXXABIThisDecl; llvm::Value *OldCXXABIThisValue; llvm::Value *OldCXXThisValue; CharUnits OldCXXABIThisAlignment; CharUnits OldCXXThisAlignment; Address OldReturnValue; QualType OldFnRetTy; CallArgList OldCXXInheritedCtorInitExprArgs; }; private: /// CXXThisDecl - When generating code for a C++ member function, /// this will hold the implicit 'this' declaration. ImplicitParamDecl *CXXABIThisDecl; llvm::Value *CXXABIThisValue; llvm::Value *CXXThisValue; CharUnits CXXABIThisAlignment; CharUnits CXXThisAlignment; /// The value of 'this' to use when evaluating CXXDefaultInitExprs within /// this expression. Address CXXDefaultInitExprThis = Address::invalid(); /// The values of function arguments to use when evaluating /// CXXInheritedCtorInitExprs within this context. CallArgList CXXInheritedCtorInitExprArgs; /// CXXStructorImplicitParamDecl - When generating code for a constructor or /// destructor, this will hold the implicit argument (e.g. VTT). ImplicitParamDecl *CXXStructorImplicitParamDecl; llvm::Value *CXXStructorImplicitParamValue; /// OutermostConditional - Points to the outermost active /// conditional control. This is used so that we know if a /// temporary should be destroyed conditionally. ConditionalEvaluation *OutermostConditional; /// The current lexical scope. LexicalScope *CurLexicalScope; /// The current source location that should be used for exception /// handling code. SourceLocation CurEHLocation; /// BlockByrefInfos - For each __block variable, contains /// information about the layout of the variable. llvm::DenseMap BlockByrefInfos; llvm::BasicBlock *TerminateLandingPad; llvm::BasicBlock *TerminateHandler; llvm::BasicBlock *TrapBB; /// Add a kernel metadata node to the named metadata node 'opencl.kernels'. /// In the kernel metadata node, reference the kernel function and metadata /// nodes for its optional attribute qualifiers (OpenCL 1.1 6.7.2): /// - A node for the vec_type_hint() qualifier contains string /// "vec_type_hint", an undefined value of the data type, /// and a Boolean that is true if the is integer and signed. /// - A node for the work_group_size_hint(X,Y,Z) qualifier contains string /// "work_group_size_hint", and three 32-bit integers X, Y and Z. /// - A node for the reqd_work_group_size(X,Y,Z) qualifier contains string /// "reqd_work_group_size", and three 32-bit integers X, Y and Z. void EmitOpenCLKernelMetadata(const FunctionDecl *FD, llvm::Function *Fn); public: CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext=false); ~CodeGenFunction(); CodeGenTypes &getTypes() const { return CGM.getTypes(); } ASTContext &getContext() const { return CGM.getContext(); } CGDebugInfo *getDebugInfo() { if (DisableDebugInfo) return nullptr; return DebugInfo; } void disableDebugInfo() { DisableDebugInfo = true; } void enableDebugInfo() { DisableDebugInfo = false; } bool shouldUseFusedARCCalls() { return CGM.getCodeGenOpts().OptimizationLevel == 0; } const LangOptions &getLangOpts() const { return CGM.getLangOpts(); } /// Returns a pointer to the function's exception object and selector slot, /// which is assigned in every landing pad. Address getExceptionSlot(); Address getEHSelectorSlot(); /// Returns the contents of the function's exception object and selector /// slots. llvm::Value *getExceptionFromSlot(); llvm::Value *getSelectorFromSlot(); Address getNormalCleanupDestSlot(); llvm::BasicBlock *getUnreachableBlock() { if (!UnreachableBlock) { UnreachableBlock = createBasicBlock("unreachable"); new llvm::UnreachableInst(getLLVMContext(), UnreachableBlock); } return UnreachableBlock; } llvm::BasicBlock *getInvokeDest() { if (!EHStack.requiresLandingPad()) return nullptr; return getInvokeDestImpl(); } bool currentFunctionUsesSEHTry() const { return CurSEHParent != nullptr; } const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } //===--------------------------------------------------------------------===// // Cleanups //===--------------------------------------------------------------------===// typedef void Destroyer(CodeGenFunction &CGF, Address addr, QualType ty); void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, Address arrayEndPointer, QualType elementType, CharUnits elementAlignment, Destroyer *destroyer); void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin, llvm::Value *arrayEnd, QualType elementType, CharUnits elementAlignment, Destroyer *destroyer); void pushDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type); void pushEHDestroy(QualType::DestructionKind dtorKind, Address addr, QualType type); void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); void pushCallObjectDeleteCleanup(const FunctionDecl *OperatorDelete, llvm::Value *CompletePtr, QualType ElementType); void pushStackRestore(CleanupKind kind, Address SPMem); void emitDestroy(Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); llvm::Function *generateDestroyHelper(Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray, const VarDecl *VD); void emitArrayDestroy(llvm::Value *begin, llvm::Value *end, QualType elementType, CharUnits elementAlign, Destroyer *destroyer, bool checkZeroLength, bool useEHCleanup); Destroyer *getDestroyer(QualType::DestructionKind destructionKind); /// Determines whether an EH cleanup is required to destroy a type /// with the given destruction kind. bool needsEHCleanup(QualType::DestructionKind kind) { switch (kind) { case QualType::DK_none: return false; case QualType::DK_cxx_destructor: case QualType::DK_objc_weak_lifetime: return getLangOpts().Exceptions; case QualType::DK_objc_strong_lifetime: return getLangOpts().Exceptions && CGM.getCodeGenOpts().ObjCAutoRefCountExceptions; } llvm_unreachable("bad destruction kind"); } CleanupKind getCleanupKind(QualType::DestructionKind kind) { return (needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup); } //===--------------------------------------------------------------------===// // Objective-C //===--------------------------------------------------------------------===// void GenerateObjCMethod(const ObjCMethodDecl *OMD); void StartObjCMethod(const ObjCMethodDecl *MD, const ObjCContainerDecl *CD); /// GenerateObjCGetter - Synthesize an Objective-C property getter function. void GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); void generateObjCGetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, const ObjCMethodDecl *GetterMothodDecl, llvm::Constant *AtomicHelperFn); void GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, ObjCMethodDecl *MD, bool ctor); /// GenerateObjCSetter - Synthesize an Objective-C property setter function /// for the given property. void GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID); void generateObjCSetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, llvm::Constant *AtomicHelperFn); //===--------------------------------------------------------------------===// // Block Bits //===--------------------------------------------------------------------===// llvm::Value *EmitBlockLiteral(const BlockExpr *); llvm::Value *EmitBlockLiteral(const CGBlockInfo &Info); static void destroyBlockInfos(CGBlockInfo *info); llvm::Function *GenerateBlockFunction(GlobalDecl GD, const CGBlockInfo &Info, const DeclMapTy &ldm, bool IsLambdaConversionToBlock); llvm::Constant *GenerateCopyHelperFunction(const CGBlockInfo &blockInfo); llvm::Constant *GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo); llvm::Constant *GenerateObjCAtomicSetterCopyHelperFunction( const ObjCPropertyImplDecl *PID); llvm::Constant *GenerateObjCAtomicGetterCopyHelperFunction( const ObjCPropertyImplDecl *PID); llvm::Value *EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty); void BuildBlockRelease(llvm::Value *DeclPtr, BlockFieldFlags flags); class AutoVarEmission; void emitByrefStructureInit(const AutoVarEmission &emission); void enterByrefCleanup(const AutoVarEmission &emission); void setBlockContextParameter(const ImplicitParamDecl *D, unsigned argNum, llvm::Value *ptr); Address LoadBlockStruct(); Address GetAddrOfBlockDecl(const VarDecl *var, bool ByRef); /// BuildBlockByrefAddress - Computes the location of the /// data in a variable which is declared as __block. Address emitBlockByrefAddress(Address baseAddr, const VarDecl *V, bool followForward = true); Address emitBlockByrefAddress(Address baseAddr, const BlockByrefInfo &info, bool followForward, const llvm::Twine &name); const BlockByrefInfo &getBlockByrefInfo(const VarDecl *var); QualType BuildFunctionArgList(GlobalDecl GD, FunctionArgList &Args); void GenerateCode(GlobalDecl GD, llvm::Function *Fn, const CGFunctionInfo &FnInfo); /// \brief Emit code for the start of a function. /// \param Loc The location to be associated with the function. /// \param StartLoc The location of the function body. void StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, SourceLocation Loc = SourceLocation(), SourceLocation StartLoc = SourceLocation()); void EmitConstructorBody(FunctionArgList &Args); void EmitDestructorBody(FunctionArgList &Args); void emitImplicitAssignmentOperatorBody(FunctionArgList &Args); void EmitFunctionBody(FunctionArgList &Args, const Stmt *Body); void EmitBlockWithFallThrough(llvm::BasicBlock *BB, const Stmt *S); void EmitForwardingCallToLambda(const CXXMethodDecl *LambdaCallOperator, CallArgList &CallArgs); void EmitLambdaToBlockPointerBody(FunctionArgList &Args); void EmitLambdaBlockInvokeBody(); void EmitLambdaDelegatingInvokeBody(const CXXMethodDecl *MD); void EmitLambdaStaticInvokeFunction(const CXXMethodDecl *MD); void EmitAsanPrologueOrEpilogue(bool Prologue); /// \brief Emit the unified return block, trying to avoid its emission when /// possible. /// \return The debug location of the user written return statement if the /// return block is is avoided. llvm::DebugLoc EmitReturnBlock(); /// FinishFunction - Complete IR generation of the current function. It is /// legal to call this function even if there is no current insertion point. void FinishFunction(SourceLocation EndLoc=SourceLocation()); void StartThunk(llvm::Function *Fn, GlobalDecl GD, const CGFunctionInfo &FnInfo); void EmitCallAndReturnForThunk(llvm::Value *Callee, const ThunkInfo *Thunk); void FinishThunk(); /// Emit a musttail call for a thunk with a potentially adjusted this pointer. void EmitMustTailThunk(const CXXMethodDecl *MD, llvm::Value *AdjustedThisPtr, llvm::Value *Callee); /// Generate a thunk for the given method. void generateThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); llvm::Function *GenerateVarArgsThunk(llvm::Function *Fn, const CGFunctionInfo &FnInfo, GlobalDecl GD, const ThunkInfo &Thunk); void EmitCtorPrologue(const CXXConstructorDecl *CD, CXXCtorType Type, FunctionArgList &Args); void EmitInitializerForField(FieldDecl *Field, LValue LHS, Expr *Init, ArrayRef ArrayIndexes); /// Struct with all informations about dynamic [sub]class needed to set vptr. struct VPtr { BaseSubobject Base; const CXXRecordDecl *NearestVBase; CharUnits OffsetFromNearestVBase; const CXXRecordDecl *VTableClass; }; /// Initialize the vtable pointer of the given subobject. void InitializeVTablePointer(const VPtr &vptr); typedef llvm::SmallVector VPtrsVector; typedef llvm::SmallPtrSet VisitedVirtualBasesSetTy; VPtrsVector getVTablePointers(const CXXRecordDecl *VTableClass); void getVTablePointers(BaseSubobject Base, const CXXRecordDecl *NearestVBase, CharUnits OffsetFromNearestVBase, bool BaseIsNonVirtualPrimaryBase, const CXXRecordDecl *VTableClass, VisitedVirtualBasesSetTy &VBases, VPtrsVector &vptrs); void InitializeVTablePointers(const CXXRecordDecl *ClassDecl); /// GetVTablePtr - Return the Value of the vtable pointer member pointed /// to by This. llvm::Value *GetVTablePtr(Address This, llvm::Type *VTableTy, const CXXRecordDecl *VTableClass); enum CFITypeCheckKind { CFITCK_VCall, CFITCK_NVCall, CFITCK_DerivedCast, CFITCK_UnrelatedCast, CFITCK_ICall, }; /// \brief Derived is the presumed address of an object of type T after a /// cast. If T is a polymorphic class type, emit a check that the virtual /// table for Derived belongs to a class derived from T. void EmitVTablePtrCheckForCast(QualType T, llvm::Value *Derived, bool MayBeNull, CFITypeCheckKind TCK, SourceLocation Loc); /// EmitVTablePtrCheckForCall - Virtual method MD is being called via VTable. /// If vptr CFI is enabled, emit a check that VTable is valid. void EmitVTablePtrCheckForCall(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc); /// EmitVTablePtrCheck - Emit a check that VTable is a valid virtual table for /// RD using llvm.type.test. void EmitVTablePtrCheck(const CXXRecordDecl *RD, llvm::Value *VTable, CFITypeCheckKind TCK, SourceLocation Loc); /// If whole-program virtual table optimization is enabled, emit an assumption /// that VTable is a member of RD's type identifier. Or, if vptr CFI is /// enabled, emit a check that VTable is a member of RD's type identifier. void EmitTypeMetadataCodeForVCall(const CXXRecordDecl *RD, llvm::Value *VTable, SourceLocation Loc); /// Returns whether we should perform a type checked load when loading a /// virtual function for virtual calls to members of RD. This is generally /// true when both vcall CFI and whole-program-vtables are enabled. bool ShouldEmitVTableTypeCheckedLoad(const CXXRecordDecl *RD); /// Emit a type checked load from the given vtable. llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableByteOffset); /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given /// expr can be devirtualized. bool CanDevirtualizeMemberFunctionCall(const Expr *Base, const CXXMethodDecl *MD); /// EnterDtorCleanups - Enter the cleanups necessary to complete the /// given phase of destruction for a destructor. The end result /// should call destructors on members and base classes in reverse /// order of their construction. void EnterDtorCleanups(const CXXDestructorDecl *Dtor, CXXDtorType Type); /// ShouldInstrumentFunction - Return true if the current function should be /// instrumented with __cyg_profile_func_* calls bool ShouldInstrumentFunction(); /// ShouldXRayInstrument - Return true if the current function should be /// instrumented with XRay nop sleds. bool ShouldXRayInstrumentFunction() const; /// EmitFunctionInstrumentation - Emit LLVM code to call the specified /// instrumentation function with the current function and the call site, if /// function instrumentation is enabled. void EmitFunctionInstrumentation(const char *Fn); /// EmitMCountInstrumentation - Emit call to .mcount. void EmitMCountInstrumentation(); /// EmitFunctionProlog - Emit the target specific LLVM code to load the /// arguments for the given function. This is also responsible for naming the /// LLVM function arguments. void EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Function *Fn, const FunctionArgList &Args); /// EmitFunctionEpilog - Emit the target specific LLVM code to return the /// given temporary. void EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc); /// EmitStartEHSpec - Emit the start of the exception spec. void EmitStartEHSpec(const Decl *D); /// EmitEndEHSpec - Emit the end of the exception spec. void EmitEndEHSpec(const Decl *D); /// getTerminateLandingPad - Return a landing pad that just calls terminate. llvm::BasicBlock *getTerminateLandingPad(); /// getTerminateHandler - Return a handler (not a landing pad, just /// a catch handler) that just calls terminate. This is used when /// a terminate scope encloses a try. llvm::BasicBlock *getTerminateHandler(); llvm::Type *ConvertTypeForMem(QualType T); llvm::Type *ConvertType(QualType T); llvm::Type *ConvertType(const TypeDecl *T) { return ConvertType(getContext().getTypeDeclType(T)); } /// LoadObjCSelf - Load the value of self. This function is only valid while /// generating code for an Objective-C method. llvm::Value *LoadObjCSelf(); /// TypeOfSelfObject - Return type of object that this self represents. QualType TypeOfSelfObject(); /// hasAggregateLLVMType - Return true if the specified AST type will map into /// an aggregate LLVM type or is void. static TypeEvaluationKind getEvaluationKind(QualType T); static bool hasScalarEvaluationKind(QualType T) { return getEvaluationKind(T) == TEK_Scalar; } static bool hasAggregateEvaluationKind(QualType T) { return getEvaluationKind(T) == TEK_Aggregate; } /// createBasicBlock - Create an LLVM basic block. llvm::BasicBlock *createBasicBlock(const Twine &name = "", llvm::Function *parent = nullptr, llvm::BasicBlock *before = nullptr) { #ifdef NDEBUG return llvm::BasicBlock::Create(getLLVMContext(), "", parent, before); #else return llvm::BasicBlock::Create(getLLVMContext(), name, parent, before); #endif } /// getBasicBlockForLabel - Return the LLVM basicblock that the specified /// label maps to. JumpDest getJumpDestForLabel(const LabelDecl *S); /// SimplifyForwardingBlocks - If the given basic block is only a branch to /// another basic block, simplify it. This assumes that no other code could /// potentially reference the basic block. void SimplifyForwardingBlocks(llvm::BasicBlock *BB); /// EmitBlock - Emit the given block \arg BB and set it as the insert point, /// adding a fall-through branch from the current insert block if /// necessary. It is legal to call this function even if there is no current /// insertion point. /// /// IsFinished - If true, indicates that the caller has finished emitting /// branches to the given block and does not expect to emit code into it. This /// means the block can be ignored if it is unreachable. void EmitBlock(llvm::BasicBlock *BB, bool IsFinished=false); /// EmitBlockAfterUses - Emit the given block somewhere hopefully /// near its uses, and leave the insertion point in it. void EmitBlockAfterUses(llvm::BasicBlock *BB); /// EmitBranch - Emit a branch to the specified basic block from the current /// insert block, taking care to avoid creation of branches from dummy /// blocks. It is legal to call this function even if there is no current /// insertion point. /// /// This function clears the current insertion point. The caller should follow /// calls to this function with calls to Emit*Block prior to generation new /// code. void EmitBranch(llvm::BasicBlock *Block); /// HaveInsertPoint - True if an insertion point is defined. If not, this /// indicates that the current code being emitted is unreachable. bool HaveInsertPoint() const { return Builder.GetInsertBlock() != nullptr; } /// EnsureInsertPoint - Ensure that an insertion point is defined so that /// emitted IR has a place to go. Note that by definition, if this function /// creates a block then that block is unreachable; callers may do better to /// detect when no insertion point is defined and simply skip IR generation. void EnsureInsertPoint() { if (!HaveInsertPoint()) EmitBlock(createBasicBlock()); } /// ErrorUnsupported - Print out an error that codegen doesn't support the /// specified stmt yet. void ErrorUnsupported(const Stmt *S, const char *Type); //===--------------------------------------------------------------------===// // Helpers //===--------------------------------------------------------------------===// LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource AlignSource = AlignmentSource::Type) { return LValue::MakeAddr(Addr, T, getContext(), AlignSource, CGM.getTBAAInfo(T)); } LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, AlignmentSource AlignSource = AlignmentSource::Type) { return LValue::MakeAddr(Address(V, Alignment), T, getContext(), AlignSource, CGM.getTBAAInfo(T)); } LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T); LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); CharUnits getNaturalTypeAlignment(QualType T, AlignmentSource *Source = nullptr, bool forPointeeType = false); CharUnits getNaturalPointeeTypeAlignment(QualType T, AlignmentSource *Source = nullptr); Address EmitLoadOfReference(Address Ref, const ReferenceType *RefTy, AlignmentSource *Source = nullptr); LValue EmitLoadOfReferenceLValue(Address Ref, const ReferenceType *RefTy); Address EmitLoadOfPointer(Address Ptr, const PointerType *PtrTy, AlignmentSource *Source = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. The caller is responsible for setting an appropriate alignment on /// the alloca. llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp"); Address CreateTempAlloca(llvm::Type *Ty, CharUnits align, const Twine &Name = "tmp"); /// CreateDefaultAlignedTempAlloca - This creates an alloca with the /// default ABI alignment of the given LLVM type. /// /// IMPORTANT NOTE: This is *not* generally the right alignment for /// any given AST type that happens to have been lowered to the /// given IR type. This should only ever be used for function-local, /// IR-driven manipulations like saving and restoring a value. Do /// not hand this address off to arbitrary IRGen routines, and especially /// do not pass it as an argument to a function that might expect a /// properly ABI-aligned value. Address CreateDefaultAlignTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp"); /// InitTempAlloca - Provide an initial value for the given alloca which /// will be observable at all locations in the function. /// /// The address should be something that was returned from one of /// the CreateTempAlloca or CreateMemTemp routines, and the /// initializer must be valid in the entry block (i.e. it must /// either be a constant or an argument value). void InitTempAlloca(Address Alloca, llvm::Value *Value); /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary /// value needs to be stored into an alloca (for example, to avoid explicit /// PHI construction), but the type is the IR type, not the type appropriate /// for storing in memory. /// /// That is, this is exactly equivalent to CreateMemTemp, but calling /// ConvertType instead of ConvertTypeForMem. Address CreateIRTemp(QualType T, const Twine &Name = "tmp"); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignment. Address CreateMemTemp(QualType T, const Twine &Name = "tmp"); Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp"); /// CreateAggTemp - Create a temporary memory object for the given /// aggregate type. AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp") { return AggValueSlot::forAddr(CreateMemTemp(T, Name), T.getQualifiers(), AggValueSlot::IsNotDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased); } /// Emit a cast to void* in the appropriate address space. llvm::Value *EmitCastToVoidPtr(llvm::Value *value); /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *EvaluateExprAsBool(const Expr *E); /// EmitIgnoredExpr - Emit an expression in a context which ignores the result. void EmitIgnoredExpr(const Expr *E); /// EmitAnyExpr - Emit code to compute the specified expression which can have /// any type. The result is returned as an RValue struct. If this is an /// aggregate expression, the aggloc/agglocvolatile arguments indicate where /// the result should be returned. /// /// \param ignoreResult True if the resulting value isn't used. RValue EmitAnyExpr(const Expr *E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); // EmitVAListRef - Emit a "reference" to a va_list; this is either the address // or the value of the expression, depending on how va_list is defined. Address EmitVAListRef(const Expr *E); /// Emit a "reference" to a __builtin_ms_va_list; this is /// always the value of the expression, because a __builtin_ms_va_list is a /// pointer to a char. Address EmitMSVAListRef(const Expr *E); /// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will /// always be accessible even if no aggregate location is provided. RValue EmitAnyExprToTemp(const Expr *E); /// EmitAnyExprToMem - Emits the code necessary to evaluate an /// arbitrary expression into the given memory location. void EmitAnyExprToMem(const Expr *E, Address Location, Qualifiers Quals, bool IsInitializer); void EmitAnyExprToExn(const Expr *E, Address Addr); /// EmitExprAsInit - Emits the code necessary to initialize a /// location in memory with the given initializer. void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit); /// hasVolatileMember - returns true if aggregate type has a volatile /// member. bool hasVolatileMember(QualType T) { if (const RecordType *RT = T->getAs()) { const RecordDecl *RD = cast(RT->getDecl()); return RD->hasVolatileMember(); } return false; } /// EmitAggregateCopy - Emit an aggregate assignment. /// /// The difference to EmitAggregateCopy is that tail padding is not copied. /// This is required for correctness when assigning non-POD structures in C++. void EmitAggregateAssign(Address DestPtr, Address SrcPtr, QualType EltTy) { bool IsVolatile = hasVolatileMember(EltTy); EmitAggregateCopy(DestPtr, SrcPtr, EltTy, IsVolatile, true); } void EmitAggregateCopyCtor(Address DestPtr, Address SrcPtr, QualType DestTy, QualType SrcTy) { EmitAggregateCopy(DestPtr, SrcPtr, SrcTy, /*IsVolatile=*/false, /*IsAssignment=*/false); } /// EmitAggregateCopy - Emit an aggregate copy. /// /// \param isVolatile - True iff either the source or the destination is /// volatile. /// \param isAssignment - If false, allow padding to be copied. This often /// yields more efficient. void EmitAggregateCopy(Address DestPtr, Address SrcPtr, QualType EltTy, bool isVolatile=false, bool isAssignment = false); /// GetAddrOfLocalVar - Return the address of a local variable. Address GetAddrOfLocalVar(const VarDecl *VD) { auto it = LocalDeclMap.find(VD); assert(it != LocalDeclMap.end() && "Invalid argument to GetAddrOfLocalVar(), no decl!"); return it->second; } /// getOpaqueLValueMapping - Given an opaque value expression (which /// must be mapped to an l-value), return its mapping. const LValue &getOpaqueLValueMapping(const OpaqueValueExpr *e) { assert(OpaqueValueMapping::shouldBindAsLValue(e)); llvm::DenseMap::iterator it = OpaqueLValues.find(e); assert(it != OpaqueLValues.end() && "no mapping for opaque value!"); return it->second; } /// getOpaqueRValueMapping - Given an opaque value expression (which /// must be mapped to an r-value), return its mapping. const RValue &getOpaqueRValueMapping(const OpaqueValueExpr *e) { assert(!OpaqueValueMapping::shouldBindAsLValue(e)); llvm::DenseMap::iterator it = OpaqueRValues.find(e); assert(it != OpaqueRValues.end() && "no mapping for opaque value!"); return it->second; } /// getAccessedFieldNo - Given an encoded value and a result number, return /// the input field number being accessed. static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts); llvm::BlockAddress *GetAddrOfLabel(const LabelDecl *L); llvm::BasicBlock *GetIndirectGotoBlock(); /// EmitNullInitialization - Generate code to set a value of the given type to /// null, If the type contains data member pointers, they will be initialized /// to -1 in accordance with the Itanium C++ ABI. void EmitNullInitialization(Address DestPtr, QualType Ty); /// Emits a call to an LLVM variable-argument intrinsic, either /// \c llvm.va_start or \c llvm.va_end. /// \param ArgValue A reference to the \c va_list as emitted by either /// \c EmitVAListRef or \c EmitMSVAListRef. /// \param IsStart If \c true, emits a call to \c llvm.va_start; otherwise, /// calls \c llvm.va_end. llvm::Value *EmitVAStartEnd(llvm::Value *ArgValue, bool IsStart); /// Generate code to get an argument from the passed in pointer /// and update it accordingly. /// \param VE The \c VAArgExpr for which to generate code. /// \param VAListAddr Receives a reference to the \c va_list as emitted by /// either \c EmitVAListRef or \c EmitMSVAListRef. /// \returns A pointer to the argument. // FIXME: We should be able to get rid of this method and use the va_arg // instruction in LLVM instead once it works well enough. Address EmitVAArg(VAArgExpr *VE, Address &VAListAddr); /// emitArrayLength - Compute the length of an array, even if it's a /// VLA, and drill down to the base element type. llvm::Value *emitArrayLength(const ArrayType *arrayType, QualType &baseType, Address &addr); /// EmitVLASize - Capture all the sizes for the VLA expressions in /// the given variably-modified type and store them in the VLASizeMap. /// /// This function can be called with a null (unreachable) insert point. void EmitVariablyModifiedType(QualType Ty); /// getVLASize - Returns an LLVM value that corresponds to the size, /// in non-variably-sized elements, of a variable length array type, /// plus that largest non-variably-sized element type. Assumes that /// the type has already been emitted with EmitVariablyModifiedType. std::pair getVLASize(const VariableArrayType *vla); std::pair getVLASize(QualType vla); /// LoadCXXThis - Load the value of 'this'. This function is only valid while /// generating code for an C++ member function. llvm::Value *LoadCXXThis() { assert(CXXThisValue && "no 'this' value for this function"); return CXXThisValue; } Address LoadCXXThisAddress(); /// LoadCXXVTT - Load the VTT parameter to base constructors/destructors have /// virtual bases. // FIXME: Every place that calls LoadCXXVTT is something // that needs to be abstracted properly. llvm::Value *LoadCXXVTT() { assert(CXXStructorImplicitParamValue && "no VTT value for this function"); return CXXStructorImplicitParamValue; } /// GetAddressOfBaseOfCompleteClass - Convert the given pointer to a /// complete class to the given direct base. Address GetAddressOfDirectBaseInCompleteClass(Address Value, const CXXRecordDecl *Derived, const CXXRecordDecl *Base, bool BaseIsVirtual); static bool ShouldNullCheckClassCastValue(const CastExpr *Cast); /// GetAddressOfBaseClass - This function will add the necessary delta to the /// load of 'this' and returns address of the base class. Address GetAddressOfBaseClass(Address Value, const CXXRecordDecl *Derived, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd, bool NullCheckValue, SourceLocation Loc); Address GetAddressOfDerivedClass(Address Value, const CXXRecordDecl *Derived, CastExpr::path_const_iterator PathBegin, CastExpr::path_const_iterator PathEnd, bool NullCheckValue); /// GetVTTParameter - Return the VTT parameter that should be passed to a /// base constructor/destructor with virtual bases. /// FIXME: VTTs are Itanium ABI-specific, so the definition should move /// to ItaniumCXXABI.cpp together with all the references to VTT. llvm::Value *GetVTTParameter(GlobalDecl GD, bool ForVirtualBase, bool Delegating); void EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, const FunctionArgList &Args, SourceLocation Loc); // It's important not to confuse this and the previous function. Delegating // constructors are the C++0x feature. The constructor delegate optimization // is used to reduce duplication in the base and complete consturctors where // they are substantially the same. void EmitDelegatingCXXConstructorCall(const CXXConstructorDecl *Ctor, const FunctionArgList &Args); /// Emit a call to an inheriting constructor (that is, one that invokes a /// constructor inherited from a base class) by inlining its definition. This /// is necessary if the ABI does not support forwarding the arguments to the /// base class constructor (because they're variadic or similar). void EmitInlinedInheritingCXXConstructorCall(const CXXConstructorDecl *Ctor, CXXCtorType CtorType, bool ForVirtualBase, bool Delegating, CallArgList &Args); /// Emit a call to a constructor inherited from a base class, passing the /// current constructor's arguments along unmodified (without even making /// a copy). void EmitInheritedCXXConstructorCall(const CXXConstructorDecl *D, bool ForVirtualBase, Address This, bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, Address This, const CXXConstructExpr *E); void EmitCXXConstructorCall(const CXXConstructorDecl *D, CXXCtorType Type, bool ForVirtualBase, bool Delegating, Address This, CallArgList &Args); /// Emit assumption load for all bases. Requires to be be called only on /// most-derived class and not under construction of the object. void EmitVTableAssumptionLoads(const CXXRecordDecl *ClassDecl, Address This); /// Emit assumption that vptr load == global vtable. void EmitVTableAssumptionLoad(const VPtr &vptr, Address This); void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, Address This, Address Src, const CXXConstructExpr *E); void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, const ArrayType *ArrayTy, Address ArrayPtr, const CXXConstructExpr *E, bool ZeroInitialization = false); void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D, llvm::Value *NumElements, Address ArrayPtr, const CXXConstructExpr *E, bool ZeroInitialization = false); static Destroyer destroyCXXObject; void EmitCXXDestructorCall(const CXXDestructorDecl *D, CXXDtorType Type, bool ForVirtualBase, bool Delegating, Address This); void EmitNewArrayInitializer(const CXXNewExpr *E, QualType elementType, llvm::Type *ElementTy, Address NewPtr, llvm::Value *NumElements, llvm::Value *AllocSizeWithoutCookie); void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType, Address Ptr); llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr); void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); void EmitCXXDeleteExpr(const CXXDeleteExpr *E); void EmitDeleteCall(const FunctionDecl *DeleteFD, llvm::Value *Ptr, QualType DeleteTy); RValue EmitBuiltinNewDeleteCall(const FunctionProtoType *Type, const Expr *Arg, bool IsDelete); llvm::Value *EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(Address V, const CXXDynamicCastExpr *DCE); Address EmitCXXUuidofExpr(const CXXUuidofExpr *E); /// \brief Situations in which we might emit a check for the suitability of a /// pointer or glvalue. enum TypeCheckKind { /// Checking the operand of a load. Must be suitably sized and aligned. TCK_Load, /// Checking the destination of a store. Must be suitably sized and aligned. TCK_Store, /// Checking the bound value in a reference binding. Must be suitably sized /// and aligned, but is not required to refer to an object (until the /// reference is used), per core issue 453. TCK_ReferenceBinding, /// Checking the object expression in a non-static data member access. Must /// be an object within its lifetime. TCK_MemberAccess, /// Checking the 'this' pointer for a call to a non-static member function. /// Must be an object within its lifetime. TCK_MemberCall, /// Checking the 'this' pointer for a constructor call. TCK_ConstructorCall, /// Checking the operand of a static_cast to a derived pointer type. Must be /// null or an object within its lifetime. TCK_DowncastPointer, /// Checking the operand of a static_cast to a derived reference type. Must /// be an object within its lifetime. TCK_DowncastReference, /// Checking the operand of a cast to a base object. Must be suitably sized /// and aligned. TCK_Upcast, /// Checking the operand of a cast to a virtual base object. Must be an /// object within its lifetime. TCK_UpcastToVirtualBase }; /// \brief Whether any type-checking sanitizers are enabled. If \c false, /// calls to EmitTypeCheck can be skipped. bool sanitizePerformTypeCheck() const; /// \brief Emit a check that \p V is the address of storage of the /// appropriate size and alignment for an object of type \p Type. void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V, QualType Type, CharUnits Alignment = CharUnits::Zero(), bool SkipNullCheck = false); /// \brief Emit a check that \p Base points into an array object, which /// we can access at index \p Index. \p Accessed should be \c false if we /// this expression is used as an lvalue, for instance in "&Arr[Idx]". void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); ComplexPairTy EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); void EmitAlignmentAssumption(llvm::Value *PtrValue, unsigned Alignment, llvm::Value *OffsetValue = nullptr) { Builder.CreateAlignmentAssumption(CGM.getDataLayout(), PtrValue, Alignment, OffsetValue); } //===--------------------------------------------------------------------===// // Declaration Emission //===--------------------------------------------------------------------===// /// EmitDecl - Emit a declaration. /// /// This function can be called with a null (unreachable) insert point. void EmitDecl(const Decl &D); /// EmitVarDecl - Emit a local variable declaration. /// /// This function can be called with a null (unreachable) insert point. void EmitVarDecl(const VarDecl &D); void EmitScalarInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit); void EmitScalarInit(llvm::Value *init, LValue lvalue); typedef void SpecialInitFn(CodeGenFunction &Init, const VarDecl &D, llvm::Value *Address); /// \brief Determine whether the given initializer is trivial in the sense /// that it requires no code to be generated. bool isTrivialInitializer(const Expr *Init); /// EmitAutoVarDecl - Emit an auto variable declaration. /// /// This function can be called with a null (unreachable) insert point. void EmitAutoVarDecl(const VarDecl &D); class AutoVarEmission { friend class CodeGenFunction; const VarDecl *Variable; /// The address of the alloca. Invalid if the variable was emitted /// as a global constant. Address Addr; llvm::Value *NRVOFlag; /// True if the variable is a __block variable. bool IsByRef; /// True if the variable is of aggregate type and has a constant /// initializer. bool IsConstantAggregate; /// Non-null if we should use lifetime annotations. llvm::Value *SizeForLifetimeMarkers; struct Invalid {}; AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()) {} AutoVarEmission(const VarDecl &variable) : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), IsByRef(false), IsConstantAggregate(false), SizeForLifetimeMarkers(nullptr) {} bool wasEmittedAsGlobal() const { return !Addr.isValid(); } public: static AutoVarEmission invalid() { return AutoVarEmission(Invalid()); } bool useLifetimeMarkers() const { return SizeForLifetimeMarkers != nullptr; } llvm::Value *getSizeForLifetimeMarkers() const { assert(useLifetimeMarkers()); return SizeForLifetimeMarkers; } /// Returns the raw, allocated address, which is not necessarily /// the address of the object itself. Address getAllocatedAddress() const { return Addr; } /// Returns the address of the object within this declaration. /// Note that this does not chase the forwarding pointer for /// __block decls. Address getObjectAddress(CodeGenFunction &CGF) const { if (!IsByRef) return Addr; return CGF.emitBlockByrefAddress(Addr, Variable, /*forward*/ false); } }; AutoVarEmission EmitAutoVarAlloca(const VarDecl &var); void EmitAutoVarInit(const AutoVarEmission &emission); void EmitAutoVarCleanups(const AutoVarEmission &emission); void emitAutoVarTypeCleanup(const AutoVarEmission &emission, QualType::DestructionKind dtorKind); void EmitStaticVarDecl(const VarDecl &D, llvm::GlobalValue::LinkageTypes Linkage); class ParamValue { llvm::Value *Value; unsigned Alignment; ParamValue(llvm::Value *V, unsigned A) : Value(V), Alignment(A) {} public: static ParamValue forDirect(llvm::Value *value) { return ParamValue(value, 0); } static ParamValue forIndirect(Address addr) { assert(!addr.getAlignment().isZero()); return ParamValue(addr.getPointer(), addr.getAlignment().getQuantity()); } bool isIndirect() const { return Alignment != 0; } llvm::Value *getAnyValue() const { return Value; } llvm::Value *getDirectValue() const { assert(!isIndirect()); return Value; } Address getIndirectAddress() const { assert(isIndirect()); return Address(Value, CharUnits::fromQuantity(Alignment)); } }; /// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl. void EmitParmDecl(const VarDecl &D, ParamValue Arg, unsigned ArgNo); /// protectFromPeepholes - Protect a value that we're intending to /// store to the side, but which will probably be used later, from /// aggressive peepholing optimizations that might delete it. /// /// Pass the result to unprotectFromPeepholes to declare that /// protection is no longer required. /// /// There's no particular reason why this shouldn't apply to /// l-values, it's just that no existing peepholes work on pointers. PeepholeProtection protectFromPeepholes(RValue rvalue); void unprotectFromPeepholes(PeepholeProtection protection); //===--------------------------------------------------------------------===// // Statement Emission //===--------------------------------------------------------------------===// /// EmitStopPoint - Emit a debug stoppoint if we are emitting debug info. void EmitStopPoint(const Stmt *S); /// EmitStmt - Emit the code for the statement \arg S. It is legal to call /// this function even if there is no current insertion point. /// /// This function may clear the current insertion point; callers should use /// EnsureInsertPoint if they wish to subsequently generate code without first /// calling EmitBlock, EmitBranch, or EmitStmt. void EmitStmt(const Stmt *S); /// EmitSimpleStmt - Try to emit a "simple" statement which does not /// necessarily require an insertion point or debug information; typically /// because the statement amounts to a jump or a container of other /// statements. /// /// \return True if the statement was handled. bool EmitSimpleStmt(const Stmt *S); Address EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false, AggValueSlot AVS = AggValueSlot::ignored()); Address EmitCompoundStmtWithoutScope(const CompoundStmt &S, bool GetLast = false, AggValueSlot AVS = AggValueSlot::ignored()); /// EmitLabel - Emit the block for the given label. It is legal to call this /// function even if there is no current insertion point. void EmitLabel(const LabelDecl *D); // helper for EmitLabelStmt. void EmitLabelStmt(const LabelStmt &S); void EmitAttributedStmt(const AttributedStmt &S); void EmitGotoStmt(const GotoStmt &S); void EmitIndirectGotoStmt(const IndirectGotoStmt &S); void EmitIfStmt(const IfStmt &S); void EmitWhileStmt(const WhileStmt &S, ArrayRef Attrs = None); void EmitDoStmt(const DoStmt &S, ArrayRef Attrs = None); void EmitForStmt(const ForStmt &S, ArrayRef Attrs = None); void EmitReturnStmt(const ReturnStmt &S); void EmitDeclStmt(const DeclStmt &S); void EmitBreakStmt(const BreakStmt &S); void EmitContinueStmt(const ContinueStmt &S); void EmitSwitchStmt(const SwitchStmt &S); void EmitDefaultStmt(const DefaultStmt &S); void EmitCaseStmt(const CaseStmt &S); void EmitCaseStmtRange(const CaseStmt &S); void EmitAsmStmt(const AsmStmt &S); void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); void EmitObjCAtThrowStmt(const ObjCAtThrowStmt &S); void EmitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt &S); void EmitObjCAutoreleasePoolStmt(const ObjCAutoreleasePoolStmt &S); void EnterCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); void ExitCXXTryStmt(const CXXTryStmt &S, bool IsFnTryBlock = false); void EmitCXXTryStmt(const CXXTryStmt &S); void EmitSEHTryStmt(const SEHTryStmt &S); void EmitSEHLeaveStmt(const SEHLeaveStmt &S); void EnterSEHTryStmt(const SEHTryStmt &S); void ExitSEHTryStmt(const SEHTryStmt &S); void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, bool IsFilter, const Stmt *OutlinedStmt); llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF, const SEHExceptStmt &Except); llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF, const SEHFinallyStmt &Finally); void EmitSEHExceptionCodeSave(CodeGenFunction &ParentCGF, llvm::Value *ParentFP, llvm::Value *EntryEBP); llvm::Value *EmitSEHExceptionCode(); llvm::Value *EmitSEHExceptionInfo(); llvm::Value *EmitSEHAbnormalTermination(); /// Scan the outlined statement for captures from the parent function. For /// each capture, mark the capture as escaped and emit a call to /// llvm.localrecover. Insert the localrecover result into the LocalDeclMap. void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt *OutlinedStmt, bool IsFilter); /// Recovers the address of a local in a parent function. ParentVar is the /// address of the variable used in the immediate parent function. It can /// either be an alloca or a call to llvm.localrecover if there are nested /// outlined functions. ParentFP is the frame pointer of the outermost parent /// frame. Address recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, Address ParentVar, llvm::Value *ParentFP); void EmitCXXForRangeStmt(const CXXForRangeStmt &S, ArrayRef Attrs = None); /// Returns calculated size of the specified type. llvm::Value *getTypeSize(QualType Ty); LValue InitCapturedStruct(const CapturedStmt &S); llvm::Function *EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K); llvm::Function *GenerateCapturedStmtFunction(const CapturedStmt &S); Address GenerateCapturedStmtArgument(const CapturedStmt &S); llvm::Function *GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S); void GenerateOpenMPCapturedVars(const CapturedStmt &S, SmallVectorImpl &CapturedVars); void emitOMPSimpleStore(LValue LVal, RValue RVal, QualType RValTy, SourceLocation Loc); /// \brief Perform element by element copying of arrays with type \a /// OriginalType from \a SrcAddr to \a DestAddr using copying procedure /// generated by \a CopyGen. /// /// \param DestAddr Address of the destination array. /// \param SrcAddr Address of the source array. /// \param OriginalType Type of destination and source arrays. /// \param CopyGen Copying procedure that copies value of single array element /// to another single array element. void EmitOMPAggregateAssign( Address DestAddr, Address SrcAddr, QualType OriginalType, const llvm::function_ref &CopyGen); /// \brief Emit proper copying of data from one variable to another. /// /// \param OriginalType Original type of the copied variables. /// \param DestAddr Destination address. /// \param SrcAddr Source address. /// \param DestVD Destination variable used in \a CopyExpr (for arrays, has /// type of the base array element). /// \param SrcVD Source variable used in \a CopyExpr (for arrays, has type of /// the base array element). /// \param Copy Actual copygin expression for copying data from \a SrcVD to \a /// DestVD. void EmitOMPCopy(QualType OriginalType, Address DestAddr, Address SrcAddr, const VarDecl *DestVD, const VarDecl *SrcVD, const Expr *Copy); /// \brief Emit atomic update code for constructs: \a X = \a X \a BO \a E or /// \a X = \a E \a BO \a E. /// /// \param X Value to be updated. /// \param E Update value. /// \param BO Binary operation for update operation. /// \param IsXLHSInRHSPart true if \a X is LHS in RHS part of the update /// expression, false otherwise. /// \param AO Atomic ordering of the generated atomic instructions. /// \param CommonGen Code generator for complex expressions that cannot be /// expressed through atomicrmw instruction. /// \returns if simple 'atomicrmw' instruction was /// generated, otherwise. std::pair EmitOMPAtomicSimpleUpdateExpr( LValue X, RValue E, BinaryOperatorKind BO, bool IsXLHSInRHSPart, llvm::AtomicOrdering AO, SourceLocation Loc, const llvm::function_ref &CommonGen); bool EmitOMPFirstprivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); void EmitOMPPrivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); /// \brief Emit code for copyin clause in \a D directive. The next code is /// generated at the start of outlined functions for directives: /// \code /// threadprivate_var1 = master_threadprivate_var1; /// operator=(threadprivate_var2, master_threadprivate_var2); /// ... /// __kmpc_barrier(&loc, global_tid); /// \endcode /// /// \param D OpenMP directive possibly with 'copyin' clause(s). /// \returns true if at least one copyin variable is found, false otherwise. bool EmitOMPCopyinClause(const OMPExecutableDirective &D); /// \brief Emit initial code for lastprivate variables. If some variable is /// not also firstprivate, then the default initialization is used. Otherwise /// initialization of this variable is performed by EmitOMPFirstprivateClause /// method. /// /// \param D Directive that may have 'lastprivate' directives. /// \param PrivateScope Private scope for capturing lastprivate variables for /// proper codegen in internal captured statement. /// /// \returns true if there is at least one lastprivate variable, false /// otherwise. bool EmitOMPLastprivateClauseInit(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); /// \brief Emit final copying of lastprivate values to original variables at /// the end of the worksharing or simd directive. /// /// \param D Directive that has at least one 'lastprivate' directives. /// \param IsLastIterCond Boolean condition that must be set to 'i1 true' if /// it is the last iteration of the loop code in associated directive, or to /// 'i1 false' otherwise. If this item is nullptr, no final check is required. void EmitOMPLastprivateClauseFinal(const OMPExecutableDirective &D, bool NoFinals, llvm::Value *IsLastIterCond = nullptr); /// Emit initial code for linear clauses. void EmitOMPLinearClause(const OMPLoopDirective &D, CodeGenFunction::OMPPrivateScope &PrivateScope); /// Emit final code for linear clauses. /// \param CondGen Optional conditional code for final part of codegen for /// linear clause. void EmitOMPLinearClauseFinal( const OMPLoopDirective &D, const llvm::function_ref &CondGen); /// \brief Emit initial code for reduction variables. Creates reduction copies /// and initializes them with the values according to OpenMP standard. /// /// \param D Directive (possibly) with the 'reduction' clause. /// \param PrivateScope Private scope for capturing reduction variables for /// proper codegen in internal captured statement. /// void EmitOMPReductionClauseInit(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); /// \brief Emit final update of reduction values to original variables at /// the end of the directive. /// /// \param D Directive that has at least one 'reduction' directives. void EmitOMPReductionClauseFinal(const OMPExecutableDirective &D); /// \brief Emit initial code for linear variables. Creates private copies /// and initializes them with the values according to OpenMP standard. /// /// \param D Directive (possibly) with the 'linear' clause. void EmitOMPLinearClauseInit(const OMPLoopDirective &D); typedef const llvm::function_ref TaskGenTy; void EmitOMPTaskBasedDirective(const OMPExecutableDirective &S, const RegionCodeGenTy &BodyGen, const TaskGenTy &TaskGen, OMPTaskDataTy &Data); void EmitOMPParallelDirective(const OMPParallelDirective &S); void EmitOMPSimdDirective(const OMPSimdDirective &S); void EmitOMPForDirective(const OMPForDirective &S); void EmitOMPForSimdDirective(const OMPForSimdDirective &S); void EmitOMPSectionsDirective(const OMPSectionsDirective &S); void EmitOMPSectionDirective(const OMPSectionDirective &S); void EmitOMPSingleDirective(const OMPSingleDirective &S); void EmitOMPMasterDirective(const OMPMasterDirective &S); void EmitOMPCriticalDirective(const OMPCriticalDirective &S); void EmitOMPParallelForDirective(const OMPParallelForDirective &S); void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S); void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S); void EmitOMPTaskDirective(const OMPTaskDirective &S); void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S); void EmitOMPBarrierDirective(const OMPBarrierDirective &S); void EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S); void EmitOMPTaskgroupDirective(const OMPTaskgroupDirective &S); void EmitOMPFlushDirective(const OMPFlushDirective &S); void EmitOMPOrderedDirective(const OMPOrderedDirective &S); void EmitOMPAtomicDirective(const OMPAtomicDirective &S); void EmitOMPTargetDirective(const OMPTargetDirective &S); void EmitOMPTargetDataDirective(const OMPTargetDataDirective &S); void EmitOMPTargetEnterDataDirective(const OMPTargetEnterDataDirective &S); void EmitOMPTargetExitDataDirective(const OMPTargetExitDataDirective &S); void EmitOMPTargetUpdateDirective(const OMPTargetUpdateDirective &S); void EmitOMPTargetParallelDirective(const OMPTargetParallelDirective &S); void EmitOMPTargetParallelForDirective(const OMPTargetParallelForDirective &S); void EmitOMPTeamsDirective(const OMPTeamsDirective &S); void EmitOMPCancellationPointDirective(const OMPCancellationPointDirective &S); void EmitOMPCancelDirective(const OMPCancelDirective &S); void EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S); void EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S); void EmitOMPTaskLoopSimdDirective(const OMPTaskLoopSimdDirective &S); void EmitOMPDistributeDirective(const OMPDistributeDirective &S); void EmitOMPDistributeLoop(const OMPDistributeDirective &S); void EmitOMPDistributeParallelForDirective( const OMPDistributeParallelForDirective &S); void EmitOMPDistributeParallelForSimdDirective( const OMPDistributeParallelForSimdDirective &S); void EmitOMPDistributeSimdDirective(const OMPDistributeSimdDirective &S); void EmitOMPTargetParallelForSimdDirective( const OMPTargetParallelForSimdDirective &S); /// Emit outlined function for the target directive. static std::pair EmitOMPTargetDirectiveOutlinedFunction(CodeGenModule &CGM, const OMPTargetDirective &S, StringRef ParentName, bool IsOffloadEntry); /// \brief Emit inner loop of the worksharing/simd construct. /// /// \param S Directive, for which the inner loop must be emitted. /// \param RequiresCleanup true, if directive has some associated private /// variables. /// \param LoopCond Bollean condition for loop continuation. /// \param IncExpr Increment expression for loop control variable. /// \param BodyGen Generator for the inner body of the inner loop. /// \param PostIncGen Genrator for post-increment code (required for ordered /// loop directvies). void EmitOMPInnerLoop( const Stmt &S, bool RequiresCleanup, const Expr *LoopCond, const Expr *IncExpr, const llvm::function_ref &BodyGen, const llvm::function_ref &PostIncGen); JumpDest getOMPCancelDestination(OpenMPDirectiveKind Kind); /// Emit initial code for loop counters of loop-based directives. void EmitOMPPrivateLoopCounters(const OMPLoopDirective &S, OMPPrivateScope &LoopScope); private: /// Helpers for the OpenMP loop directives. void EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit); void EmitOMPSimdInit(const OMPLoopDirective &D, bool IsMonotonic = false); void EmitOMPSimdFinal( const OMPLoopDirective &D, const llvm::function_ref &CondGen); /// \brief Emit code for the worksharing loop-based directive. /// \return true, if this construct has any lastprivate clause, false - /// otherwise. bool EmitOMPWorksharingLoop(const OMPLoopDirective &S); void EmitOMPOuterLoop(bool IsMonotonic, bool DynamicOrOrdered, const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk); void EmitOMPForOuterLoop(const OpenMPScheduleTy &ScheduleKind, bool IsMonotonic, const OMPLoopDirective &S, OMPPrivateScope &LoopScope, bool Ordered, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk); void EmitOMPDistributeOuterLoop( OpenMPDistScheduleClauseKind ScheduleKind, const OMPDistributeDirective &S, OMPPrivateScope &LoopScope, Address LB, Address UB, Address ST, Address IL, llvm::Value *Chunk); /// \brief Emit code for sections directive. void EmitSections(const OMPExecutableDirective &S); public: //===--------------------------------------------------------------------===// // LValue Expression Emission //===--------------------------------------------------------------------===// /// GetUndefRValue - Get an appropriate 'undef' rvalue for the given type. RValue GetUndefRValue(QualType Ty); /// EmitUnsupportedRValue - Emit a dummy r-value using the type of E /// and issue an ErrorUnsupported style diagnostic (using the /// provided Name). RValue EmitUnsupportedRValue(const Expr *E, const char *Name); /// EmitUnsupportedLValue - Emit a dummy l-value using the type of E and issue /// an ErrorUnsupported style diagnostic (using the provided Name). LValue EmitUnsupportedLValue(const Expr *E, const char *Name); /// EmitLValue - Emit code to compute a designator that specifies the location /// of the expression. /// /// This can return one of two things: a simple address or a bitfield /// reference. In either case, the LLVM Value* in the LValue structure is /// guaranteed to be an LLVM pointer type. /// /// If this returns a bitfield reference, nothing about the pointee type of /// the LLVM value is known: For example, it may not be a pointer to an /// integer. /// /// If this returns a normal address, and if the lvalue's C type is fixed /// size, this method guarantees that the returned pointer type will point to /// an LLVM type of the same size of the lvalue's type. If the lvalue has a /// variable length type, this is not possible. /// LValue EmitLValue(const Expr *E); /// \brief Same as EmitLValue but additionally we generate checking code to /// guard against undefined behavior. This is only suitable when we know /// that the address will be used to access the object. LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK); RValue convertTempToRValue(Address addr, QualType type, SourceLocation Loc); void EmitAtomicInit(Expr *E, LValue lvalue); bool LValueIsSuitableForInlineAtomic(LValue Src); RValue EmitAtomicLoad(LValue LV, SourceLocation SL, AggValueSlot Slot = AggValueSlot::ignored()); RValue EmitAtomicLoad(LValue lvalue, SourceLocation loc, llvm::AtomicOrdering AO, bool IsVolatile = false, AggValueSlot slot = AggValueSlot::ignored()); void EmitAtomicStore(RValue rvalue, LValue lvalue, bool isInit); void EmitAtomicStore(RValue rvalue, LValue lvalue, llvm::AtomicOrdering AO, bool IsVolatile, bool isInit); std::pair EmitAtomicCompareExchange( LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc, llvm::AtomicOrdering Success = llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering Failure = llvm::AtomicOrdering::SequentiallyConsistent, bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored()); void EmitAtomicUpdate(LValue LVal, llvm::AtomicOrdering AO, const llvm::function_ref &UpdateOp, bool IsVolatile); /// EmitToMemory - Change a scalar value from its value /// representation to its in-memory representation. llvm::Value *EmitToMemory(llvm::Value *Value, QualType Ty); /// EmitFromMemory - Change a scalar value from its memory /// representation to its value representation. llvm::Value *EmitFromMemory(llvm::Value *Value, QualType Ty); /// EmitLoadOfScalar - Load a scalar value from an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. llvm::Value *EmitLoadOfScalar(Address Addr, bool Volatile, QualType Ty, SourceLocation Loc, AlignmentSource AlignSource = AlignmentSource::Type, llvm::MDNode *TBAAInfo = nullptr, QualType TBAABaseTy = QualType(), uint64_t TBAAOffset = 0, bool isNontemporal = false); /// EmitLoadOfScalar - Load a scalar value from an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. The l-value must be a simple /// l-value. llvm::Value *EmitLoadOfScalar(LValue lvalue, SourceLocation Loc); /// EmitStoreOfScalar - Store a scalar value to an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. void EmitStoreOfScalar(llvm::Value *Value, Address Addr, bool Volatile, QualType Ty, AlignmentSource AlignSource = AlignmentSource::Type, llvm::MDNode *TBAAInfo = nullptr, bool isInit = false, QualType TBAABaseTy = QualType(), uint64_t TBAAOffset = 0, bool isNontemporal = false); /// EmitStoreOfScalar - Store a scalar value to an address, taking /// care to appropriately convert from the memory representation to /// the LLVM value representation. The l-value must be a simple /// l-value. The isInit flag indicates whether this is an initialization. /// If so, atomic qualifiers are ignored and the store is always non-atomic. void EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit=false); /// EmitLoadOfLValue - Given an expression that represents a value lvalue, /// this method emits the address of the lvalue, then loads the result as an /// rvalue, returning the rvalue. RValue EmitLoadOfLValue(LValue V, SourceLocation Loc); RValue EmitLoadOfExtVectorElementLValue(LValue V); RValue EmitLoadOfBitfieldLValue(LValue LV); RValue EmitLoadOfGlobalRegLValue(LValue LV); /// EmitStoreThroughLValue - Store the specified rvalue into the specified /// lvalue, where both are guaranteed to the have the same type, and that type /// is 'Ty'. void EmitStoreThroughLValue(RValue Src, LValue Dst, bool isInit = false); void EmitStoreThroughExtVectorComponentLValue(RValue Src, LValue Dst); void EmitStoreThroughGlobalRegLValue(RValue Src, LValue Dst); /// EmitStoreThroughBitfieldLValue - Store Src into Dst with same constraints /// as EmitStoreThroughLValue. /// /// \param Result [out] - If non-null, this will be set to a Value* for the /// bit-field contents after the store, appropriate for use as the result of /// an assignment to the bit-field. void EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, llvm::Value **Result=nullptr); /// Emit an l-value for an assignment (simple or compound) of complex type. LValue EmitComplexAssignmentLValue(const BinaryOperator *E); LValue EmitComplexCompoundAssignmentLValue(const CompoundAssignOperator *E); LValue EmitScalarCompoundAssignWithComplex(const CompoundAssignOperator *E, llvm::Value *&Result); // Note: only available for agg return types LValue EmitBinaryOperatorLValue(const BinaryOperator *E); LValue EmitCompoundAssignmentLValue(const CompoundAssignOperator *E); // Note: only available for agg return types LValue EmitCallExprLValue(const CallExpr *E); // Note: only available for agg return types LValue EmitVAArgExprLValue(const VAArgExpr *E); LValue EmitDeclRefLValue(const DeclRefExpr *E); LValue EmitStringLiteralLValue(const StringLiteral *E); LValue EmitObjCEncodeExprLValue(const ObjCEncodeExpr *E); LValue EmitPredefinedLValue(const PredefinedExpr *E); LValue EmitUnaryOpLValue(const UnaryOperator *E); LValue EmitArraySubscriptExpr(const ArraySubscriptExpr *E, bool Accessed = false); LValue EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, bool IsLowerBound = true); LValue EmitExtVectorElementExpr(const ExtVectorElementExpr *E); LValue EmitMemberExpr(const MemberExpr *E); LValue EmitObjCIsaExpr(const ObjCIsaExpr *E); LValue EmitCompoundLiteralLValue(const CompoundLiteralExpr *E); LValue EmitInitListLValue(const InitListExpr *E); LValue EmitConditionalOperatorLValue(const AbstractConditionalOperator *E); LValue EmitCastLValue(const CastExpr *E); LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); Address EmitExtVectorElementLValue(LValue V); RValue EmitRValueForField(LValue LV, const FieldDecl *FD, SourceLocation Loc); Address EmitArrayToPointerDecay(const Expr *Array, AlignmentSource *AlignSource = nullptr); class ConstantEmission { llvm::PointerIntPair ValueAndIsReference; ConstantEmission(llvm::Constant *C, bool isReference) : ValueAndIsReference(C, isReference) {} public: ConstantEmission() {} static ConstantEmission forReference(llvm::Constant *C) { return ConstantEmission(C, true); } static ConstantEmission forValue(llvm::Constant *C) { return ConstantEmission(C, false); } explicit operator bool() const { return ValueAndIsReference.getOpaqueValue() != nullptr; } bool isReference() const { return ValueAndIsReference.getInt(); } LValue getReferenceLValue(CodeGenFunction &CGF, Expr *refExpr) const { assert(isReference()); return CGF.MakeNaturalAlignAddrLValue(ValueAndIsReference.getPointer(), refExpr->getType()); } llvm::Constant *getValue() const { assert(!isReference()); return ValueAndIsReference.getPointer(); } }; ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e, AggValueSlot slot = AggValueSlot::ignored()); LValue EmitPseudoObjectLValue(const PseudoObjectExpr *e); llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface, const ObjCIvarDecl *Ivar); LValue EmitLValueForField(LValue Base, const FieldDecl* Field); LValue EmitLValueForLambdaField(const FieldDecl *Field); /// EmitLValueForFieldInitialization - Like EmitLValueForField, except that /// if the Field is a reference, this will return the address of the reference /// and not the address of the value stored in the reference. LValue EmitLValueForFieldInitialization(LValue Base, const FieldDecl* Field); LValue EmitLValueForIvar(QualType ObjectTy, llvm::Value* Base, const ObjCIvarDecl *Ivar, unsigned CVRQualifiers); LValue EmitCXXConstructLValue(const CXXConstructExpr *E); LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitLambdaLValue(const LambdaExpr *E); LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E); LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E); LValue EmitStmtExprLValue(const StmtExpr *E); LValue EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E); LValue EmitObjCSelectorLValue(const ObjCSelectorExpr *E); void EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init); //===--------------------------------------------------------------------===// // Scalar Expression Emission //===--------------------------------------------------------------------===// /// EmitCall - Generate a call of the given function, expecting the given /// result type, and using the given argument list which specifies both the /// LLVM arguments and the types they were derived from. RValue EmitCall(const CGFunctionInfo &FnInfo, llvm::Value *Callee, ReturnValueSlot ReturnValue, const CallArgList &Args, CGCalleeInfo CalleeInfo = CGCalleeInfo(), llvm::Instruction **callOrInvoke = nullptr); RValue EmitCall(QualType FnType, llvm::Value *Callee, const CallExpr *E, ReturnValueSlot ReturnValue, CGCalleeInfo CalleeInfo = CGCalleeInfo(), llvm::Value *Chain = nullptr); RValue EmitCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue = ReturnValueSlot()); void checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl); llvm::CallInst *EmitRuntimeCall(llvm::Value *callee, const Twine &name = ""); llvm::CallInst *EmitRuntimeCall(llvm::Value *callee, ArrayRef args, const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee, const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::Value *callee, ArrayRef args, const Twine &name = ""); llvm::CallSite EmitCallOrInvoke(llvm::Value *Callee, ArrayRef Args, const Twine &Name = ""); llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef args, const Twine &name = ""); llvm::CallSite EmitRuntimeCallOrInvoke(llvm::Value *callee, const Twine &name = ""); void EmitNoreturnRuntimeCallOrInvoke(llvm::Value *callee, ArrayRef args); llvm::Value *BuildAppleKextVirtualCall(const CXXMethodDecl *MD, NestedNameSpecifier *Qual, llvm::Type *Ty); llvm::Value *BuildAppleKextVirtualDestructorCall(const CXXDestructorDecl *DD, CXXDtorType Type, const CXXRecordDecl *RD); RValue EmitCXXMemberOrOperatorCall(const CXXMethodDecl *MD, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *E); RValue EmitCXXDestructorCall(const CXXDestructorDecl *DD, llvm::Value *Callee, llvm::Value *This, llvm::Value *ImplicitParam, QualType ImplicitParamTy, const CallExpr *E, StructorType Type); RValue EmitCXXMemberCallExpr(const CXXMemberCallExpr *E, ReturnValueSlot ReturnValue); RValue EmitCXXMemberOrOperatorMemberCallExpr(const CallExpr *CE, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue, bool HasQualifier, NestedNameSpecifier *Qualifier, bool IsArrow, const Expr *Base); // Compute the object pointer. Address EmitCXXMemberDataPointerAddress(const Expr *E, Address base, llvm::Value *memberPtr, const MemberPointerType *memberPtrType, AlignmentSource *AlignSource = nullptr); RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, ReturnValueSlot ReturnValue); RValue EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, const CXXMethodDecl *MD, ReturnValueSlot ReturnValue); RValue EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, ReturnValueSlot ReturnValue); RValue EmitCUDADevicePrintfCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); RValue EmitBuiltinExpr(const FunctionDecl *FD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); RValue EmitBlockCallExpr(const CallExpr *E, ReturnValueSlot ReturnValue); /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call /// is unhandled by the current target. llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty, const llvm::CmpInst::Predicate Fp, const llvm::CmpInst::Predicate Ip, const llvm::Twine &Name = ""); llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitCommonNeonBuiltinExpr(unsigned BuiltinID, unsigned LLVMIntrinsic, unsigned AltLLVMIntrinsic, const char *NameHint, unsigned Modifier, const CallExpr *E, SmallVectorImpl &Ops, Address PtrOp0, Address PtrOp1); llvm::Function *LookupNeonLLVMIntrinsic(unsigned IntrinsicID, unsigned Modifier, llvm::Type *ArgTy, const CallExpr *E); llvm::Value *EmitNeonCall(llvm::Function *F, SmallVectorImpl &O, const char *name, unsigned shift = 0, bool rightshift = false); llvm::Value *EmitNeonSplat(llvm::Value *V, llvm::Constant *Idx); llvm::Value *EmitNeonShiftVector(llvm::Value *V, llvm::Type *Ty, bool negateForRightShift); llvm::Value *EmitNeonRShiftImm(llvm::Value *Vec, llvm::Value *Amt, llvm::Type *Ty, bool usgn, const char *name); llvm::Value *vectorWrapScalar16(llvm::Value *Op); llvm::Value *EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *BuildVector(ArrayRef Ops); llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E); llvm::Value *EmitObjCProtocolExpr(const ObjCProtocolExpr *E); llvm::Value *EmitObjCStringLiteral(const ObjCStringLiteral *E); llvm::Value *EmitObjCBoxedExpr(const ObjCBoxedExpr *E); llvm::Value *EmitObjCArrayLiteral(const ObjCArrayLiteral *E); llvm::Value *EmitObjCDictionaryLiteral(const ObjCDictionaryLiteral *E); llvm::Value *EmitObjCCollectionLiteral(const Expr *E, const ObjCMethodDecl *MethodWithObjects); llvm::Value *EmitObjCSelectorExpr(const ObjCSelectorExpr *E); RValue EmitObjCMessageExpr(const ObjCMessageExpr *E, ReturnValueSlot Return = ReturnValueSlot()); /// Retrieves the default cleanup kind for an ARC cleanup. /// Except under -fobjc-arc-eh, ARC cleanups are normal-only. CleanupKind getARCCleanupKind() { return CGM.getCodeGenOpts().ObjCAutoRefCountExceptions ? NormalAndEHCleanup : NormalCleanup; } // ARC primitives. void EmitARCInitWeak(Address addr, llvm::Value *value); void EmitARCDestroyWeak(Address addr); llvm::Value *EmitARCLoadWeak(Address addr); llvm::Value *EmitARCLoadWeakRetained(Address addr); llvm::Value *EmitARCStoreWeak(Address addr, llvm::Value *value, bool ignored); void EmitARCCopyWeak(Address dst, Address src); void EmitARCMoveWeak(Address dst, Address src); llvm::Value *EmitARCRetainAutorelease(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainAutoreleaseNonBlock(llvm::Value *value); llvm::Value *EmitARCStoreStrong(LValue lvalue, llvm::Value *value, bool resultIgnored); llvm::Value *EmitARCStoreStrongCall(Address addr, llvm::Value *value, bool resultIgnored); llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory); void EmitARCDestroyStrong(Address addr, ARCPreciseLifetime_t precise); void EmitARCRelease(llvm::Value *value, ARCPreciseLifetime_t precise); llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); llvm::Value *EmitARCRetainAutoreleaseReturnValue(llvm::Value *value); llvm::Value *EmitARCRetainAutoreleasedReturnValue(llvm::Value *value); llvm::Value *EmitARCUnsafeClaimAutoreleasedReturnValue(llvm::Value *value); std::pair EmitARCStoreAutoreleasing(const BinaryOperator *e); std::pair EmitARCStoreStrong(const BinaryOperator *e, bool ignored); std::pair EmitARCStoreUnsafeUnretained(const BinaryOperator *e, bool ignored); llvm::Value *EmitObjCThrowOperand(const Expr *expr); llvm::Value *EmitObjCConsumeObject(QualType T, llvm::Value *Ptr); llvm::Value *EmitObjCExtendObjectLifetime(QualType T, llvm::Value *Ptr); llvm::Value *EmitARCExtendBlockObject(const Expr *expr); llvm::Value *EmitARCReclaimReturnedObject(const Expr *e, bool allowUnsafeClaim); llvm::Value *EmitARCRetainScalarExpr(const Expr *expr); llvm::Value *EmitARCRetainAutoreleaseScalarExpr(const Expr *expr); llvm::Value *EmitARCUnsafeUnretainedScalarExpr(const Expr *expr); void EmitARCIntrinsicUse(ArrayRef values); static Destroyer destroyARCStrongImprecise; static Destroyer destroyARCStrongPrecise; static Destroyer destroyARCWeak; void EmitObjCAutoreleasePoolPop(llvm::Value *Ptr); llvm::Value *EmitObjCAutoreleasePoolPush(); llvm::Value *EmitObjCMRRAutoreleasePoolPush(); void EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr); void EmitObjCMRRAutoreleasePoolPop(llvm::Value *Ptr); /// \brief Emits a reference binding to the passed in expression. RValue EmitReferenceBindingToExpr(const Expr *E); //===--------------------------------------------------------------------===// // Expression Emission //===--------------------------------------------------------------------===// // Expressions are broken into three classes: scalar, complex, aggregate. /// EmitScalarExpr - Emit the computation of the specified expression of LLVM /// scalar type, returning the result. llvm::Value *EmitScalarExpr(const Expr *E , bool IgnoreResultAssign = false); /// Emit a conversion from the specified type to the specified destination /// type, both of which are LLVM scalar types. llvm::Value *EmitScalarConversion(llvm::Value *Src, QualType SrcTy, QualType DstTy, SourceLocation Loc); /// Emit a conversion from the specified complex type to the specified /// destination type, where the destination type is an LLVM scalar type. llvm::Value *EmitComplexToScalarConversion(ComplexPairTy Src, QualType SrcTy, QualType DstTy, SourceLocation Loc); /// EmitAggExpr - Emit the computation of the specified expression /// of aggregate type. The result is computed into the given slot, /// which may be null to indicate that the value is not needed. void EmitAggExpr(const Expr *E, AggValueSlot AS); /// EmitAggExprToLValue - Emit the computation of the specified expression of /// aggregate type into a temporary LValue. LValue EmitAggExprToLValue(const Expr *E); /// EmitExtendGCLifetime - Given a pointer to an Objective-C object, /// make sure it survives garbage collection until this point. void EmitExtendGCLifetime(llvm::Value *object); /// EmitComplexExpr - Emit the computation of the specified expression of /// complex type, returning the result. ComplexPairTy EmitComplexExpr(const Expr *E, bool IgnoreReal = false, bool IgnoreImag = false); /// EmitComplexExprIntoLValue - Emit the given expression of complex /// type and place its result into the specified l-value. void EmitComplexExprIntoLValue(const Expr *E, LValue dest, bool isInit); /// EmitStoreOfComplex - Store a complex number into the specified l-value. void EmitStoreOfComplex(ComplexPairTy V, LValue dest, bool isInit); /// EmitLoadOfComplex - Load a complex number from the specified l-value. ComplexPairTy EmitLoadOfComplex(LValue src, SourceLocation loc); Address emitAddrOfRealComponent(Address complex, QualType complexType); Address emitAddrOfImagComponent(Address complex, QualType complexType); /// AddInitializerToStaticVarDecl - Add the initializer for 'D' to the /// global variable that has already been created for it. If the initializer /// has a different type than GV does, this may free GV and return a different /// one. Otherwise it just returns GV. llvm::GlobalVariable * AddInitializerToStaticVarDecl(const VarDecl &D, llvm::GlobalVariable *GV); /// EmitCXXGlobalVarDeclInit - Create the initializer for a C++ /// variable with global storage. void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::Constant *DeclPtr, bool PerformInit); llvm::Constant *createAtExitStub(const VarDecl &VD, llvm::Constant *Dtor, llvm::Constant *Addr); /// Call atexit() with a function that passes the given argument to /// the given function. void registerGlobalDtorWithAtExit(const VarDecl &D, llvm::Constant *fn, llvm::Constant *addr); /// Emit code in this function to perform a guarded variable /// initialization. Guarded initializations are used when it's not /// possible to prove that an initialization will be done exactly /// once, e.g. with a static local variable or a static data member /// of a class template. void EmitCXXGuardedInit(const VarDecl &D, llvm::GlobalVariable *DeclPtr, bool PerformInit); /// GenerateCXXGlobalInitFunc - Generates code for initializing global /// variables. void GenerateCXXGlobalInitFunc(llvm::Function *Fn, ArrayRef CXXThreadLocals, Address Guard = Address::invalid()); /// GenerateCXXGlobalDtorsFunc - Generates code for destroying global /// variables. void GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, const std::vector > &DtorsAndObjects); void GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, llvm::GlobalVariable *Addr, bool PerformInit); void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest); void EmitSynthesizedCXXCopyCtor(Address Dest, Address Src, const Expr *Exp); void enterFullExpression(const ExprWithCleanups *E) { if (E->getNumObjects() == 0) return; enterNonTrivialFullExpression(E); } void enterNonTrivialFullExpression(const ExprWithCleanups *E); void EmitCXXThrowExpr(const CXXThrowExpr *E, bool KeepInsertionPoint = true); void EmitLambdaExpr(const LambdaExpr *E, AggValueSlot Dest); RValue EmitAtomicExpr(AtomicExpr *E); //===--------------------------------------------------------------------===// // Annotations Emission //===--------------------------------------------------------------------===// /// Emit an annotation call (intrinsic or builtin). llvm::Value *EmitAnnotationCall(llvm::Value *AnnotationFn, llvm::Value *AnnotatedVal, StringRef AnnotationStr, SourceLocation Location); /// Emit local annotations for the local variable V, declared by D. void EmitVarAnnotations(const VarDecl *D, llvm::Value *V); /// Emit field annotations for the given field & value. Returns the /// annotation result. Address EmitFieldAnnotations(const FieldDecl *D, Address V); //===--------------------------------------------------------------------===// // Internal Helpers //===--------------------------------------------------------------------===// /// ContainsLabel - Return true if the statement contains a label in it. If /// this statement is not executed normally, it not containing a label means /// that we can just remove the code. static bool ContainsLabel(const Stmt *S, bool IgnoreCaseStmts = false); /// containsBreak - Return true if the statement contains a break out of it. /// If the statement (recursively) contains a switch or loop with a break /// inside of it, this is fine. static bool containsBreak(const Stmt *S); /// Determine if the given statement might introduce a declaration into the /// current scope, by being a (possibly-labelled) DeclStmt. static bool mightAddDeclToScope(const Stmt *S); /// ConstantFoldsToSimpleInteger - If the specified expression does not fold /// to a constant, or if it does but contains a label, return false. If it /// constant folds return true and set the boolean result in Result. bool ConstantFoldsToSimpleInteger(const Expr *Cond, bool &Result, bool AllowLabels = false); /// ConstantFoldsToSimpleInteger - If the specified expression does not fold /// to a constant, or if it does but contains a label, return false. If it /// constant folds return true and set the folded value. bool ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APSInt &Result, bool AllowLabels = false); /// EmitBranchOnBoolExpr - Emit a branch on a boolean condition (e.g. for an /// if statement) to the specified blocks. Based on the condition, this might /// try to simplify the codegen of the conditional based on the branch. /// TrueCount should be the number of times we expect the condition to /// evaluate to true based on PGO data. void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock, uint64_t TrueCount); /// \brief Emit a description of a type in a format suitable for passing to /// a runtime sanitizer handler. llvm::Constant *EmitCheckTypeDescriptor(QualType T); /// \brief Convert a value into a format suitable for passing to a runtime /// sanitizer handler. llvm::Value *EmitCheckValue(llvm::Value *V); /// \brief Emit a description of a source location in a format suitable for /// passing to a runtime sanitizer handler. llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc); /// \brief Create a basic block that will call a handler function in a /// sanitizer runtime with the provided arguments, and create a conditional /// branch to it. void EmitCheck(ArrayRef> Checked, StringRef CheckName, ArrayRef StaticArgs, ArrayRef DynamicArgs); /// \brief Emit a slow path cross-DSO CFI check which calls __cfi_slowpath /// if Cond if false. void EmitCfiSlowPathCheck(SanitizerMask Kind, llvm::Value *Cond, llvm::ConstantInt *TypeId, llvm::Value *Ptr, ArrayRef StaticArgs); /// \brief Create a basic block that will call the trap intrinsic, and emit a /// conditional branch to it, for the -ftrapv checks. void EmitTrapCheck(llvm::Value *Checked); /// \brief Emit a call to trap or debugtrap and attach function attribute /// "trap-func-name" if specified. llvm::CallInst *EmitTrapCall(llvm::Intrinsic::ID IntrID); /// \brief Emit a cross-DSO CFI failure handling function. void EmitCfiCheckFail(); /// \brief Create a check for a function parameter that may potentially be /// declared as non-null. void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, const FunctionDecl *FD, unsigned ParmNum); /// EmitCallArg - Emit a single call argument. void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); /// EmitDelegateCallArg - We are performing a delegate call; that /// is, the current function is delegating to another one. Produce /// a r-value suitable for passing the given parameter. void EmitDelegateCallArg(CallArgList &args, const VarDecl *param, SourceLocation loc); /// SetFPAccuracy - Set the minimum required accuracy of the given floating /// point operation, expressed as the maximum relative error in ulp. void SetFPAccuracy(llvm::Value *Val, float Accuracy); private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); void deferPlaceholderReplacement(llvm::Instruction *Old, llvm::Value *New); llvm::SmallVector, 4> DeferredReplacements; /// Set the address of a local variable. void setAddrOfLocalVar(const VarDecl *VD, Address Addr) { assert(!LocalDeclMap.count(VD) && "Decl already exists in LocalDeclMap!"); LocalDeclMap.insert({VD, Addr}); } /// ExpandTypeFromArgs - Reconstruct a structure of type \arg Ty /// from function arguments into \arg Dst. See ABIArgInfo::Expand. /// /// \param AI - The first function argument of the expansion. void ExpandTypeFromArgs(QualType Ty, LValue Dst, SmallVectorImpl::iterator &AI); /// ExpandTypeToArgs - Expand an RValue \arg RV, with the LLVM type for \arg /// Ty, into individual arguments on the provided vector \arg IRCallArgs, /// starting at index \arg IRCallArgPos. See ABIArgInfo::Expand. void ExpandTypeToArgs(QualType Ty, RValue RV, llvm::FunctionType *IRFuncTy, SmallVectorImpl &IRCallArgs, unsigned &IRCallArgPos); llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr); llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, LValue InputValue, QualType InputType, std::string &ConstraintStr, SourceLocation Loc); /// \brief Attempts to statically evaluate the object size of E. If that /// fails, emits code to figure the size of E out for us. This is /// pass_object_size aware. llvm::Value *evaluateOrEmitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::IntegerType *ResType); /// \brief Emits the size of E, as required by __builtin_object_size. This /// function is aware of pass_object_size parameters, and will act accordingly /// if E is a parameter with the pass_object_size attribute. llvm::Value *emitBuiltinObjectSize(const Expr *E, unsigned Type, llvm::IntegerType *ResType); public: #ifndef NDEBUG // Determine whether the given argument is an Objective-C method // that may have type parameters in its signature. static bool isObjCMethodWithTypeParams(const ObjCMethodDecl *method) { const DeclContext *dc = method->getDeclContext(); if (const ObjCInterfaceDecl *classDecl= dyn_cast(dc)) { return classDecl->getTypeParamListAsWritten(); } if (const ObjCCategoryDecl *catDecl = dyn_cast(dc)) { return catDecl->getTypeParamList(); } return false; } template static bool isObjCMethodWithTypeParams(const T *) { return false; } #endif /// EmitCallArgs - Emit call arguments for a function. template void EmitCallArgs(CallArgList &Args, const T *CallArgTypeInfo, llvm::iterator_range ArgRange, const FunctionDecl *CalleeDecl = nullptr, unsigned ParamsToSkip = 0) { SmallVector ArgTypes; CallExpr::const_arg_iterator Arg = ArgRange.begin(); assert((ParamsToSkip == 0 || CallArgTypeInfo) && "Can't skip parameters if type info is not provided"); if (CallArgTypeInfo) { #ifndef NDEBUG bool isGenericMethod = isObjCMethodWithTypeParams(CallArgTypeInfo); #endif // First, use the argument types that the type info knows about for (auto I = CallArgTypeInfo->param_type_begin() + ParamsToSkip, E = CallArgTypeInfo->param_type_end(); I != E; ++I, ++Arg) { assert(Arg != ArgRange.end() && "Running over edge of argument list!"); assert((isGenericMethod || ((*I)->isVariablyModifiedType() || (*I).getNonReferenceType()->isObjCRetainableType() || getContext() .getCanonicalType((*I).getNonReferenceType()) .getTypePtr() == getContext() .getCanonicalType((*Arg)->getType()) .getTypePtr())) && "type mismatch in call argument!"); ArgTypes.push_back(*I); } } // Either we've emitted all the call args, or we have a call to variadic // function. assert((Arg == ArgRange.end() || !CallArgTypeInfo || CallArgTypeInfo->isVariadic()) && "Extra arguments in non-variadic function!"); // If we still have any arguments, emit them using the type of the argument. for (auto *A : llvm::make_range(Arg, ArgRange.end())) ArgTypes.push_back(getVarArgType(A)); EmitCallArgs(Args, ArgTypes, ArgRange, CalleeDecl, ParamsToSkip); } void EmitCallArgs(CallArgList &Args, ArrayRef ArgTypes, llvm::iterator_range ArgRange, const FunctionDecl *CalleeDecl = nullptr, unsigned ParamsToSkip = 0); /// EmitPointerWithAlignment - Given an expression with a pointer /// type, emit the value and compute our best estimate of the /// alignment of the pointee. /// /// Note that this function will conservatively fall back on the type /// when it doesn't /// /// \param Source - If non-null, this will be initialized with /// information about the source of the alignment. Note that this /// function will conservatively fall back on the type when it /// doesn't recognize the expression, which means that sometimes /// /// a worst-case One /// reasonable way to use this information is when there's a /// language guarantee that the pointer must be aligned to some /// stricter value, and we're simply trying to ensure that /// sufficiently obvious uses of under-aligned objects don't get /// miscompiled; for example, a placement new into the address of /// a local variable. In such a case, it's quite reasonable to /// just ignore the returned alignment when it isn't from an /// explicit source. Address EmitPointerWithAlignment(const Expr *Addr, AlignmentSource *Source = nullptr); void EmitSanitizerStatReport(llvm::SanitizerStatKind SSK); private: QualType getVarArgType(const Expr *Arg); const TargetCodeGenInfo &getTargetHooks() const { return CGM.getTargetCodeGenInfo(); } void EmitDeclMetadata(); BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType, const AutoVarEmission &emission); void AddObjCARCExceptionMetadata(llvm::Instruction *Inst); llvm::Value *GetValueForARMHint(unsigned BuiltinID); }; /// Helper class with most of the code for saving a value for a /// conditional expression cleanup. struct DominatingLLVMValue { typedef llvm::PointerIntPair saved_type; /// Answer whether the given value needs extra work to be saved. static bool needsSaving(llvm::Value *value) { // If it's not an instruction, we don't need to save. if (!isa(value)) return false; // If it's an instruction in the entry block, we don't need to save. llvm::BasicBlock *block = cast(value)->getParent(); return (block != &block->getParent()->getEntryBlock()); } /// Try to save the given value. static saved_type save(CodeGenFunction &CGF, llvm::Value *value) { if (!needsSaving(value)) return saved_type(value, false); // Otherwise, we need an alloca. auto align = CharUnits::fromQuantity( CGF.CGM.getDataLayout().getPrefTypeAlignment(value->getType())); Address alloca = CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save"); CGF.Builder.CreateStore(value, alloca); return saved_type(alloca.getPointer(), true); } static llvm::Value *restore(CodeGenFunction &CGF, saved_type value) { // If the value says it wasn't saved, trust that it's still dominating. if (!value.getInt()) return value.getPointer(); // Otherwise, it should be an alloca instruction, as set up in save(). auto alloca = cast(value.getPointer()); return CGF.Builder.CreateAlignedLoad(alloca, alloca->getAlignment()); } }; /// A partial specialization of DominatingValue for llvm::Values that /// might be llvm::Instructions. template struct DominatingPointer : DominatingLLVMValue { typedef T *type; static type restore(CodeGenFunction &CGF, saved_type value) { return static_cast(DominatingLLVMValue::restore(CGF, value)); } }; /// A specialization of DominatingValue for Address. template <> struct DominatingValue
{ typedef Address type; struct saved_type { DominatingLLVMValue::saved_type SavedValue; CharUnits Alignment; }; static bool needsSaving(type value) { return DominatingLLVMValue::needsSaving(value.getPointer()); } static saved_type save(CodeGenFunction &CGF, type value) { return { DominatingLLVMValue::save(CGF, value.getPointer()), value.getAlignment() }; } static type restore(CodeGenFunction &CGF, saved_type value) { return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), value.Alignment); } }; /// A specialization of DominatingValue for RValue. template <> struct DominatingValue { typedef RValue type; class saved_type { enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, AggregateAddress, ComplexAddress }; llvm::Value *Value; unsigned K : 3; unsigned Align : 29; saved_type(llvm::Value *v, Kind k, unsigned a = 0) : Value(v), K(k), Align(a) {} public: static bool needsSaving(RValue value); static saved_type save(CodeGenFunction &CGF, RValue value); RValue restore(CodeGenFunction &CGF); // implementations in CGCleanup.cpp }; static bool needsSaving(type value) { return saved_type::needsSaving(value); } static saved_type save(CodeGenFunction &CGF, type value) { return saved_type::save(CGF, value); } static type restore(CodeGenFunction &CGF, saved_type value) { return value.restore(CGF); } }; } // end namespace CodeGen } // end namespace clang #endif diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 657ef7e30cfa..fa2d2107781b 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -1,128 +1,129 @@ set(files adxintrin.h altivec.h ammintrin.h arm_acle.h avx2intrin.h avx512bwintrin.h avx512cdintrin.h avx512dqintrin.h avx512erintrin.h avx512fintrin.h avx512ifmaintrin.h avx512ifmavlintrin.h avx512pfintrin.h avx512vbmiintrin.h avx512vbmivlintrin.h avx512vlbwintrin.h avx512vlcdintrin.h avx512vldqintrin.h avx512vlintrin.h avxintrin.h bmi2intrin.h bmiintrin.h __clang_cuda_cmath.h __clang_cuda_intrinsics.h __clang_cuda_math_forward_declares.h __clang_cuda_runtime_wrapper.h cpuid.h cuda_builtin_vars.h clflushoptintrin.h emmintrin.h f16cintrin.h float.h fma4intrin.h fmaintrin.h fxsrintrin.h htmintrin.h htmxlintrin.h ia32intrin.h immintrin.h intrin.h inttypes.h iso646.h limits.h lzcntintrin.h mm3dnow.h mmintrin.h mm_malloc.h module.modulemap + msa.h mwaitxintrin.h nmmintrin.h opencl-c.h pkuintrin.h pmmintrin.h popcntintrin.h prfchwintrin.h rdseedintrin.h rtmintrin.h s390intrin.h shaintrin.h smmintrin.h stdalign.h stdarg.h stdatomic.h stdbool.h stddef.h __stddef_max_align_t.h stdint.h stdnoreturn.h tbmintrin.h tgmath.h tmmintrin.h unwind.h vadefs.h varargs.h vecintrin.h wmmintrin.h __wmmintrin_aes.h __wmmintrin_pclmul.h x86intrin.h xmmintrin.h xopintrin.h xsavecintrin.h xsaveintrin.h xsaveoptintrin.h xsavesintrin.h xtestintrin.h ) set(output_dir ${LLVM_LIBRARY_OUTPUT_INTDIR}/clang/${CLANG_VERSION}/include) # Generate arm_neon.h clang_tablegen(arm_neon.h -gen-arm-neon SOURCE ${CLANG_SOURCE_DIR}/include/clang/Basic/arm_neon.td) set(out_files) foreach( f ${files} ) set( src ${CMAKE_CURRENT_SOURCE_DIR}/${f} ) set( dst ${output_dir}/${f} ) add_custom_command(OUTPUT ${dst} DEPENDS ${src} COMMAND ${CMAKE_COMMAND} -E copy_if_different ${src} ${dst} COMMENT "Copying clang's ${f}...") list(APPEND out_files ${dst}) endforeach( f ) add_custom_command(OUTPUT ${output_dir}/arm_neon.h DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h ${output_dir}/arm_neon.h COMMENT "Copying clang's arm_neon.h...") list(APPEND out_files ${output_dir}/arm_neon.h) add_custom_target(clang-headers ALL DEPENDS ${out_files}) set_target_properties(clang-headers PROPERTIES FOLDER "Misc") install( FILES ${files} ${CMAKE_CURRENT_BINARY_DIR}/arm_neon.h COMPONENT clang-headers PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ DESTINATION lib${LLVM_LIBDIR_SUFFIX}/clang/${CLANG_VERSION}/include) if (NOT CMAKE_CONFIGURATION_TYPES) # don't add this for IDE's. add_custom_target(install-clang-headers DEPENDS clang-headers COMMAND "${CMAKE_COMMAND}" -DCMAKE_INSTALL_COMPONENT=clang-headers -P "${CMAKE_BINARY_DIR}/cmake_install.cmake") endif() diff --git a/lib/Headers/msa.h b/lib/Headers/msa.h new file mode 100644 index 000000000000..da680f5ca9ee --- /dev/null +++ b/lib/Headers/msa.h @@ -0,0 +1,583 @@ +/*===---- msa.h - MIPS MSA intrinsics --------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef _MSA_H +#define _MSA_H 1 + +#if defined(__mips_msa) +typedef signed char v16i8 __attribute__((vector_size(16), aligned(16))); +typedef signed char v16i8_b __attribute__((vector_size(16), aligned(1))); +typedef unsigned char v16u8 __attribute__((vector_size(16), aligned(16))); +typedef unsigned char v16u8_b __attribute__((vector_size(16), aligned(1))); +typedef short v8i16 __attribute__((vector_size(16), aligned(16))); +typedef short v8i16_h __attribute__((vector_size(16), aligned(2))); +typedef unsigned short v8u16 __attribute__((vector_size(16), aligned(16))); +typedef unsigned short v8u16_h __attribute__((vector_size(16), aligned(2))); +typedef int v4i32 __attribute__((vector_size(16), aligned(16))); +typedef int v4i32_w __attribute__((vector_size(16), aligned(4))); +typedef unsigned int v4u32 __attribute__((vector_size(16), aligned(16))); +typedef unsigned int v4u32_w __attribute__((vector_size(16), aligned(4))); +typedef long long v2i64 __attribute__((vector_size(16), aligned(16))); +typedef long long v2i64_d __attribute__((vector_size(16), aligned(8))); +typedef unsigned long long v2u64 __attribute__((vector_size(16), aligned(16))); +typedef unsigned long long v2u64_d __attribute__((vector_size(16), aligned(8))); +typedef float v4f32 __attribute__((vector_size(16), aligned(16))); +typedef float v4f32_w __attribute__((vector_size(16), aligned(4))); +typedef double v2f64 __attribute__ ((vector_size(16), aligned(16))); +typedef double v2f64_d __attribute__ ((vector_size(16), aligned(8))); + +#define __msa_sll_b __builtin_msa_sll_b +#define __msa_sll_h __builtin_msa_sll_h +#define __msa_sll_w __builtin_msa_sll_w +#define __msa_sll_d __builtin_msa_sll_d +#define __msa_slli_b __builtin_msa_slli_b +#define __msa_slli_h __builtin_msa_slli_h +#define __msa_slli_w __builtin_msa_slli_w +#define __msa_slli_d __builtin_msa_slli_d +#define __msa_sra_b __builtin_msa_sra_b +#define __msa_sra_h __builtin_msa_sra_h +#define __msa_sra_w __builtin_msa_sra_w +#define __msa_sra_d __builtin_msa_sra_d +#define __msa_srai_b __builtin_msa_srai_b +#define __msa_srai_h __builtin_msa_srai_h +#define __msa_srai_w __builtin_msa_srai_w +#define __msa_srai_d __builtin_msa_srai_d +#define __msa_srar_b __builtin_msa_srar_b +#define __msa_srar_h __builtin_msa_srar_h +#define __msa_srar_w __builtin_msa_srar_w +#define __msa_srar_d __builtin_msa_srar_d +#define __msa_srari_b __builtin_msa_srari_b +#define __msa_srari_h __builtin_msa_srari_h +#define __msa_srari_w __builtin_msa_srari_w +#define __msa_srari_d __builtin_msa_srari_d +#define __msa_srl_b __builtin_msa_srl_b +#define __msa_srl_h __builtin_msa_srl_h +#define __msa_srl_w __builtin_msa_srl_w +#define __msa_srl_d __builtin_msa_srl_d +#define __msa_srli_b __builtin_msa_srli_b +#define __msa_srli_h __builtin_msa_srli_h +#define __msa_srli_w __builtin_msa_srli_w +#define __msa_srli_d __builtin_msa_srli_d +#define __msa_srlr_b __builtin_msa_srlr_b +#define __msa_srlr_h __builtin_msa_srlr_h +#define __msa_srlr_w __builtin_msa_srlr_w +#define __msa_srlr_d __builtin_msa_srlr_d +#define __msa_srlri_b __builtin_msa_srlri_b +#define __msa_srlri_h __builtin_msa_srlri_h +#define __msa_srlri_w __builtin_msa_srlri_w +#define __msa_srlri_d __builtin_msa_srlri_d +#define __msa_bclr_b __builtin_msa_bclr_b +#define __msa_bclr_h __builtin_msa_bclr_h +#define __msa_bclr_w __builtin_msa_bclr_w +#define __msa_bclr_d __builtin_msa_bclr_d +#define __msa_bclri_b __builtin_msa_bclri_b +#define __msa_bclri_h __builtin_msa_bclri_h +#define __msa_bclri_w __builtin_msa_bclri_w +#define __msa_bclri_d __builtin_msa_bclri_d +#define __msa_bset_b __builtin_msa_bset_b +#define __msa_bset_h __builtin_msa_bset_h +#define __msa_bset_w __builtin_msa_bset_w +#define __msa_bset_d __builtin_msa_bset_d +#define __msa_bseti_b __builtin_msa_bseti_b +#define __msa_bseti_h __builtin_msa_bseti_h +#define __msa_bseti_w __builtin_msa_bseti_w +#define __msa_bseti_d __builtin_msa_bseti_d +#define __msa_bneg_b __builtin_msa_bneg_b +#define __msa_bneg_h __builtin_msa_bneg_h +#define __msa_bneg_w __builtin_msa_bneg_w +#define __msa_bneg_d __builtin_msa_bneg_d +#define __msa_bnegi_b __builtin_msa_bnegi_b +#define __msa_bnegi_h __builtin_msa_bnegi_h +#define __msa_bnegi_w __builtin_msa_bnegi_w +#define __msa_bnegi_d __builtin_msa_bnegi_d +#define __msa_binsl_b __builtin_msa_binsl_b +#define __msa_binsl_h __builtin_msa_binsl_h +#define __msa_binsl_w __builtin_msa_binsl_w +#define __msa_binsl_d __builtin_msa_binsl_d +#define __msa_binsli_b __builtin_msa_binsli_b +#define __msa_binsli_h __builtin_msa_binsli_h +#define __msa_binsli_w __builtin_msa_binsli_w +#define __msa_binsli_d __builtin_msa_binsli_d +#define __msa_binsr_b __builtin_msa_binsr_b +#define __msa_binsr_h __builtin_msa_binsr_h +#define __msa_binsr_w __builtin_msa_binsr_w +#define __msa_binsr_d __builtin_msa_binsr_d +#define __msa_binsri_b __builtin_msa_binsri_b +#define __msa_binsri_h __builtin_msa_binsri_h +#define __msa_binsri_w __builtin_msa_binsri_w +#define __msa_binsri_d __builtin_msa_binsri_d +#define __msa_addv_b __builtin_msa_addv_b +#define __msa_addv_h __builtin_msa_addv_h +#define __msa_addv_w __builtin_msa_addv_w +#define __msa_addv_d __builtin_msa_addv_d +#define __msa_addvi_b __builtin_msa_addvi_b +#define __msa_addvi_h __builtin_msa_addvi_h +#define __msa_addvi_w __builtin_msa_addvi_w +#define __msa_addvi_d __builtin_msa_addvi_d +#define __msa_subv_b __builtin_msa_subv_b +#define __msa_subv_h __builtin_msa_subv_h +#define __msa_subv_w __builtin_msa_subv_w +#define __msa_subv_d __builtin_msa_subv_d +#define __msa_subvi_b __builtin_msa_subvi_b +#define __msa_subvi_h __builtin_msa_subvi_h +#define __msa_subvi_w __builtin_msa_subvi_w +#define __msa_subvi_d __builtin_msa_subvi_d +#define __msa_max_s_b __builtin_msa_max_s_b +#define __msa_max_s_h __builtin_msa_max_s_h +#define __msa_max_s_w __builtin_msa_max_s_w +#define __msa_max_s_d __builtin_msa_max_s_d +#define __msa_maxi_s_b __builtin_msa_maxi_s_b +#define __msa_maxi_s_h __builtin_msa_maxi_s_h +#define __msa_maxi_s_w __builtin_msa_maxi_s_w +#define __msa_maxi_s_d __builtin_msa_maxi_s_d +#define __msa_max_u_b __builtin_msa_max_u_b +#define __msa_max_u_h __builtin_msa_max_u_h +#define __msa_max_u_w __builtin_msa_max_u_w +#define __msa_max_u_d __builtin_msa_max_u_d +#define __msa_maxi_u_b __builtin_msa_maxi_u_b +#define __msa_maxi_u_h __builtin_msa_maxi_u_h +#define __msa_maxi_u_w __builtin_msa_maxi_u_w +#define __msa_maxi_u_d __builtin_msa_maxi_u_d +#define __msa_min_s_b __builtin_msa_min_s_b +#define __msa_min_s_h __builtin_msa_min_s_h +#define __msa_min_s_w __builtin_msa_min_s_w +#define __msa_min_s_d __builtin_msa_min_s_d +#define __msa_mini_s_b __builtin_msa_mini_s_b +#define __msa_mini_s_h __builtin_msa_mini_s_h +#define __msa_mini_s_w __builtin_msa_mini_s_w +#define __msa_mini_s_d __builtin_msa_mini_s_d +#define __msa_min_u_b __builtin_msa_min_u_b +#define __msa_min_u_h __builtin_msa_min_u_h +#define __msa_min_u_w __builtin_msa_min_u_w +#define __msa_min_u_d __builtin_msa_min_u_d +#define __msa_mini_u_b __builtin_msa_mini_u_b +#define __msa_mini_u_h __builtin_msa_mini_u_h +#define __msa_mini_u_w __builtin_msa_mini_u_w +#define __msa_mini_u_d __builtin_msa_mini_u_d +#define __msa_max_a_b __builtin_msa_max_a_b +#define __msa_max_a_h __builtin_msa_max_a_h +#define __msa_max_a_w __builtin_msa_max_a_w +#define __msa_max_a_d __builtin_msa_max_a_d +#define __msa_min_a_b __builtin_msa_min_a_b +#define __msa_min_a_h __builtin_msa_min_a_h +#define __msa_min_a_w __builtin_msa_min_a_w +#define __msa_min_a_d __builtin_msa_min_a_d +#define __msa_ceq_b __builtin_msa_ceq_b +#define __msa_ceq_h __builtin_msa_ceq_h +#define __msa_ceq_w __builtin_msa_ceq_w +#define __msa_ceq_d __builtin_msa_ceq_d +#define __msa_ceqi_b __builtin_msa_ceqi_b +#define __msa_ceqi_h __builtin_msa_ceqi_h +#define __msa_ceqi_w __builtin_msa_ceqi_w +#define __msa_ceqi_d __builtin_msa_ceqi_d +#define __msa_clt_s_b __builtin_msa_clt_s_b +#define __msa_clt_s_h __builtin_msa_clt_s_h +#define __msa_clt_s_w __builtin_msa_clt_s_w +#define __msa_clt_s_d __builtin_msa_clt_s_d +#define __msa_clti_s_b __builtin_msa_clti_s_b +#define __msa_clti_s_h __builtin_msa_clti_s_h +#define __msa_clti_s_w __builtin_msa_clti_s_w +#define __msa_clti_s_d __builtin_msa_clti_s_d +#define __msa_clt_u_b __builtin_msa_clt_u_b +#define __msa_clt_u_h __builtin_msa_clt_u_h +#define __msa_clt_u_w __builtin_msa_clt_u_w +#define __msa_clt_u_d __builtin_msa_clt_u_d +#define __msa_clti_u_b __builtin_msa_clti_u_b +#define __msa_clti_u_h __builtin_msa_clti_u_h +#define __msa_clti_u_w __builtin_msa_clti_u_w +#define __msa_clti_u_d __builtin_msa_clti_u_d +#define __msa_cle_s_b __builtin_msa_cle_s_b +#define __msa_cle_s_h __builtin_msa_cle_s_h +#define __msa_cle_s_w __builtin_msa_cle_s_w +#define __msa_cle_s_d __builtin_msa_cle_s_d +#define __msa_clei_s_b __builtin_msa_clei_s_b +#define __msa_clei_s_h __builtin_msa_clei_s_h +#define __msa_clei_s_w __builtin_msa_clei_s_w +#define __msa_clei_s_d __builtin_msa_clei_s_d +#define __msa_cle_u_b __builtin_msa_cle_u_b +#define __msa_cle_u_h __builtin_msa_cle_u_h +#define __msa_cle_u_w __builtin_msa_cle_u_w +#define __msa_cle_u_d __builtin_msa_cle_u_d +#define __msa_clei_u_b __builtin_msa_clei_u_b +#define __msa_clei_u_h __builtin_msa_clei_u_h +#define __msa_clei_u_w __builtin_msa_clei_u_w +#define __msa_clei_u_d __builtin_msa_clei_u_d +#define __msa_ld_b __builtin_msa_ld_b +#define __msa_ld_h __builtin_msa_ld_h +#define __msa_ld_w __builtin_msa_ld_w +#define __msa_ld_d __builtin_msa_ld_d +#define __msa_st_b __builtin_msa_st_b +#define __msa_st_h __builtin_msa_st_h +#define __msa_st_w __builtin_msa_st_w +#define __msa_st_d __builtin_msa_st_d +#define __msa_sat_s_b __builtin_msa_sat_s_b +#define __msa_sat_s_h __builtin_msa_sat_s_h +#define __msa_sat_s_w __builtin_msa_sat_s_w +#define __msa_sat_s_d __builtin_msa_sat_s_d +#define __msa_sat_u_b __builtin_msa_sat_u_b +#define __msa_sat_u_h __builtin_msa_sat_u_h +#define __msa_sat_u_w __builtin_msa_sat_u_w +#define __msa_sat_u_d __builtin_msa_sat_u_d +#define __msa_add_a_b __builtin_msa_add_a_b +#define __msa_add_a_h __builtin_msa_add_a_h +#define __msa_add_a_w __builtin_msa_add_a_w +#define __msa_add_a_d __builtin_msa_add_a_d +#define __msa_adds_a_b __builtin_msa_adds_a_b +#define __msa_adds_a_h __builtin_msa_adds_a_h +#define __msa_adds_a_w __builtin_msa_adds_a_w +#define __msa_adds_a_d __builtin_msa_adds_a_d +#define __msa_adds_s_b __builtin_msa_adds_s_b +#define __msa_adds_s_h __builtin_msa_adds_s_h +#define __msa_adds_s_w __builtin_msa_adds_s_w +#define __msa_adds_s_d __builtin_msa_adds_s_d +#define __msa_adds_u_b __builtin_msa_adds_u_b +#define __msa_adds_u_h __builtin_msa_adds_u_h +#define __msa_adds_u_w __builtin_msa_adds_u_w +#define __msa_adds_u_d __builtin_msa_adds_u_d +#define __msa_ave_s_b __builtin_msa_ave_s_b +#define __msa_ave_s_h __builtin_msa_ave_s_h +#define __msa_ave_s_w __builtin_msa_ave_s_w +#define __msa_ave_s_d __builtin_msa_ave_s_d +#define __msa_ave_u_b __builtin_msa_ave_u_b +#define __msa_ave_u_h __builtin_msa_ave_u_h +#define __msa_ave_u_w __builtin_msa_ave_u_w +#define __msa_ave_u_d __builtin_msa_ave_u_d +#define __msa_aver_s_b __builtin_msa_aver_s_b +#define __msa_aver_s_h __builtin_msa_aver_s_h +#define __msa_aver_s_w __builtin_msa_aver_s_w +#define __msa_aver_s_d __builtin_msa_aver_s_d +#define __msa_aver_u_b __builtin_msa_aver_u_b +#define __msa_aver_u_h __builtin_msa_aver_u_h +#define __msa_aver_u_w __builtin_msa_aver_u_w +#define __msa_aver_u_d __builtin_msa_aver_u_d +#define __msa_subs_s_b __builtin_msa_subs_s_b +#define __msa_subs_s_h __builtin_msa_subs_s_h +#define __msa_subs_s_w __builtin_msa_subs_s_w +#define __msa_subs_s_d __builtin_msa_subs_s_d +#define __msa_subs_u_b __builtin_msa_subs_u_b +#define __msa_subs_u_h __builtin_msa_subs_u_h +#define __msa_subs_u_w __builtin_msa_subs_u_w +#define __msa_subs_u_d __builtin_msa_subs_u_d +#define __msa_subsuu_s_b __builtin_msa_subsuu_s_b +#define __msa_subsuu_s_h __builtin_msa_subsuu_s_h +#define __msa_subsuu_s_w __builtin_msa_subsuu_s_w +#define __msa_subsuu_s_d __builtin_msa_subsuu_s_d +#define __msa_subsus_u_b __builtin_msa_subsus_u_b +#define __msa_subsus_u_h __builtin_msa_subsus_u_h +#define __msa_subsus_u_w __builtin_msa_subsus_u_w +#define __msa_subsus_u_d __builtin_msa_subsus_u_d +#define __msa_asub_s_b __builtin_msa_asub_s_b +#define __msa_asub_s_h __builtin_msa_asub_s_h +#define __msa_asub_s_w __builtin_msa_asub_s_w +#define __msa_asub_s_d __builtin_msa_asub_s_d +#define __msa_asub_u_b __builtin_msa_asub_u_b +#define __msa_asub_u_h __builtin_msa_asub_u_h +#define __msa_asub_u_w __builtin_msa_asub_u_w +#define __msa_asub_u_d __builtin_msa_asub_u_d +#define __msa_mulv_b __builtin_msa_mulv_b +#define __msa_mulv_h __builtin_msa_mulv_h +#define __msa_mulv_w __builtin_msa_mulv_w +#define __msa_mulv_d __builtin_msa_mulv_d +#define __msa_maddv_b __builtin_msa_maddv_b +#define __msa_maddv_h __builtin_msa_maddv_h +#define __msa_maddv_w __builtin_msa_maddv_w +#define __msa_maddv_d __builtin_msa_maddv_d +#define __msa_msubv_b __builtin_msa_msubv_b +#define __msa_msubv_h __builtin_msa_msubv_h +#define __msa_msubv_w __builtin_msa_msubv_w +#define __msa_msubv_d __builtin_msa_msubv_d +#define __msa_div_s_b __builtin_msa_div_s_b +#define __msa_div_s_h __builtin_msa_div_s_h +#define __msa_div_s_w __builtin_msa_div_s_w +#define __msa_div_s_d __builtin_msa_div_s_d +#define __msa_div_u_b __builtin_msa_div_u_b +#define __msa_div_u_h __builtin_msa_div_u_h +#define __msa_div_u_w __builtin_msa_div_u_w +#define __msa_div_u_d __builtin_msa_div_u_d +#define __msa_hadd_s_h __builtin_msa_hadd_s_h +#define __msa_hadd_s_w __builtin_msa_hadd_s_w +#define __msa_hadd_s_d __builtin_msa_hadd_s_d +#define __msa_hadd_u_h __builtin_msa_hadd_u_h +#define __msa_hadd_u_w __builtin_msa_hadd_u_w +#define __msa_hadd_u_d __builtin_msa_hadd_u_d +#define __msa_hsub_s_h __builtin_msa_hsub_s_h +#define __msa_hsub_s_w __builtin_msa_hsub_s_w +#define __msa_hsub_s_d __builtin_msa_hsub_s_d +#define __msa_hsub_u_h __builtin_msa_hsub_u_h +#define __msa_hsub_u_w __builtin_msa_hsub_u_w +#define __msa_hsub_u_d __builtin_msa_hsub_u_d +#define __msa_mod_s_b __builtin_msa_mod_s_b +#define __msa_mod_s_h __builtin_msa_mod_s_h +#define __msa_mod_s_w __builtin_msa_mod_s_w +#define __msa_mod_s_d __builtin_msa_mod_s_d +#define __msa_mod_u_b __builtin_msa_mod_u_b +#define __msa_mod_u_h __builtin_msa_mod_u_h +#define __msa_mod_u_w __builtin_msa_mod_u_w +#define __msa_mod_u_d __builtin_msa_mod_u_d +#define __msa_dotp_s_h __builtin_msa_dotp_s_h +#define __msa_dotp_s_w __builtin_msa_dotp_s_w +#define __msa_dotp_s_d __builtin_msa_dotp_s_d +#define __msa_dotp_u_h __builtin_msa_dotp_u_h +#define __msa_dotp_u_w __builtin_msa_dotp_u_w +#define __msa_dotp_u_d __builtin_msa_dotp_u_d +#define __msa_dpadd_s_h __builtin_msa_dpadd_s_h +#define __msa_dpadd_s_w __builtin_msa_dpadd_s_w +#define __msa_dpadd_s_d __builtin_msa_dpadd_s_d +#define __msa_dpadd_u_h __builtin_msa_dpadd_u_h +#define __msa_dpadd_u_w __builtin_msa_dpadd_u_w +#define __msa_dpadd_u_d __builtin_msa_dpadd_u_d +#define __msa_dpsub_s_h __builtin_msa_dpsub_s_h +#define __msa_dpsub_s_w __builtin_msa_dpsub_s_w +#define __msa_dpsub_s_d __builtin_msa_dpsub_s_d +#define __msa_dpsub_u_h __builtin_msa_dpsub_u_h +#define __msa_dpsub_u_w __builtin_msa_dpsub_u_w +#define __msa_dpsub_u_d __builtin_msa_dpsub_u_d +#define __msa_sld_b __builtin_msa_sld_b +#define __msa_sld_h __builtin_msa_sld_h +#define __msa_sld_w __builtin_msa_sld_w +#define __msa_sld_d __builtin_msa_sld_d +#define __msa_sldi_b __builtin_msa_sldi_b +#define __msa_sldi_h __builtin_msa_sldi_h +#define __msa_sldi_w __builtin_msa_sldi_w +#define __msa_sldi_d __builtin_msa_sldi_d +#define __msa_splat_b __builtin_msa_splat_b +#define __msa_splat_h __builtin_msa_splat_h +#define __msa_splat_w __builtin_msa_splat_w +#define __msa_splat_d __builtin_msa_splat_d +#define __msa_splati_b __builtin_msa_splati_b +#define __msa_splati_h __builtin_msa_splati_h +#define __msa_splati_w __builtin_msa_splati_w +#define __msa_splati_d __builtin_msa_splati_d +#define __msa_pckev_b __builtin_msa_pckev_b +#define __msa_pckev_h __builtin_msa_pckev_h +#define __msa_pckev_w __builtin_msa_pckev_w +#define __msa_pckev_d __builtin_msa_pckev_d +#define __msa_pckod_b __builtin_msa_pckod_b +#define __msa_pckod_h __builtin_msa_pckod_h +#define __msa_pckod_w __builtin_msa_pckod_w +#define __msa_pckod_d __builtin_msa_pckod_d +#define __msa_ilvl_b __builtin_msa_ilvl_b +#define __msa_ilvl_h __builtin_msa_ilvl_h +#define __msa_ilvl_w __builtin_msa_ilvl_w +#define __msa_ilvl_d __builtin_msa_ilvl_d +#define __msa_ilvr_b __builtin_msa_ilvr_b +#define __msa_ilvr_h __builtin_msa_ilvr_h +#define __msa_ilvr_w __builtin_msa_ilvr_w +#define __msa_ilvr_d __builtin_msa_ilvr_d +#define __msa_ilvev_b __builtin_msa_ilvev_b +#define __msa_ilvev_h __builtin_msa_ilvev_h +#define __msa_ilvev_w __builtin_msa_ilvev_w +#define __msa_ilvev_d __builtin_msa_ilvev_d +#define __msa_ilvod_b __builtin_msa_ilvod_b +#define __msa_ilvod_h __builtin_msa_ilvod_h +#define __msa_ilvod_w __builtin_msa_ilvod_w +#define __msa_ilvod_d __builtin_msa_ilvod_d +#define __msa_vshf_b __builtin_msa_vshf_b +#define __msa_vshf_h __builtin_msa_vshf_h +#define __msa_vshf_w __builtin_msa_vshf_w +#define __msa_vshf_d __builtin_msa_vshf_d +#define __msa_and_v __builtin_msa_and_v +#define __msa_andi_b __builtin_msa_andi_b +#define __msa_or_v __builtin_msa_or_v +#define __msa_ori_b __builtin_msa_ori_b +#define __msa_nor_v __builtin_msa_nor_v +#define __msa_nori_b __builtin_msa_nori_b +#define __msa_xor_v __builtin_msa_xor_v +#define __msa_xori_b __builtin_msa_xori_b +#define __msa_bmnz_v __builtin_msa_bmnz_v +#define __msa_bmnzi_b __builtin_msa_bmnzi_b +#define __msa_bmz_v __builtin_msa_bmz_v +#define __msa_bmzi_b __builtin_msa_bmzi_b +#define __msa_bsel_v __builtin_msa_bsel_v +#define __msa_bseli_b __builtin_msa_bseli_b +#define __msa_shf_b __builtin_msa_shf_b +#define __msa_shf_h __builtin_msa_shf_h +#define __msa_shf_w __builtin_msa_shf_w +#define __msa_test_bnz_v __builtin_msa_bnz_v +#define __msa_test_bz_v __builtin_msa_bz_v +#define __msa_fill_b __builtin_msa_fill_b +#define __msa_fill_h __builtin_msa_fill_h +#define __msa_fill_w __builtin_msa_fill_w +#define __msa_fill_d __builtin_msa_fill_d +#define __msa_pcnt_b __builtin_msa_pcnt_b +#define __msa_pcnt_h __builtin_msa_pcnt_h +#define __msa_pcnt_w __builtin_msa_pcnt_w +#define __msa_pcnt_d __builtin_msa_pcnt_d +#define __msa_nloc_b __builtin_msa_nloc_b +#define __msa_nloc_h __builtin_msa_nloc_h +#define __msa_nloc_w __builtin_msa_nloc_w +#define __msa_nloc_d __builtin_msa_nloc_d +#define __msa_nlzc_b __builtin_msa_nlzc_b +#define __msa_nlzc_h __builtin_msa_nlzc_h +#define __msa_nlzc_w __builtin_msa_nlzc_w +#define __msa_nlzc_d __builtin_msa_nlzc_d +#define __msa_copy_s_b __builtin_msa_copy_s_b +#define __msa_copy_s_h __builtin_msa_copy_s_h +#define __msa_copy_s_w __builtin_msa_copy_s_w +#define __msa_copy_s_d __builtin_msa_copy_s_d +#define __msa_copy_u_b __builtin_msa_copy_u_b +#define __msa_copy_u_h __builtin_msa_copy_u_h +#define __msa_copy_u_w __builtin_msa_copy_u_w +#define __msa_copy_u_d __builtin_msa_copy_u_d +#define __msa_insert_b __builtin_msa_insert_b +#define __msa_insert_h __builtin_msa_insert_h +#define __msa_insert_w __builtin_msa_insert_w +#define __msa_insert_d __builtin_msa_insert_d +#define __msa_insve_b __builtin_msa_insve_b +#define __msa_insve_h __builtin_msa_insve_h +#define __msa_insve_w __builtin_msa_insve_w +#define __msa_insve_d __builtin_msa_insve_d +#define __msa_test_bnz_b __builtin_msa_bnz_b +#define __msa_test_bnz_h __builtin_msa_bnz_h +#define __msa_test_bnz_w __builtin_msa_bnz_w +#define __msa_test_bnz_d __builtin_msa_bnz_d +#define __msa_test_bz_b __builtin_msa_bz_b +#define __msa_test_bz_h __builtin_msa_bz_h +#define __msa_test_bz_w __builtin_msa_bz_w +#define __msa_test_bz_d __builtin_msa_bz_d +#define __msa_ldi_b __builtin_msa_ldi_b +#define __msa_ldi_h __builtin_msa_ldi_h +#define __msa_ldi_w __builtin_msa_ldi_w +#define __msa_ldi_d __builtin_msa_ldi_d +#define __msa_fcaf_w __builtin_msa_fcaf_w +#define __msa_fcaf_d __builtin_msa_fcaf_d +#define __msa_fcor_w __builtin_msa_fcor_w +#define __msa_fcor_d __builtin_msa_fcor_d +#define __msa_fcun_w __builtin_msa_fcun_w +#define __msa_fcun_d __builtin_msa_fcun_d +#define __msa_fcune_w __builtin_msa_fcune_w +#define __msa_fcune_d __builtin_msa_fcune_d +#define __msa_fcueq_w __builtin_msa_fcueq_w +#define __msa_fcueq_d __builtin_msa_fcueq_d +#define __msa_fceq_w __builtin_msa_fceq_w +#define __msa_fceq_d __builtin_msa_fceq_d +#define __msa_fcne_w __builtin_msa_fcne_w +#define __msa_fcne_d __builtin_msa_fcne_d +#define __msa_fclt_w __builtin_msa_fclt_w +#define __msa_fclt_d __builtin_msa_fclt_d +#define __msa_fcult_w __builtin_msa_fcult_w +#define __msa_fcult_d __builtin_msa_fcult_d +#define __msa_fcle_w __builtin_msa_fcle_w +#define __msa_fcle_d __builtin_msa_fcle_d +#define __msa_fcule_w __builtin_msa_fcule_w +#define __msa_fcule_d __builtin_msa_fcule_d +#define __msa_fsaf_w __builtin_msa_fsaf_w +#define __msa_fsaf_d __builtin_msa_fsaf_d +#define __msa_fsor_w __builtin_msa_fsor_w +#define __msa_fsor_d __builtin_msa_fsor_d +#define __msa_fsun_w __builtin_msa_fsun_w +#define __msa_fsun_d __builtin_msa_fsun_d +#define __msa_fsune_w __builtin_msa_fsune_w +#define __msa_fsune_d __builtin_msa_fsune_d +#define __msa_fsueq_w __builtin_msa_fsueq_w +#define __msa_fsueq_d __builtin_msa_fsueq_d +#define __msa_fseq_w __builtin_msa_fseq_w +#define __msa_fseq_d __builtin_msa_fseq_d +#define __msa_fsne_w __builtin_msa_fsne_w +#define __msa_fsne_d __builtin_msa_fsne_d +#define __msa_fslt_w __builtin_msa_fslt_w +#define __msa_fslt_d __builtin_msa_fslt_d +#define __msa_fsult_w __builtin_msa_fsult_w +#define __msa_fsult_d __builtin_msa_fsult_d +#define __msa_fsle_w __builtin_msa_fsle_w +#define __msa_fsle_d __builtin_msa_fsle_d +#define __msa_fsule_w __builtin_msa_fsule_w +#define __msa_fsule_d __builtin_msa_fsule_d +#define __msa_fadd_w __builtin_msa_fadd_w +#define __msa_fadd_d __builtin_msa_fadd_d +#define __msa_fsub_w __builtin_msa_fsub_w +#define __msa_fsub_d __builtin_msa_fsub_d +#define __msa_fmul_w __builtin_msa_fmul_w +#define __msa_fmul_d __builtin_msa_fmul_d +#define __msa_fdiv_w __builtin_msa_fdiv_w +#define __msa_fdiv_d __builtin_msa_fdiv_d +#define __msa_fmadd_w __builtin_msa_fmadd_w +#define __msa_fmadd_d __builtin_msa_fmadd_d +#define __msa_fmsub_w __builtin_msa_fmsub_w +#define __msa_fmsub_d __builtin_msa_fmsub_d +#define __msa_fexp2_w __builtin_msa_fexp2_w +#define __msa_fexp2_d __builtin_msa_fexp2_d +#define __msa_fexdo_h __builtin_msa_fexdo_h +#define __msa_fexdo_w __builtin_msa_fexdo_w +#define __msa_ftq_h __builtin_msa_ftq_h +#define __msa_ftq_w __builtin_msa_ftq_w +#define __msa_fmin_w __builtin_msa_fmin_w +#define __msa_fmin_d __builtin_msa_fmin_d +#define __msa_fmin_a_w __builtin_msa_fmin_a_w +#define __msa_fmin_a_d __builtin_msa_fmin_a_d +#define __msa_fmax_w __builtin_msa_fmax_w +#define __msa_fmax_d __builtin_msa_fmax_d +#define __msa_fmax_a_w __builtin_msa_fmax_a_w +#define __msa_fmax_a_d __builtin_msa_fmax_a_d +#define __msa_mul_q_h __builtin_msa_mul_q_h +#define __msa_mul_q_w __builtin_msa_mul_q_w +#define __msa_mulr_q_h __builtin_msa_mulr_q_h +#define __msa_mulr_q_w __builtin_msa_mulr_q_w +#define __msa_madd_q_h __builtin_msa_madd_q_h +#define __msa_madd_q_w __builtin_msa_madd_q_w +#define __msa_maddr_q_h __builtin_msa_maddr_q_h +#define __msa_maddr_q_w __builtin_msa_maddr_q_w +#define __msa_msub_q_h __builtin_msa_msub_q_h +#define __msa_msub_q_w __builtin_msa_msub_q_w +#define __msa_msubr_q_h __builtin_msa_msubr_q_h +#define __msa_msubr_q_w __builtin_msa_msubr_q_w +#define __msa_fclass_w __builtin_msa_fclass_w +#define __msa_fclass_d __builtin_msa_fclass_d +#define __msa_fsqrt_w __builtin_msa_fsqrt_w +#define __msa_fsqrt_d __builtin_msa_fsqrt_d +#define __msa_frcp_w __builtin_msa_frcp_w +#define __msa_frcp_d __builtin_msa_frcp_d +#define __msa_frint_w __builtin_msa_frint_w +#define __msa_frint_d __builtin_msa_frint_d +#define __msa_frsqrt_w __builtin_msa_frsqrt_w +#define __msa_frsqrt_d __builtin_msa_frsqrt_d +#define __msa_flog2_w __builtin_msa_flog2_w +#define __msa_flog2_d __builtin_msa_flog2_d +#define __msa_fexupl_w __builtin_msa_fexupl_w +#define __msa_fexupl_d __builtin_msa_fexupl_d +#define __msa_fexupr_w __builtin_msa_fexupr_w +#define __msa_fexupr_d __builtin_msa_fexupr_d +#define __msa_ffql_w __builtin_msa_ffql_w +#define __msa_ffql_d __builtin_msa_ffql_d +#define __msa_ffqr_w __builtin_msa_ffqr_w +#define __msa_ffqr_d __builtin_msa_ffqr_d +#define __msa_ftint_s_w __builtin_msa_ftint_s_w +#define __msa_ftint_s_d __builtin_msa_ftint_s_d +#define __msa_ftint_u_w __builtin_msa_ftint_u_w +#define __msa_ftint_u_d __builtin_msa_ftint_u_d +#define __msa_ftrunc_s_w __builtin_msa_ftrunc_s_w +#define __msa_ftrunc_s_d __builtin_msa_ftrunc_s_d +#define __msa_ftrunc_u_w __builtin_msa_ftrunc_u_w +#define __msa_ftrunc_u_d __builtin_msa_ftrunc_u_d +#define __msa_ffint_s_w __builtin_msa_ffint_s_w +#define __msa_ffint_s_d __builtin_msa_ffint_s_d +#define __msa_ffint_u_w __builtin_msa_ffint_u_w +#define __msa_ffint_u_d __builtin_msa_ffint_u_d +#define __msa_cfcmsa __builtin_msa_cfcmsa +#define __msa_move_v __builtin_msa_move_v +#define __msa_cast_to_vector_float __builtin_msa_cast_to_vector_float +#define __msa_cast_to_vector_double __builtin_msa_cast_to_vector_double +#define __msa_cast_to_scalar_float __builtin_msa_cast_to_scalar_float +#define __msa_cast_to_scalar_double __builtin_msa_cast_to_scalar_double +#endif /* defined(__mips_msa) */ +#endif /* _MSA_H */ diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index b8e7ede2716c..7f7dbe8873d4 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -1,10942 +1,11132 @@ //===--- SemaChecking.cpp - Extra Semantic Checking -----------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements extra semantic analysis beyond what is enforced // by the C type system. // //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/EvaluatedExprVisitor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/Analysis/Analyses/FormatString.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" // TODO: Extract static functions to fix layering. #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/Format.h" #include "llvm/Support/Locale.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" #include using namespace clang; using namespace sema; SourceLocation Sema::getLocationOfStringLiteralByte(const StringLiteral *SL, unsigned ByteNo) const { return SL->getLocationOfByte(ByteNo, getSourceManager(), LangOpts, Context.getTargetInfo()); } /// Checks that a call expression's argument count is the desired number. /// This is useful when doing custom type-checking. Returns true on error. static bool checkArgCount(Sema &S, CallExpr *call, unsigned desiredArgCount) { unsigned argCount = call->getNumArgs(); if (argCount == desiredArgCount) return false; if (argCount < desiredArgCount) return S.Diag(call->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 /*function call*/ << desiredArgCount << argCount << call->getSourceRange(); // Highlight all the excess arguments. SourceRange range(call->getArg(desiredArgCount)->getLocStart(), call->getArg(argCount - 1)->getLocEnd()); return S.Diag(range.getBegin(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << desiredArgCount << argCount << call->getArg(1)->getSourceRange(); } /// Check that the first argument to __builtin_annotation is an integer /// and the second argument is a non-wide string literal. static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 2)) return true; // First argument should be an integer. Expr *ValArg = TheCall->getArg(0); QualType Ty = ValArg->getType(); if (!Ty->isIntegerType()) { S.Diag(ValArg->getLocStart(), diag::err_builtin_annotation_first_arg) << ValArg->getSourceRange(); return true; } // Second argument should be a constant string. Expr *StrArg = TheCall->getArg(1)->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast(StrArg); if (!Literal || !Literal->isAscii()) { S.Diag(StrArg->getLocStart(), diag::err_builtin_annotation_second_arg) << StrArg->getSourceRange(); return true; } TheCall->setType(Ty); return false; } /// Check that the argument to __builtin_addressof is a glvalue, and set the /// result type to the corresponding pointer type. static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; ExprResult Arg(TheCall->getArg(0)); QualType ResultType = S.CheckAddressOfOperand(Arg, TheCall->getLocStart()); if (ResultType.isNull()) return true; TheCall->setArg(0, Arg.get()); TheCall->setType(ResultType); return false; } static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 3)) return true; // First two arguments should be integers. for (unsigned I = 0; I < 2; ++I) { Expr *Arg = TheCall->getArg(I); QualType Ty = Arg->getType(); if (!Ty->isIntegerType()) { S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_int) << Ty << Arg->getSourceRange(); return true; } } // Third argument should be a pointer to a non-const integer. // IRGen correctly handles volatile, restrict, and address spaces, and // the other qualifiers aren't possible. { Expr *Arg = TheCall->getArg(2); QualType Ty = Arg->getType(); const auto *PtrTy = Ty->getAs(); if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && !PtrTy->getPointeeType().isConstQualified())) { S.Diag(Arg->getLocStart(), diag::err_overflow_builtin_must_be_ptr_int) << Ty << Arg->getSourceRange(); return true; } } return false; } static void SemaBuiltinMemChkCall(Sema &S, FunctionDecl *FDecl, CallExpr *TheCall, unsigned SizeIdx, unsigned DstSizeIdx) { if (TheCall->getNumArgs() <= SizeIdx || TheCall->getNumArgs() <= DstSizeIdx) return; const Expr *SizeArg = TheCall->getArg(SizeIdx); const Expr *DstSizeArg = TheCall->getArg(DstSizeIdx); llvm::APSInt Size, DstSize; // find out if both sizes are known at compile time if (!SizeArg->EvaluateAsInt(Size, S.Context) || !DstSizeArg->EvaluateAsInt(DstSize, S.Context)) return; if (Size.ule(DstSize)) return; // confirmed overflow so generate the diagnostic. IdentifierInfo *FnName = FDecl->getIdentifier(); SourceLocation SL = TheCall->getLocStart(); SourceRange SR = TheCall->getSourceRange(); S.Diag(SL, diag::warn_memcpy_chk_overflow) << SR << FnName; } static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; SourceLocation BuiltinLoc = BuiltinCall->getLocStart(); Expr *Builtin = BuiltinCall->getCallee()->IgnoreImpCasts(); Expr *Call = BuiltinCall->getArg(0); Expr *Chain = BuiltinCall->getArg(1); if (Call->getStmtClass() != Stmt::CallExprClass) { S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_not_call) << Call->getSourceRange(); return true; } auto CE = cast(Call); if (CE->getCallee()->getType()->isBlockPointerType()) { S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_block_call) << Call->getSourceRange(); return true; } const Decl *TargetDecl = CE->getCalleeDecl(); if (const FunctionDecl *FD = dyn_cast_or_null(TargetDecl)) if (FD->getBuiltinID()) { S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_builtin_call) << Call->getSourceRange(); return true; } if (isa(CE->getCallee()->IgnoreParens())) { S.Diag(BuiltinLoc, diag::err_first_argument_to_cwsc_pdtor_call) << Call->getSourceRange(); return true; } ExprResult ChainResult = S.UsualUnaryConversions(Chain); if (ChainResult.isInvalid()) return true; if (!ChainResult.get()->getType()->isPointerType()) { S.Diag(BuiltinLoc, diag::err_second_argument_to_cwsc_not_pointer) << Chain->getSourceRange(); return true; } QualType ReturnTy = CE->getCallReturnType(S.Context); QualType ArgTys[2] = { ReturnTy, ChainResult.get()->getType() }; QualType BuiltinTy = S.Context.getFunctionType( ReturnTy, ArgTys, FunctionProtoType::ExtProtoInfo()); QualType BuiltinPtrTy = S.Context.getPointerType(BuiltinTy); Builtin = S.ImpCastExprToType(Builtin, BuiltinPtrTy, CK_BuiltinFnToFnPtr).get(); BuiltinCall->setType(CE->getType()); BuiltinCall->setValueKind(CE->getValueKind()); BuiltinCall->setObjectKind(CE->getObjectKind()); BuiltinCall->setCallee(Builtin); BuiltinCall->setArg(1, ChainResult.get()); return false; } static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, Scope::ScopeFlags NeededScopeFlags, unsigned DiagID) { // Scopes aren't available during instantiation. Fortunately, builtin // functions cannot be template args so they cannot be formed through template // instantiation. Therefore checking once during the parse is sufficient. if (!SemaRef.ActiveTemplateInstantiations.empty()) return false; Scope *S = SemaRef.getCurScope(); while (S && !S->isSEHExceptScope()) S = S->getParent(); if (!S || !(S->getFlags() & NeededScopeFlags)) { auto *DRE = cast(TheCall->getCallee()->IgnoreParenCasts()); SemaRef.Diag(TheCall->getExprLoc(), DiagID) << DRE->getDecl()->getIdentifier(); return true; } return false; } static inline bool isBlockPointer(Expr *Arg) { return Arg->getType()->isBlockPointerType(); } /// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local /// void*, which is a requirement of device side enqueue. static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { const BlockPointerType *BPT = cast(BlockArg->getType().getCanonicalType()); ArrayRef Params = BPT->getPointeeType()->getAs()->getParamTypes(); unsigned ArgCounter = 0; bool IllegalParams = false; // Iterate through the block parameters until either one is found that is not // a local void*, or the block is valid. for (ArrayRef::iterator I = Params.begin(), E = Params.end(); I != E; ++I, ++ArgCounter) { if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || (*I)->getPointeeType().getQualifiers().getAddressSpace() != LangAS::opencl_local) { // Get the location of the error. If a block literal has been passed // (BlockExpr) then we can point straight to the offending argument, // else we just point to the variable reference. SourceLocation ErrorLoc; if (isa(BlockArg)) { BlockDecl *BD = cast(BlockArg)->getBlockDecl(); ErrorLoc = BD->getParamDecl(ArgCounter)->getLocStart(); } else if (isa(BlockArg)) { ErrorLoc = cast(BlockArg)->getLocStart(); } S.Diag(ErrorLoc, diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); IllegalParams = true; } } return IllegalParams; } /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; Expr *BlockArg = TheCall->getArg(0); if (!isBlockPointer(BlockArg)) { S.Diag(BlockArg->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << "block"; return true; } return checkOpenCLBlockArgs(S, BlockArg); } static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, unsigned Start, unsigned End); /// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all /// 'local void*' parameter of passed block. static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, Expr *BlockArg, unsigned NumNonVarArgs) { const BlockPointerType *BPT = cast(BlockArg->getType().getCanonicalType()); unsigned NumBlockParams = BPT->getPointeeType()->getAs()->getNumParams(); unsigned TotalNumArgs = TheCall->getNumArgs(); // For each argument passed to the block, a corresponding uint needs to // be passed to describe the size of the local memory. if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { S.Diag(TheCall->getLocStart(), diag::err_opencl_enqueue_kernel_local_size_args); return true; } // Check that the sizes of the local memory are specified by integers. return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, TotalNumArgs - 1); } /// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different /// overload formats specified in Table 6.13.17.1. /// int enqueue_kernel(queue_t queue, /// kernel_enqueue_flags_t flags, /// const ndrange_t ndrange, /// void (^block)(void)) /// int enqueue_kernel(queue_t queue, /// kernel_enqueue_flags_t flags, /// const ndrange_t ndrange, /// uint num_events_in_wait_list, /// clk_event_t *event_wait_list, /// clk_event_t *event_ret, /// void (^block)(void)) /// int enqueue_kernel(queue_t queue, /// kernel_enqueue_flags_t flags, /// const ndrange_t ndrange, /// void (^block)(local void*, ...), /// uint size0, ...) /// int enqueue_kernel(queue_t queue, /// kernel_enqueue_flags_t flags, /// const ndrange_t ndrange, /// uint num_events_in_wait_list, /// clk_event_t *event_wait_list, /// clk_event_t *event_ret, /// void (^block)(local void*, ...), /// uint size0, ...) static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs < 4) { S.Diag(TheCall->getLocStart(), diag::err_typecheck_call_too_few_args); return true; } Expr *Arg0 = TheCall->getArg(0); Expr *Arg1 = TheCall->getArg(1); Expr *Arg2 = TheCall->getArg(2); Expr *Arg3 = TheCall->getArg(3); // First argument always needs to be a queue_t type. if (!Arg0->getType()->isQueueT()) { S.Diag(TheCall->getArg(0)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.OCLQueueTy; return true; } // Second argument always needs to be a kernel_enqueue_flags_t enum value. if (!Arg1->getType()->isIntegerType()) { S.Diag(TheCall->getArg(1)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << "'kernel_enqueue_flags_t' (i.e. uint)"; return true; } // Third argument is always an ndrange_t type. if (!Arg2->getType()->isNDRangeT()) { S.Diag(TheCall->getArg(2)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.OCLNDRangeTy; return true; } // With four arguments, there is only one form that the function could be // called in: no events and no variable arguments. if (NumArgs == 4) { // check that the last argument is the right block type. if (!isBlockPointer(Arg3)) { S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << "block"; return true; } // we have a block type, check the prototype const BlockPointerType *BPT = cast(Arg3->getType().getCanonicalType()); if (BPT->getPointeeType()->getAs()->getNumParams() > 0) { S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_blocks_no_args); return true; } return false; } // we can have block + varargs. if (isBlockPointer(Arg3)) return (checkOpenCLBlockArgs(S, Arg3) || checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg3, 4)); // last two cases with either exactly 7 args or 7 args and varargs. if (NumArgs >= 7) { // check common block argument. Expr *Arg6 = TheCall->getArg(6); if (!isBlockPointer(Arg6)) { S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << "block"; return true; } if (checkOpenCLBlockArgs(S, Arg6)) return true; // Forth argument has to be any integer type. if (!Arg3->getType()->isIntegerType()) { S.Diag(TheCall->getArg(3)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << "integer"; return true; } // check remaining common arguments. Expr *Arg4 = TheCall->getArg(4); Expr *Arg5 = TheCall->getArg(5); // Fith argument is always passed as pointers to clk_event_t. if (!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { S.Diag(TheCall->getArg(4)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } // Sixth argument is always passed as pointers to clk_event_t. if (!(Arg5->getType()->isPointerType() && Arg5->getType()->getPointeeType()->isClkEventT())) { S.Diag(TheCall->getArg(5)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } if (NumArgs == 7) return false; return checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg6, 7); } // None of the specific case has been detected, give generic error S.Diag(TheCall->getLocStart(), diag::err_opencl_enqueue_kernel_incorrect_args); return true; } /// Returns OpenCL access qual. static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { return D->getAttr(); } /// Returns true if pipe element type is different from the pointer. static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { const Expr *Arg0 = Call->getArg(0); // First argument type should always be pipe. if (!Arg0->getType()->isPipeType()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) << Call->getDirectCallee() << Arg0->getSourceRange(); return true; } OpenCLAccessAttr *AccessQual = getOpenCLArgAccess(cast(Arg0)->getDecl()); // Validates the access qualifier is compatible with the call. // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be // read_only and write_only, and assumed to be read_only if no qualifier is // specified. switch (Call->getDirectCallee()->getBuiltinID()) { case Builtin::BIread_pipe: case Builtin::BIreserve_read_pipe: case Builtin::BIcommit_read_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIsub_group_commit_read_pipe: if (!(!AccessQual || AccessQual->isReadOnly())) { S.Diag(Arg0->getLocStart(), diag::err_opencl_builtin_pipe_invalid_access_modifier) << "read_only" << Arg0->getSourceRange(); return true; } break; case Builtin::BIwrite_pipe: case Builtin::BIreserve_write_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_reserve_write_pipe: case Builtin::BIsub_group_reserve_write_pipe: case Builtin::BIwork_group_commit_write_pipe: case Builtin::BIsub_group_commit_write_pipe: if (!(AccessQual && AccessQual->isWriteOnly())) { S.Diag(Arg0->getLocStart(), diag::err_opencl_builtin_pipe_invalid_access_modifier) << "write_only" << Arg0->getSourceRange(); return true; } break; default: break; } return false; } /// Returns true if pipe element type is different from the pointer. static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { const Expr *Arg0 = Call->getArg(0); const Expr *ArgIdx = Call->getArg(Idx); const PipeType *PipeTy = cast(Arg0->getType()); const QualType EltTy = PipeTy->getElementType(); const PointerType *ArgTy = ArgIdx->getType()->getAs(); // The Idx argument should be a pointer and the type of the pointer and // the type of pipe element should also be the same. if (!ArgTy || !S.Context.hasSameType( EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) << Call->getDirectCallee() << S.Context.getPointerType(EltTy) << ArgIdx->getType() << ArgIdx->getSourceRange(); return true; } return false; } // \brief Performs semantic analysis for the read/write_pipe call. // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // OpenCL v2.0 s6.13.16.2 - The built-in read/write // functions have two forms. switch (Call->getNumArgs()) { case 2: { if (checkOpenCLPipeArg(S, Call)) return true; // The call with 2 arguments should be // read/write_pipe(pipe T, T*). // Check packet type T. if (checkOpenCLPipePacketType(S, Call, 1)) return true; } break; case 4: { if (checkOpenCLPipeArg(S, Call)) return true; // The call with 4 arguments should be // read/write_pipe(pipe T, reserve_id_t, uint, T*). // Check reserve_id_t. if (!Call->getArg(1)->getType()->isReserveIDT()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) << Call->getDirectCallee() << S.Context.OCLReserveIDTy << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); return true; } // Check the index. const Expr *Arg2 = Call->getArg(2); if (!Arg2->getType()->isIntegerType() && !Arg2->getType()->isUnsignedIntegerType()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) << Call->getDirectCallee() << S.Context.UnsignedIntTy << Arg2->getType() << Arg2->getSourceRange(); return true; } // Check packet type T. if (checkOpenCLPipePacketType(S, Call, 3)) return true; } break; default: S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num) << Call->getDirectCallee() << Call->getSourceRange(); return true; } return false; } // \brief Performs a semantic analysis on the {work_group_/sub_group_ // /_}reserve_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; if (checkOpenCLPipeArg(S, Call)) return true; // Check the reserve size. if (!Call->getArg(1)->getType()->isIntegerType() && !Call->getArg(1)->getType()->isUnsignedIntegerType()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) << Call->getDirectCallee() << S.Context.UnsignedIntTy << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); return true; } return false; } // \brief Performs a semantic analysis on {work_group_/sub_group_ // /_}commit_{read/write}_pipe // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; if (checkOpenCLPipeArg(S, Call)) return true; // Check reserve_id_t. if (!Call->getArg(1)->getType()->isReserveIDT()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) << Call->getDirectCallee() << S.Context.OCLReserveIDTy << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); return true; } return false; } // \brief Performs a semantic analysis on the call to built-in Pipe // Query Functions. // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 1)) return true; if (!Call->getArg(0)->getType()->isPipeType()) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); return true; } return false; } // \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. // \brief Performs semantic analysis for the to_global/local/private call. // \param S Reference to the semantic analyzer. // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { if (Call->getNumArgs() != 1) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num) << Call->getDirectCallee() << Call->getSourceRange(); return true; } auto RT = Call->getArg(0)->getType(); if (!RT->isPointerType() || RT->getPointeeType() .getAddressSpace() == LangAS::opencl_constant) { S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg) << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); return true; } RT = RT->getPointeeType(); auto Qual = RT.getQualifiers(); switch (BuiltinID) { case Builtin::BIto_global: Qual.setAddressSpace(LangAS::opencl_global); break; case Builtin::BIto_local: Qual.setAddressSpace(LangAS::opencl_local); break; default: Qual.removeAddressSpace(); } Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( RT.getUnqualifiedType(), Qual))); return false; } ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { ExprResult TheCallResult(TheCall); // Find out if any arguments are required to be integer constant expressions. unsigned ICEArguments = 0; ASTContext::GetBuiltinTypeError Error; Context.GetBuiltinType(BuiltinID, Error, &ICEArguments); if (Error != ASTContext::GE_None) ICEArguments = 0; // Don't diagnose previously diagnosed errors. // If any arguments are required to be ICE's, check and diagnose. for (unsigned ArgNo = 0; ICEArguments != 0; ++ArgNo) { // Skip arguments not required to be ICE's. if ((ICEArguments & (1 << ArgNo)) == 0) continue; llvm::APSInt Result; if (SemaBuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && "Wrong # arguments to builtin CFStringMakeConstantString"); if (CheckObjCString(TheCall->getArg(0))) return ExprError(); break; case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: if (SemaBuiltinVAStart(TheCall)) return ExprError(); break; case Builtin::BI__va_start: { switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::thumb: if (SemaBuiltinVAStartARM(TheCall)) return ExprError(); break; default: if (SemaBuiltinVAStart(TheCall)) return ExprError(); break; } break; } case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: if (SemaBuiltinUnorderedCompare(TheCall)) return ExprError(); break; case Builtin::BI__builtin_fpclassify: if (SemaBuiltinFPClassification(TheCall, 6)) return ExprError(); break; case Builtin::BI__builtin_isfinite: case Builtin::BI__builtin_isinf: case Builtin::BI__builtin_isinf_sign: case Builtin::BI__builtin_isnan: case Builtin::BI__builtin_isnormal: if (SemaBuiltinFPClassification(TheCall, 1)) return ExprError(); break; case Builtin::BI__builtin_shufflevector: return SemaBuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since // SemaBuiltinShuffleVector guts it, but then doesn't release it. case Builtin::BI__builtin_prefetch: if (SemaBuiltinPrefetch(TheCall)) return ExprError(); break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: if (SemaBuiltinAssume(TheCall)) return ExprError(); break; case Builtin::BI__builtin_assume_aligned: if (SemaBuiltinAssumeAligned(TheCall)) return ExprError(); break; case Builtin::BI__builtin_object_size: if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); break; case Builtin::BI__builtin_longjmp: if (SemaBuiltinLongjmp(TheCall)) return ExprError(); break; case Builtin::BI__builtin_setjmp: if (SemaBuiltinSetjmp(TheCall)) return ExprError(); break; case Builtin::BI_setjmp: case Builtin::BI_setjmpex: if (checkArgCount(*this, TheCall, 1)) return true; break; case Builtin::BI__builtin_classify_type: if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); break; case Builtin::BI__builtin_constant_p: if (checkArgCount(*this, TheCall, 1)) return true; TheCall->setType(Context.IntTy); break; case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: case Builtin::BI__sync_fetch_and_add_4: case Builtin::BI__sync_fetch_and_add_8: case Builtin::BI__sync_fetch_and_add_16: case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_sub_1: case Builtin::BI__sync_fetch_and_sub_2: case Builtin::BI__sync_fetch_and_sub_4: case Builtin::BI__sync_fetch_and_sub_8: case Builtin::BI__sync_fetch_and_sub_16: case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_or_1: case Builtin::BI__sync_fetch_and_or_2: case Builtin::BI__sync_fetch_and_or_4: case Builtin::BI__sync_fetch_and_or_8: case Builtin::BI__sync_fetch_and_or_16: case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_and_1: case Builtin::BI__sync_fetch_and_and_2: case Builtin::BI__sync_fetch_and_and_4: case Builtin::BI__sync_fetch_and_and_8: case Builtin::BI__sync_fetch_and_and_16: case Builtin::BI__sync_fetch_and_xor: case Builtin::BI__sync_fetch_and_xor_1: case Builtin::BI__sync_fetch_and_xor_2: case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_fetch_and_nand_1: case Builtin::BI__sync_fetch_and_nand_2: case Builtin::BI__sync_fetch_and_nand_4: case Builtin::BI__sync_fetch_and_nand_8: case Builtin::BI__sync_fetch_and_nand_16: case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_and_and_fetch_1: case Builtin::BI__sync_and_and_fetch_2: case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_or_and_fetch_1: case Builtin::BI__sync_or_and_fetch_2: case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: case Builtin::BI__sync_xor_and_fetch: case Builtin::BI__sync_xor_and_fetch_1: case Builtin::BI__sync_xor_and_fetch_2: case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_nand_and_fetch_1: case Builtin::BI__sync_nand_and_fetch_2: case Builtin::BI__sync_nand_and_fetch_4: case Builtin::BI__sync_nand_and_fetch_8: case Builtin::BI__sync_nand_and_fetch_16: case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: case Builtin::BI__sync_val_compare_and_swap_16: case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap_1: case Builtin::BI__sync_bool_compare_and_swap_2: case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: case Builtin::BI__sync_bool_compare_and_swap_16: case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: case Builtin::BI__sync_lock_release: case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: case Builtin::BI__sync_lock_release_4: case Builtin::BI__sync_lock_release_8: case Builtin::BI__sync_lock_release_16: case Builtin::BI__sync_swap: case Builtin::BI__sync_swap_1: case Builtin::BI__sync_swap_2: case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: return SemaBuiltinAtomicOverloaded(TheCallResult); case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: return SemaBuiltinNontemporalOverloaded(TheCallResult); #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ case Builtin::BI##ID: \ return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.def" case Builtin::BI__builtin_annotation: if (SemaBuiltinAnnotation(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_addressof: if (SemaBuiltinAddressof(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: if (SemaBuiltinOverflow(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_operator_new: case Builtin::BI__builtin_operator_delete: if (!getLangOpts().CPlusPlus) { Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) << (BuiltinID == Builtin::BI__builtin_operator_new ? "__builtin_operator_new" : "__builtin_operator_delete") << "C++"; return ExprError(); } // CodeGen assumes it can find the global new and delete to call, // so ensure that they are declared. DeclareGlobalNewDelete(); break; // check secure string manipulation functions where overflows // are detectable at compile time case Builtin::BI__builtin___memcpy_chk: case Builtin::BI__builtin___memmove_chk: case Builtin::BI__builtin___memset_chk: case Builtin::BI__builtin___strlcat_chk: case Builtin::BI__builtin___strlcpy_chk: case Builtin::BI__builtin___strncat_chk: case Builtin::BI__builtin___strncpy_chk: case Builtin::BI__builtin___stpncpy_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 2, 3); break; case Builtin::BI__builtin___memccpy_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 3, 4); break; case Builtin::BI__builtin___snprintf_chk: case Builtin::BI__builtin___vsnprintf_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); break; case Builtin::BI__builtin_call_with_static_chain: if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; case Builtin::BI__exception_code: case Builtin::BI_exception_code: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, diag::err_seh___except_block)) return ExprError(); break; case Builtin::BI__exception_info: case Builtin::BI_exception_info: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, diag::err_seh___except_filter)) return ExprError(); break; case Builtin::BI__GetExceptionInfo: if (checkArgCount(*this, TheCall, 1)) return ExprError(); if (CheckCXXThrowOperand( TheCall->getLocStart(), Context.getExceptionObjectType(FDecl->getParamDecl(0)->getType()), TheCall)) return ExprError(); TheCall->setType(Context.VoidPtrTy); break; // OpenCL v2.0, s6.13.16 - Pipe functions case Builtin::BIread_pipe: case Builtin::BIwrite_pipe: // Since those two functions are declared with var args, we need a semantic // check for the argument. if (SemaBuiltinRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: if (SemaBuiltinReserveRWPipe(*this, TheCall)) return ExprError(); // Since return type of reserve_read/write_pipe built-in function is // reserve_id_t, which is not defined in the builtin def file , we used int // as return type and need to override the return type of these functions. TheCall->setType(Context.OCLReserveIDTy); break; case Builtin::BIcommit_read_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIwork_group_commit_write_pipe: case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: if (SemaBuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: case Builtin::BIget_pipe_max_packets: if (SemaBuiltinPipePackets(*this, TheCall)) return ExprError(); break; case Builtin::BIto_global: case Builtin::BIto_local: case Builtin::BIto_private: if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) return ExprError(); break; // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. case Builtin::BIenqueue_kernel: if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall)) return ExprError(); break; case Builtin::BIget_kernel_work_group_size: case Builtin::BIget_kernel_preferred_work_group_size_multiple: if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); } // Since the target specific builtins for each arch overlap, only check those // of the arch we are compiling for. if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) { switch (Context.getTargetInfo().getTriple().getArch()) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; case llvm::Triple::aarch64: case llvm::Triple::aarch64_be: if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; case llvm::Triple::systemz: if (CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; case llvm::Triple::x86: case llvm::Triple::x86_64: if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); break; default: break; } } return TheCallResult; } // Get the valid immediate range for the specified NEON type code. static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { NeonTypeFlags Type(t); int IsQuad = ForceQuad ? true : Type.isQuad(); switch (Type.getEltType()) { case NeonTypeFlags::Int8: case NeonTypeFlags::Poly8: return shift ? 7 : (8 << IsQuad) - 1; case NeonTypeFlags::Int16: case NeonTypeFlags::Poly16: return shift ? 15 : (4 << IsQuad) - 1; case NeonTypeFlags::Int32: return shift ? 31 : (2 << IsQuad) - 1; case NeonTypeFlags::Int64: case NeonTypeFlags::Poly64: return shift ? 63 : (1 << IsQuad) - 1; case NeonTypeFlags::Poly128: return shift ? 127 : (1 << IsQuad) - 1; case NeonTypeFlags::Float16: assert(!shift && "cannot shift float types!"); return (4 << IsQuad) - 1; case NeonTypeFlags::Float32: assert(!shift && "cannot shift float types!"); return (2 << IsQuad) - 1; case NeonTypeFlags::Float64: assert(!shift && "cannot shift float types!"); return (1 << IsQuad) - 1; } llvm_unreachable("Invalid NeonTypeFlag!"); } /// getNeonEltType - Return the QualType corresponding to the elements of /// the vector type specified by the NeonTypeFlags. This is used to check /// the pointer arguments for Neon load/store intrinsics. static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, bool IsPolyUnsigned, bool IsInt64Long) { switch (Flags.getEltType()) { case NeonTypeFlags::Int8: return Flags.isUnsigned() ? Context.UnsignedCharTy : Context.SignedCharTy; case NeonTypeFlags::Int16: return Flags.isUnsigned() ? Context.UnsignedShortTy : Context.ShortTy; case NeonTypeFlags::Int32: return Flags.isUnsigned() ? Context.UnsignedIntTy : Context.IntTy; case NeonTypeFlags::Int64: if (IsInt64Long) return Flags.isUnsigned() ? Context.UnsignedLongTy : Context.LongTy; else return Flags.isUnsigned() ? Context.UnsignedLongLongTy : Context.LongLongTy; case NeonTypeFlags::Poly8: return IsPolyUnsigned ? Context.UnsignedCharTy : Context.SignedCharTy; case NeonTypeFlags::Poly16: return IsPolyUnsigned ? Context.UnsignedShortTy : Context.ShortTy; case NeonTypeFlags::Poly64: if (IsInt64Long) return Context.UnsignedLongTy; else return Context.UnsignedLongLongTy; case NeonTypeFlags::Poly128: break; case NeonTypeFlags::Float16: return Context.HalfTy; case NeonTypeFlags::Float32: return Context.FloatTy; case NeonTypeFlags::Float64: return Context.DoubleTy; } llvm_unreachable("Invalid NeonTypeFlag!"); } bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { llvm::APSInt Result; uint64_t mask = 0; unsigned TV = 0; int PtrArgNum = -1; bool HasConstPtr = false; switch (BuiltinID) { #define GET_NEON_OVERLOAD_CHECK #include "clang/Basic/arm_neon.inc" #undef GET_NEON_OVERLOAD_CHECK } // For NEON intrinsics which are overloaded on vector element type, validate // the immediate which specifies which variant to emit. unsigned ImmArg = TheCall->getNumArgs()-1; if (mask) { if (SemaBuiltinConstantArg(TheCall, ImmArg, Result)) return true; TV = Result.getLimitedValue(64); if ((TV > 63) || (mask & (1ULL << TV)) == 0) return Diag(TheCall->getLocStart(), diag::err_invalid_neon_type_code) << TheCall->getArg(ImmArg)->getSourceRange(); } if (PtrArgNum >= 0) { // Check that pointer arguments have the specified type. Expr *Arg = TheCall->getArg(PtrArgNum); if (ImplicitCastExpr *ICE = dyn_cast(Arg)) Arg = ICE->getSubExpr(); ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg); QualType RHSTy = RHS.get()->getType(); llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); bool IsPolyUnsigned = Arch == llvm::Triple::aarch64; bool IsInt64Long = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong; QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long); if (HasConstPtr) EltTy = EltTy.withConst(); QualType LHSTy = Context.getPointerType(EltTy); AssignConvertType ConvTy; ConvTy = CheckSingleAssignmentConstraints(LHSTy, RHS); if (RHS.isInvalid()) return true; if (DiagnoseAssignmentResult(ConvTy, Arg->getLocStart(), LHSTy, RHSTy, RHS.get(), AA_Assigning)) return true; } // For NEON intrinsics which take an immediate value as part of the // instruction, range check them here. unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; #define GET_NEON_IMMEDIATE_CHECK #include "clang/Basic/arm_neon.inc" #undef GET_NEON_IMMEDIATE_CHECK } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || BuiltinID == ARM::BI__builtin_arm_stlex || BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || BuiltinID == AArch64::BI__builtin_arm_stlex) && "unexpected ARM builtin"); bool IsLdrex = BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex; DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); // Ensure that we have the proper number of arguments. if (checkArgCount(*this, TheCall, IsLdrex ? 1 : 2)) return true; // Inspect the pointer argument of the atomic builtin. This should always be // a pointer type, whose element is an integral scalar or pointer type. // Because it is a pointer type, we don't have to worry about any implicit // casts here. Expr *PointerArg = TheCall->getArg(IsLdrex ? 0 : 1); ExprResult PointerArgRes = DefaultFunctionArrayLvalueConversion(PointerArg); if (PointerArgRes.isInvalid()) return true; PointerArg = PointerArgRes.get(); const PointerType *pointerType = PointerArg->getType()->getAs(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) << PointerArg->getType() << PointerArg->getSourceRange(); return true; } // ldrex takes a "const volatile T*" and strex takes a "volatile T*". Our next // task is to insert the appropriate casts into the AST. First work out just // what the appropriate type is. QualType ValType = pointerType->getPointeeType(); QualType AddrType = ValType.getUnqualifiedType().withVolatile(); if (IsLdrex) AddrType.addConst(); // Issue a warning if the cast is dodgy. CastKind CastNeeded = CK_NoOp; if (!AddrType.isAtLeastAsQualifiedAs(ValType)) { CastNeeded = CK_BitCast; Diag(DRE->getLocStart(), diag::ext_typecheck_convert_discards_qualifiers) << PointerArg->getType() << Context.getPointerType(AddrType) << AA_Passing << PointerArg->getSourceRange(); } // Finally, do the cast and replace the argument with the corrected version. AddrType = Context.getPointerType(AddrType); PointerArgRes = ImpCastExprToType(PointerArg, AddrType, CastNeeded); if (PointerArgRes.isInvalid()) return true; PointerArg = PointerArgRes.get(); TheCall->setArg(IsLdrex ? 0 : 1, PointerArg); // In general, we allow ints, floats and pointers to be loaded and stored. if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType() && !ValType->isFloatingType()) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intfltptr) << PointerArg->getType() << PointerArg->getSourceRange(); return true; } // But ARM doesn't have instructions to deal with 128-bit versions. if (Context.getTypeSize(ValType) > MaxWidth) { assert(MaxWidth == 64 && "Diagnostic unexpectedly inaccurate"); Diag(DRE->getLocStart(), diag::err_atomic_exclusive_builtin_pointer_size) << PointerArg->getType() << PointerArg->getSourceRange(); return true; } switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: // okay break; case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: case Qualifiers::OCL_Autoreleasing: Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) << ValType << PointerArg->getSourceRange(); return true; } if (IsLdrex) { TheCall->setType(ValType); return false; } // Initialize the argument to be stored. ExprResult ValArg = TheCall->getArg(0); InitializedEntity Entity = InitializedEntity::InitializeParameter( Context, ValType, /*consume*/ false); ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); if (ValArg.isInvalid()) return true; TheCall->setArg(0, ValArg.get()); // __builtin_arm_strex always returns an int. It's marked as such in the .def, // but the custom checker bypasses all default analysis. TheCall->setType(Context.IntTy); return false; } bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { llvm::APSInt Result; if (BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || BuiltinID == ARM::BI__builtin_arm_stlex) { return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 64); } if (BuiltinID == ARM::BI__builtin_arm_prefetch) { return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); } if (BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); if (BuiltinID == ARM::BI__builtin_arm_rsr || BuiltinID == ARM::BI__builtin_arm_rsrp || BuiltinID == ARM::BI__builtin_arm_wsr || BuiltinID == ARM::BI__builtin_arm_wsrp) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; // For intrinsics which take an immediate value as part of the instruction, // range check them here. unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; case ARM::BI__builtin_arm_ssat: i = 1; l = 1; u = 31; break; case ARM::BI__builtin_arm_usat: i = 1; u = 31; break; case ARM::BI__builtin_arm_vcvtr_f: case ARM::BI__builtin_arm_vcvtr_d: i = 1; u = 1; break; case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: case ARM::BI__builtin_arm_isb: case ARM::BI__builtin_arm_dbg: l = 0; u = 15; break; } // FIXME: VFP Intrinsics should error if VFP not present. return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { llvm::APSInt Result; if (BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || BuiltinID == AArch64::BI__builtin_arm_stlex) { return CheckARMBuiltinExclusiveCall(BuiltinID, TheCall, 128); } if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 2) || SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); } if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || BuiltinID == AArch64::BI__builtin_arm_wsrp) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; // For intrinsics which take an immediate value as part of the instruction, // range check them here. unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; case AArch64::BI__builtin_arm_dmb: case AArch64::BI__builtin_arm_dsb: case AArch64::BI__builtin_arm_isb: l = 0; u = 15; break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the +// intrinsic is correct. The switch statement is ordered by DSP, MSA. The +// ordering for DSP is unspecified. MSA is ordered by the data format used +// by the underlying instruction i.e., df/m, df/n and then by size. +// +// FIXME: The size tests here should instead be tablegen'd along with the +// definitions from include/clang/Basic/BuiltinsMips.def. +// FIXME: GCC is strict on signedness for some of these intrinsics, we should +// be too. bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; + unsigned i = 0, l = 0, u = 0, m = 0; switch (BuiltinID) { default: return false; case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break; case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break; case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break; case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; - } - - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + // MSA instrinsics. Instructions (which the intrinsics maps to) which use the + // df/m field. + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_bclri_b: + case Mips::BI__builtin_msa_bnegi_b: + case Mips::BI__builtin_msa_bseti_b: + case Mips::BI__builtin_msa_sat_s_b: + case Mips::BI__builtin_msa_sat_u_b: + case Mips::BI__builtin_msa_slli_b: + case Mips::BI__builtin_msa_srai_b: + case Mips::BI__builtin_msa_srari_b: + case Mips::BI__builtin_msa_srli_b: + case Mips::BI__builtin_msa_srlri_b: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_binsli_b: + case Mips::BI__builtin_msa_binsri_b: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_bclri_h: + case Mips::BI__builtin_msa_bnegi_h: + case Mips::BI__builtin_msa_bseti_h: + case Mips::BI__builtin_msa_sat_s_h: + case Mips::BI__builtin_msa_sat_u_h: + case Mips::BI__builtin_msa_slli_h: + case Mips::BI__builtin_msa_srai_h: + case Mips::BI__builtin_msa_srari_h: + case Mips::BI__builtin_msa_srli_h: + case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_binsli_h: + case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 5 bit immedate. + // The first block of intrinsics actually have an unsigned 5 bit field, + // not a df/n field. + case Mips::BI__builtin_msa_clei_u_b: + case Mips::BI__builtin_msa_clei_u_h: + case Mips::BI__builtin_msa_clei_u_w: + case Mips::BI__builtin_msa_clei_u_d: + case Mips::BI__builtin_msa_clti_u_b: + case Mips::BI__builtin_msa_clti_u_h: + case Mips::BI__builtin_msa_clti_u_w: + case Mips::BI__builtin_msa_clti_u_d: + case Mips::BI__builtin_msa_maxi_u_b: + case Mips::BI__builtin_msa_maxi_u_h: + case Mips::BI__builtin_msa_maxi_u_w: + case Mips::BI__builtin_msa_maxi_u_d: + case Mips::BI__builtin_msa_mini_u_b: + case Mips::BI__builtin_msa_mini_u_h: + case Mips::BI__builtin_msa_mini_u_w: + case Mips::BI__builtin_msa_mini_u_d: + case Mips::BI__builtin_msa_addvi_b: + case Mips::BI__builtin_msa_addvi_h: + case Mips::BI__builtin_msa_addvi_w: + case Mips::BI__builtin_msa_addvi_d: + case Mips::BI__builtin_msa_bclri_w: + case Mips::BI__builtin_msa_bnegi_w: + case Mips::BI__builtin_msa_bseti_w: + case Mips::BI__builtin_msa_sat_s_w: + case Mips::BI__builtin_msa_sat_u_w: + case Mips::BI__builtin_msa_slli_w: + case Mips::BI__builtin_msa_srai_w: + case Mips::BI__builtin_msa_srari_w: + case Mips::BI__builtin_msa_srli_w: + case Mips::BI__builtin_msa_srlri_w: + case Mips::BI__builtin_msa_subvi_b: + case Mips::BI__builtin_msa_subvi_h: + case Mips::BI__builtin_msa_subvi_w: + case Mips::BI__builtin_msa_subvi_d: i = 1; l = 0; u = 31; break; + case Mips::BI__builtin_msa_binsli_w: + case Mips::BI__builtin_msa_binsri_w: i = 2; l = 0; u = 31; break; + // These intrinsics take an unsigned 6 bit immediate. + case Mips::BI__builtin_msa_bclri_d: + case Mips::BI__builtin_msa_bnegi_d: + case Mips::BI__builtin_msa_bseti_d: + case Mips::BI__builtin_msa_sat_s_d: + case Mips::BI__builtin_msa_sat_u_d: + case Mips::BI__builtin_msa_slli_d: + case Mips::BI__builtin_msa_srai_d: + case Mips::BI__builtin_msa_srari_d: + case Mips::BI__builtin_msa_srli_d: + case Mips::BI__builtin_msa_srlri_d: i = 1; l = 0; u = 63; break; + case Mips::BI__builtin_msa_binsli_d: + case Mips::BI__builtin_msa_binsri_d: i = 2; l = 0; u = 63; break; + // These intrinsics take a signed 5 bit immediate. + case Mips::BI__builtin_msa_ceqi_b: + case Mips::BI__builtin_msa_ceqi_h: + case Mips::BI__builtin_msa_ceqi_w: + case Mips::BI__builtin_msa_ceqi_d: + case Mips::BI__builtin_msa_clti_s_b: + case Mips::BI__builtin_msa_clti_s_h: + case Mips::BI__builtin_msa_clti_s_w: + case Mips::BI__builtin_msa_clti_s_d: + case Mips::BI__builtin_msa_clei_s_b: + case Mips::BI__builtin_msa_clei_s_h: + case Mips::BI__builtin_msa_clei_s_w: + case Mips::BI__builtin_msa_clei_s_d: + case Mips::BI__builtin_msa_maxi_s_b: + case Mips::BI__builtin_msa_maxi_s_h: + case Mips::BI__builtin_msa_maxi_s_w: + case Mips::BI__builtin_msa_maxi_s_d: + case Mips::BI__builtin_msa_mini_s_b: + case Mips::BI__builtin_msa_mini_s_h: + case Mips::BI__builtin_msa_mini_s_w: + case Mips::BI__builtin_msa_mini_s_d: i = 1; l = -16; u = 15; break; + // These intrinsics take an unsigned 8 bit immediate. + case Mips::BI__builtin_msa_andi_b: + case Mips::BI__builtin_msa_nori_b: + case Mips::BI__builtin_msa_ori_b: + case Mips::BI__builtin_msa_shf_b: + case Mips::BI__builtin_msa_shf_h: + case Mips::BI__builtin_msa_shf_w: + case Mips::BI__builtin_msa_xori_b: i = 1; l = 0; u = 255; break; + case Mips::BI__builtin_msa_bseli_b: + case Mips::BI__builtin_msa_bmnzi_b: + case Mips::BI__builtin_msa_bmzi_b: i = 2; l = 0; u = 255; break; + // df/n format + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_copy_s_b: + case Mips::BI__builtin_msa_copy_u_b: + case Mips::BI__builtin_msa_insve_b: + case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_sld_b: + case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_copy_s_h: + case Mips::BI__builtin_msa_copy_u_h: + case Mips::BI__builtin_msa_insve_h: + case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_sld_h: + case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 2 bit immediate. + case Mips::BI__builtin_msa_copy_s_w: + case Mips::BI__builtin_msa_copy_u_w: + case Mips::BI__builtin_msa_insve_w: + case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break; + case Mips::BI__builtin_msa_sld_w: + case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break; + // These intrinsics take an unsigned 1 bit immediate. + case Mips::BI__builtin_msa_copy_s_d: + case Mips::BI__builtin_msa_copy_u_d: + case Mips::BI__builtin_msa_insve_d: + case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break; + case Mips::BI__builtin_msa_sld_d: + case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break; + // Memory offsets and immediate loads. + // These intrinsics take a signed 10 bit immediate. + case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 127; break; + case Mips::BI__builtin_msa_ldi_h: + case Mips::BI__builtin_msa_ldi_w: + case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break; + case Mips::BI__builtin_msa_ld_b: i = 1; l = -512; u = 511; m = 16; break; + case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 16; break; + case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 16; break; + case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 16; break; + case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 16; break; + case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 16; break; + case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 16; break; + case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 16; break; + } + + if (!m) + return SemaBuiltinConstantArgRange(TheCall, i, l, u); + + return SemaBuiltinConstantArgRange(TheCall, i, l, u) || + SemaBuiltinConstantArgMultiple(TheCall, i, m); } bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0; bool Is64BitBltin = BuiltinID == PPC::BI__builtin_divde || BuiltinID == PPC::BI__builtin_divdeu || BuiltinID == PPC::BI__builtin_bpermd; bool IsTarget64Bit = Context.getTargetInfo() .getTypeWidth(Context .getTargetInfo() .getIntPtrType()) == 64; bool IsBltinExtDiv = BuiltinID == PPC::BI__builtin_divwe || BuiltinID == PPC::BI__builtin_divweu || BuiltinID == PPC::BI__builtin_divde || BuiltinID == PPC::BI__builtin_divdeu; if (Is64BitBltin && !IsTarget64Bit) return Diag(TheCall->getLocStart(), diag::err_64_bit_builtin_32_bit_tgt) << TheCall->getSourceRange(); if ((IsBltinExtDiv && !Context.getTargetInfo().hasFeature("extdiv")) || (BuiltinID == PPC::BI__builtin_bpermd && !Context.getTargetInfo().hasFeature("bpermd"))) return Diag(TheCall->getLocStart(), diag::err_ppc_builtin_only_on_pwr7) << TheCall->getSourceRange(); switch (BuiltinID) { default: return false; case PPC::BI__builtin_altivec_crypto_vshasigmaw: case PPC::BI__builtin_altivec_crypto_vshasigmad: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: i = 0; l = 0; u = 1; break; case PPC::BI__builtin_tsr: i = 0; l = 0; u = 7; break; case PPC::BI__builtin_tabortwc: case PPC::BI__builtin_tabortdc: i = 0; l = 0; u = 31; break; case PPC::BI__builtin_tabortwci: case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == SystemZ::BI__builtin_tabort) { Expr *Arg = TheCall->getArg(0); llvm::APSInt AbortCode(32); if (Arg->isIntegerConstantExpr(AbortCode, Context) && AbortCode.getSExtValue() >= 0 && AbortCode.getSExtValue() < 256) return Diag(Arg->getLocStart(), diag::err_systemz_invalid_tabort_code) << Arg->getSourceRange(); } // For intrinsics which take an immediate value as part of the instruction, // range check them here. unsigned i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; case SystemZ::BI__builtin_s390_lcbb: i = 1; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_verimb: case SystemZ::BI__builtin_s390_verimh: case SystemZ::BI__builtin_s390_verimf: case SystemZ::BI__builtin_s390_verimg: i = 3; l = 0; u = 255; break; case SystemZ::BI__builtin_s390_vfaeb: case SystemZ::BI__builtin_s390_vfaeh: case SystemZ::BI__builtin_s390_vfaef: case SystemZ::BI__builtin_s390_vfaebs: case SystemZ::BI__builtin_s390_vfaehs: case SystemZ::BI__builtin_s390_vfaefs: case SystemZ::BI__builtin_s390_vfaezb: case SystemZ::BI__builtin_s390_vfaezh: case SystemZ::BI__builtin_s390_vfaezf: case SystemZ::BI__builtin_s390_vfaezbs: case SystemZ::BI__builtin_s390_vfaezhs: case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vfidb: return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vpdi: i = 2; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vsldb: i = 2; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vstrcb: case SystemZ::BI__builtin_s390_vstrch: case SystemZ::BI__builtin_s390_vstrcf: case SystemZ::BI__builtin_s390_vstrczb: case SystemZ::BI__builtin_s390_vstrczh: case SystemZ::BI__builtin_s390_vstrczf: case SystemZ::BI__builtin_s390_vstrcbs: case SystemZ::BI__builtin_s390_vstrchs: case SystemZ::BI__builtin_s390_vstrcfs: case SystemZ::BI__builtin_s390_vstrczbs: case SystemZ::BI__builtin_s390_vstrczhs: case SystemZ::BI__builtin_s390_vstrczfs: i = 3; l = 0; u = 15; break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } /// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *). /// This checks that the target supports __builtin_cpu_supports and /// that the string argument is constant and valid. static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); // Check if the argument is a string literal. if (!isa(Arg->IgnoreParenImpCasts())) return S.Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) << Arg->getSourceRange(); // Check the contents of the string. StringRef Feature = cast(Arg->IgnoreParenImpCasts())->getString(); if (!S.Context.getTargetInfo().validateCpuSupports(Feature)) return S.Diag(TheCall->getLocStart(), diag::err_invalid_cpu_supports) << Arg->getSourceRange(); return false; } bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { int i = 0, l = 0, u = 0; switch (BuiltinID) { default: return false; case X86::BI__builtin_cpu_supports: return SemaBuiltinCpuSupports(*this, TheCall); case X86::BI__builtin_ms_va_start: return SemaBuiltinMSVAStart(TheCall); case X86::BI__builtin_ia32_extractf64x4_mask: case X86::BI__builtin_ia32_extracti64x4_mask: case X86::BI__builtin_ia32_extractf32x8_mask: case X86::BI__builtin_ia32_extracti32x8_mask: case X86::BI__builtin_ia32_extractf64x2_256_mask: case X86::BI__builtin_ia32_extracti64x2_256_mask: case X86::BI__builtin_ia32_extractf32x4_256_mask: case X86::BI__builtin_ia32_extracti32x4_256_mask: i = 1; l = 0; u = 1; break; case X86::BI_mm_prefetch: case X86::BI__builtin_ia32_extractf32x4_mask: case X86::BI__builtin_ia32_extracti32x4_mask: case X86::BI__builtin_ia32_extractf64x2_512_mask: case X86::BI__builtin_ia32_extracti64x2_512_mask: i = 1; l = 0; u = 3; break; case X86::BI__builtin_ia32_insertf32x8_mask: case X86::BI__builtin_ia32_inserti32x8_mask: case X86::BI__builtin_ia32_insertf64x4_mask: case X86::BI__builtin_ia32_inserti64x4_mask: case X86::BI__builtin_ia32_insertf64x2_256_mask: case X86::BI__builtin_ia32_inserti64x2_256_mask: case X86::BI__builtin_ia32_insertf32x4_256_mask: case X86::BI__builtin_ia32_inserti32x4_256_mask: i = 2; l = 0; u = 1; break; case X86::BI__builtin_ia32_sha1rnds4: case X86::BI__builtin_ia32_shuf_f32x4_256_mask: case X86::BI__builtin_ia32_shuf_f64x2_256_mask: case X86::BI__builtin_ia32_shuf_i32x4_256_mask: case X86::BI__builtin_ia32_shuf_i64x2_256_mask: case X86::BI__builtin_ia32_insertf64x2_512_mask: case X86::BI__builtin_ia32_inserti64x2_512_mask: case X86::BI__builtin_ia32_insertf32x4_mask: case X86::BI__builtin_ia32_inserti32x4_mask: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: case X86::BI__builtin_ia32_vpermil2pd256: case X86::BI__builtin_ia32_vpermil2ps: case X86::BI__builtin_ia32_vpermil2ps256: i = 3; l = 0; u = 3; break; case X86::BI__builtin_ia32_cmpb128_mask: case X86::BI__builtin_ia32_cmpw128_mask: case X86::BI__builtin_ia32_cmpd128_mask: case X86::BI__builtin_ia32_cmpq128_mask: case X86::BI__builtin_ia32_cmpb256_mask: case X86::BI__builtin_ia32_cmpw256_mask: case X86::BI__builtin_ia32_cmpd256_mask: case X86::BI__builtin_ia32_cmpq256_mask: case X86::BI__builtin_ia32_cmpb512_mask: case X86::BI__builtin_ia32_cmpw512_mask: case X86::BI__builtin_ia32_cmpd512_mask: case X86::BI__builtin_ia32_cmpq512_mask: case X86::BI__builtin_ia32_ucmpb128_mask: case X86::BI__builtin_ia32_ucmpw128_mask: case X86::BI__builtin_ia32_ucmpd128_mask: case X86::BI__builtin_ia32_ucmpq128_mask: case X86::BI__builtin_ia32_ucmpb256_mask: case X86::BI__builtin_ia32_ucmpw256_mask: case X86::BI__builtin_ia32_ucmpd256_mask: case X86::BI__builtin_ia32_ucmpq256_mask: case X86::BI__builtin_ia32_ucmpb512_mask: case X86::BI__builtin_ia32_ucmpw512_mask: case X86::BI__builtin_ia32_ucmpd512_mask: case X86::BI__builtin_ia32_ucmpq512_mask: case X86::BI__builtin_ia32_vpcomub: case X86::BI__builtin_ia32_vpcomuw: case X86::BI__builtin_ia32_vpcomud: case X86::BI__builtin_ia32_vpcomuq: case X86::BI__builtin_ia32_vpcomb: case X86::BI__builtin_ia32_vpcomw: case X86::BI__builtin_ia32_vpcomd: case X86::BI__builtin_ia32_vpcomq: i = 2; l = 0; u = 7; break; case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: case X86::BI__builtin_ia32_roundpd256: i = 1; l = 0; u = 15; break; case X86::BI__builtin_ia32_roundss: case X86::BI__builtin_ia32_roundsd: case X86::BI__builtin_ia32_rangepd128_mask: case X86::BI__builtin_ia32_rangepd256_mask: case X86::BI__builtin_ia32_rangepd512_mask: case X86::BI__builtin_ia32_rangeps128_mask: case X86::BI__builtin_ia32_rangeps256_mask: case X86::BI__builtin_ia32_rangeps512_mask: case X86::BI__builtin_ia32_getmantsd_round_mask: case X86::BI__builtin_ia32_getmantss_round_mask: i = 2; l = 0; u = 15; break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: case X86::BI__builtin_ia32_cmpsd: case X86::BI__builtin_ia32_cmpps256: case X86::BI__builtin_ia32_cmppd256: case X86::BI__builtin_ia32_cmpps128_mask: case X86::BI__builtin_ia32_cmppd128_mask: case X86::BI__builtin_ia32_cmpps256_mask: case X86::BI__builtin_ia32_cmppd256_mask: case X86::BI__builtin_ia32_cmpps512_mask: case X86::BI__builtin_ia32_cmppd512_mask: case X86::BI__builtin_ia32_cmpsd_mask: case X86::BI__builtin_ia32_cmpss_mask: i = 2; l = 0; u = 31; break; case X86::BI__builtin_ia32_xabort: i = 0; l = -128; u = 255; break; case X86::BI__builtin_ia32_pshufw: case X86::BI__builtin_ia32_aeskeygenassist128: i = 1; l = -128; u = 255; break; case X86::BI__builtin_ia32_vcvtps2ph: case X86::BI__builtin_ia32_vcvtps2ph256: case X86::BI__builtin_ia32_rndscaleps_128_mask: case X86::BI__builtin_ia32_rndscalepd_128_mask: case X86::BI__builtin_ia32_rndscaleps_256_mask: case X86::BI__builtin_ia32_rndscalepd_256_mask: case X86::BI__builtin_ia32_rndscaleps_mask: case X86::BI__builtin_ia32_rndscalepd_mask: case X86::BI__builtin_ia32_reducepd128_mask: case X86::BI__builtin_ia32_reducepd256_mask: case X86::BI__builtin_ia32_reducepd512_mask: case X86::BI__builtin_ia32_reduceps128_mask: case X86::BI__builtin_ia32_reduceps256_mask: case X86::BI__builtin_ia32_reduceps512_mask: case X86::BI__builtin_ia32_prold512_mask: case X86::BI__builtin_ia32_prolq512_mask: case X86::BI__builtin_ia32_prold128_mask: case X86::BI__builtin_ia32_prold256_mask: case X86::BI__builtin_ia32_prolq128_mask: case X86::BI__builtin_ia32_prolq256_mask: case X86::BI__builtin_ia32_prord128_mask: case X86::BI__builtin_ia32_prord256_mask: case X86::BI__builtin_ia32_prorq128_mask: case X86::BI__builtin_ia32_prorq256_mask: case X86::BI__builtin_ia32_psllwi512_mask: case X86::BI__builtin_ia32_psllwi128_mask: case X86::BI__builtin_ia32_psllwi256_mask: case X86::BI__builtin_ia32_psrldi128_mask: case X86::BI__builtin_ia32_psrldi256_mask: case X86::BI__builtin_ia32_psrldi512_mask: case X86::BI__builtin_ia32_psrlqi128_mask: case X86::BI__builtin_ia32_psrlqi256_mask: case X86::BI__builtin_ia32_psrlqi512_mask: case X86::BI__builtin_ia32_psrawi512_mask: case X86::BI__builtin_ia32_psrawi128_mask: case X86::BI__builtin_ia32_psrawi256_mask: case X86::BI__builtin_ia32_psrlwi512_mask: case X86::BI__builtin_ia32_psrlwi128_mask: case X86::BI__builtin_ia32_psrlwi256_mask: case X86::BI__builtin_ia32_psradi128_mask: case X86::BI__builtin_ia32_psradi256_mask: case X86::BI__builtin_ia32_psradi512_mask: case X86::BI__builtin_ia32_psraqi128_mask: case X86::BI__builtin_ia32_psraqi256_mask: case X86::BI__builtin_ia32_psraqi512_mask: case X86::BI__builtin_ia32_pslldi128_mask: case X86::BI__builtin_ia32_pslldi256_mask: case X86::BI__builtin_ia32_pslldi512_mask: case X86::BI__builtin_ia32_psllqi128_mask: case X86::BI__builtin_ia32_psllqi256_mask: case X86::BI__builtin_ia32_psllqi512_mask: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: case X86::BI__builtin_ia32_fpclassps256_mask: case X86::BI__builtin_ia32_fpclassps512_mask: case X86::BI__builtin_ia32_fpclasspd512_mask: case X86::BI__builtin_ia32_fpclasssd_mask: case X86::BI__builtin_ia32_fpclassss_mask: i = 1; l = 0; u = 255; break; case X86::BI__builtin_ia32_palignr: case X86::BI__builtin_ia32_insertps128: case X86::BI__builtin_ia32_dpps: case X86::BI__builtin_ia32_dppd: case X86::BI__builtin_ia32_dpps256: case X86::BI__builtin_ia32_mpsadbw128: case X86::BI__builtin_ia32_mpsadbw256: case X86::BI__builtin_ia32_pcmpistrm128: case X86::BI__builtin_ia32_pcmpistri128: case X86::BI__builtin_ia32_pcmpistria128: case X86::BI__builtin_ia32_pcmpistric128: case X86::BI__builtin_ia32_pcmpistrio128: case X86::BI__builtin_ia32_pcmpistris128: case X86::BI__builtin_ia32_pcmpistriz128: case X86::BI__builtin_ia32_pclmulqdq128: case X86::BI__builtin_ia32_vperm2f128_pd256: case X86::BI__builtin_ia32_vperm2f128_ps256: case X86::BI__builtin_ia32_vperm2f128_si256: case X86::BI__builtin_ia32_permti256: i = 2; l = -128; u = 255; break; case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: case X86::BI__builtin_ia32_palignr128_mask: case X86::BI__builtin_ia32_palignr256_mask: case X86::BI__builtin_ia32_palignr512_mask: case X86::BI__builtin_ia32_alignq512_mask: case X86::BI__builtin_ia32_alignd512_mask: case X86::BI__builtin_ia32_alignd128_mask: case X86::BI__builtin_ia32_alignd256_mask: case X86::BI__builtin_ia32_alignq128_mask: case X86::BI__builtin_ia32_alignq256_mask: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: case X86::BI__builtin_ia32_shuf_f32x4_mask: case X86::BI__builtin_ia32_shuf_f64x2_mask: case X86::BI__builtin_ia32_shuf_i32x4_mask: case X86::BI__builtin_ia32_shuf_i64x2_mask: case X86::BI__builtin_ia32_dbpsadbw128_mask: case X86::BI__builtin_ia32_dbpsadbw256_mask: case X86::BI__builtin_ia32_dbpsadbw512_mask: i = 2; l = 0; u = 255; break; case X86::BI__builtin_ia32_fixupimmpd512_mask: case X86::BI__builtin_ia32_fixupimmpd512_maskz: case X86::BI__builtin_ia32_fixupimmps512_mask: case X86::BI__builtin_ia32_fixupimmps512_maskz: case X86::BI__builtin_ia32_fixupimmsd_mask: case X86::BI__builtin_ia32_fixupimmsd_maskz: case X86::BI__builtin_ia32_fixupimmss_mask: case X86::BI__builtin_ia32_fixupimmss_maskz: case X86::BI__builtin_ia32_fixupimmpd128_mask: case X86::BI__builtin_ia32_fixupimmpd128_maskz: case X86::BI__builtin_ia32_fixupimmpd256_mask: case X86::BI__builtin_ia32_fixupimmpd256_maskz: case X86::BI__builtin_ia32_fixupimmps128_mask: case X86::BI__builtin_ia32_fixupimmps128_maskz: case X86::BI__builtin_ia32_fixupimmps256_mask: case X86::BI__builtin_ia32_fixupimmps256_maskz: case X86::BI__builtin_ia32_pternlogd512_mask: case X86::BI__builtin_ia32_pternlogd512_maskz: case X86::BI__builtin_ia32_pternlogq512_mask: case X86::BI__builtin_ia32_pternlogq512_maskz: case X86::BI__builtin_ia32_pternlogd128_mask: case X86::BI__builtin_ia32_pternlogd128_maskz: case X86::BI__builtin_ia32_pternlogd256_mask: case X86::BI__builtin_ia32_pternlogd256_maskz: case X86::BI__builtin_ia32_pternlogq128_mask: case X86::BI__builtin_ia32_pternlogq128_maskz: case X86::BI__builtin_ia32_pternlogq256_mask: case X86::BI__builtin_ia32_pternlogq256_maskz: i = 3; l = 0; u = 255; break; case X86::BI__builtin_ia32_pcmpestrm128: case X86::BI__builtin_ia32_pcmpestri128: case X86::BI__builtin_ia32_pcmpestria128: case X86::BI__builtin_ia32_pcmpestric128: case X86::BI__builtin_ia32_pcmpestrio128: case X86::BI__builtin_ia32_pcmpestris128: case X86::BI__builtin_ia32_pcmpestriz128: i = 4; l = -128; u = 255; break; case X86::BI__builtin_ia32_rndscalesd_round_mask: case X86::BI__builtin_ia32_rndscaless_round_mask: i = 4; l = 0; u = 255; break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo /// parameter with the FormatAttr's correct format_idx and firstDataArg. /// Returns true when the format fits the function and the FormatStringInfo has /// been populated. bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, FormatStringInfo *FSI) { FSI->HasVAListArg = Format->getFirstArg() == 0; FSI->FormatIdx = Format->getFormatIdx() - 1; FSI->FirstDataArg = FSI->HasVAListArg ? 0 : Format->getFirstArg() - 1; // The way the format attribute works in GCC, the implicit this argument // of member functions is counted. However, it doesn't appear in our own // lists, so decrement format_idx in that case. if (IsCXXMember) { if(FSI->FormatIdx == 0) return false; --FSI->FormatIdx; if (FSI->FirstDataArg != 0) --FSI->FirstDataArg; } return true; } /// Checks if a the given expression evaluates to null. /// /// \brief Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability(S.Context)) { if (*nullability == NullabilityKind::NonNull) return false; } // As a special case, transparent unions initialized with zero are // considered null for the purposes of the nonnull attribute. if (const RecordType *UT = Expr->getType()->getAsUnionType()) { if (UT->getDecl()->hasAttr()) if (const CompoundLiteralExpr *CLE = dyn_cast(Expr)) if (const InitListExpr *ILE = dyn_cast(CLE->getInitializer())) Expr = ILE->getInit(0); } bool Result; return (!Expr->isValueDependent() && Expr->EvaluateAsBooleanCondition(Result, S.Context) && !Result); } static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr, SourceLocation CallSiteLoc) { if (CheckNonNullExpr(S, ArgExpr)) S.DiagRuntimeBehavior(CallSiteLoc, ArgExpr, S.PDiag(diag::warn_null_arg) << ArgExpr->getSourceRange()); } bool Sema::GetFormatNSStringIdx(const FormatAttr *Format, unsigned &Idx) { FormatStringInfo FSI; if ((GetFormatStringType(Format) == FST_NSString) && getFormatStringInfo(Format, false, &FSI)) { Idx = FSI.FormatIdx; return true; } return false; } /// \brief Diagnose use of %s directive in an NSString which is being passed /// as formatting string to formatting method. static void DiagnoseCStringFormatDirectiveInCFAPI(Sema &S, const NamedDecl *FDecl, Expr **Args, unsigned NumArgs) { unsigned Idx = 0; bool Format = false; ObjCStringFormatFamily SFFamily = FDecl->getObjCFStringFormattingFamily(); if (SFFamily == ObjCStringFormatFamily::SFF_CFString) { Idx = 2; Format = true; } else for (const auto *I : FDecl->specific_attrs()) { if (S.GetFormatNSStringIdx(I, Idx)) { Format = true; break; } } if (!Format || NumArgs <= Idx) return; const Expr *FormatExpr = Args[Idx]; if (const CStyleCastExpr *CSCE = dyn_cast(FormatExpr)) FormatExpr = CSCE->getSubExpr(); const StringLiteral *FormatString; if (const ObjCStringLiteral *OSL = dyn_cast(FormatExpr->IgnoreParenImpCasts())) FormatString = OSL->getString(); else FormatString = dyn_cast(FormatExpr->IgnoreParenImpCasts()); if (!FormatString) return; if (S.FormatStringHasSArg(FormatString)) { S.Diag(FormatExpr->getExprLoc(), diag::warn_objc_cdirective_format_string) << "%s" << 1 << 1; S.Diag(FDecl->getLocation(), diag::note_entity_declared_at) << FDecl->getDeclName(); } } /// Determine whether the given type has a non-null nullability annotation. static bool isNonNullType(ASTContext &ctx, QualType type) { if (auto nullability = type->getNullability(ctx)) return *nullability == NullabilityKind::NonNull; return false; } static void CheckNonNullArguments(Sema &S, const NamedDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, SourceLocation CallSiteLoc) { assert((FDecl || Proto) && "Need a function declaration or prototype"); // Check the attributes attached to the method/function itself. llvm::SmallBitVector NonNullArgs; if (FDecl) { // Handle the nonnull attribute on the function/method declaration itself. for (const auto *NonNull : FDecl->specific_attrs()) { if (!NonNull->args_size()) { // Easy case: all pointer arguments are nonnull. for (const auto *Arg : Args) if (S.isValidPointerAttrType(Arg->getType())) CheckNonNullArgument(S, Arg, CallSiteLoc); return; } for (unsigned Val : NonNull->args()) { if (Val >= Args.size()) continue; if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); NonNullArgs.set(Val); } } } if (FDecl && (isa(FDecl) || isa(FDecl))) { // Handle the nonnull attribute on the parameters of the // function/method. ArrayRef parms; if (const FunctionDecl *FD = dyn_cast(FDecl)) parms = FD->parameters(); else parms = cast(FDecl)->parameters(); unsigned ParamIndex = 0; for (ArrayRef::iterator I = parms.begin(), E = parms.end(); I != E; ++I, ++ParamIndex) { const ParmVarDecl *PVD = *I; if (PVD->hasAttr() || isNonNullType(S.Context, PVD->getType())) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); NonNullArgs.set(ParamIndex); } } } else { // If we have a non-function, non-method declaration but no // function prototype, try to dig out the function prototype. if (!Proto) { if (const ValueDecl *VD = dyn_cast(FDecl)) { QualType type = VD->getType().getNonReferenceType(); if (auto pointerType = type->getAs()) type = pointerType->getPointeeType(); else if (auto blockType = type->getAs()) type = blockType->getPointeeType(); // FIXME: data member pointers? // Dig out the function prototype, if there is one. Proto = type->getAs(); } } // Fill in non-null argument information from the nullability // information on the parameter types (if we have them). if (Proto) { unsigned Index = 0; for (auto paramType : Proto->getParamTypes()) { if (isNonNullType(S.Context, paramType)) { if (NonNullArgs.empty()) NonNullArgs.resize(Args.size()); NonNullArgs.set(Index); } ++Index; } } } // Check for non-null arguments. for (unsigned ArgIndex = 0, ArgIndexEnd = NonNullArgs.size(); ArgIndex != ArgIndexEnd; ++ArgIndex) { if (NonNullArgs[ArgIndex]) CheckNonNullArgument(S, Args[ArgIndex], CallSiteLoc); } } /// Handles the checks for format strings, non-POD arguments to vararg /// functions, and NULL arguments passed to non-NULL parameters. void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, ArrayRef Args, bool IsMemberFunction, SourceLocation Loc, SourceRange Range, VariadicCallType CallType) { // FIXME: We should check as much as we can in the template definition. if (CurContext->isDependentContext()) return; // Printf and scanf checking. llvm::SmallBitVector CheckedVarArgs; if (FDecl) { for (const auto *I : FDecl->specific_attrs()) { // Only create vector if there are format attributes. CheckedVarArgs.resize(Args.size()); CheckFormatArguments(I, Args, IsMemberFunction, CallType, Loc, Range, CheckedVarArgs); } } // Refuse POD arguments that weren't caught by the format string // checks above. if (CallType != VariadicDoesNotApply) { unsigned NumParams = Proto ? Proto->getNumParams() : FDecl && isa(FDecl) ? cast(FDecl)->getNumParams() : FDecl && isa(FDecl) ? cast(FDecl)->param_size() : 0; for (unsigned ArgIdx = NumParams; ArgIdx < Args.size(); ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { if (CheckedVarArgs.empty() || !CheckedVarArgs[ArgIdx]) checkVariadicArgument(Arg, CallType); } } } if (FDecl || Proto) { CheckNonNullArguments(*this, FDecl, Proto, Args, Loc); // Type safety checking. if (FDecl) { for (const auto *I : FDecl->specific_attrs()) CheckArgumentWithTypeTag(I, Args.data()); } } } /// CheckConstructorCall - Check a constructor call for correctness and safety /// properties not enforced by the C type system. void Sema::CheckConstructorCall(FunctionDecl *FDecl, ArrayRef Args, const FunctionProtoType *Proto, SourceLocation Loc) { VariadicCallType CallType = Proto->isVariadic() ? VariadicConstructor : VariadicDoesNotApply; checkCall(FDecl, Proto, Args, /*IsMemberFunction=*/true, Loc, SourceRange(), CallType); } /// CheckFunctionCall - Check a direct function call for various correctness /// and safety properties not strictly enforced by the C type system. bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { bool IsMemberOperatorCall = isa(TheCall) && isa(FDecl); bool IsMemberFunction = isa(TheCall) || IsMemberOperatorCall; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, TheCall->getCallee()); Expr** Args = TheCall->getArgs(); unsigned NumArgs = TheCall->getNumArgs(); if (IsMemberOperatorCall) { // If this is a call to a member operator, hide the first argument // from checkCall. // FIXME: Our choice of AST representation here is less than ideal. ++Args; --NumArgs; } checkCall(FDecl, Proto, llvm::makeArrayRef(Args, NumArgs), IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); IdentifierInfo *FnInfo = FDecl->getIdentifier(); // None of the checks below are needed for functions that don't have // simple names (e.g., C++ conversion functions). if (!FnInfo) return false; CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo); if (getLangOpts().ObjC1) DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); unsigned CMId = FDecl->getMemoryFunctionKind(); if (CMId == 0) return false; // Handle memory setting and copying functions. if (CMId == Builtin::BIstrlcpy || CMId == Builtin::BIstrlcat) CheckStrlcpycatArguments(TheCall, FnInfo); else if (CMId == Builtin::BIstrncat) CheckStrncatArguments(TheCall, FnInfo); else CheckMemaccessArguments(TheCall, CMId, FnInfo); return false; } bool Sema::CheckObjCMethodCall(ObjCMethodDecl *Method, SourceLocation lbrac, ArrayRef Args) { VariadicCallType CallType = Method->isVariadic() ? VariadicMethod : VariadicDoesNotApply; checkCall(Method, nullptr, Args, /*IsMemberFunction=*/false, lbrac, Method->getSourceRange(), CallType); return false; } bool Sema::CheckPointerCall(NamedDecl *NDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { QualType Ty; if (const auto *V = dyn_cast(NDecl)) Ty = V->getType().getNonReferenceType(); else if (const auto *F = dyn_cast(NDecl)) Ty = F->getType().getNonReferenceType(); else return false; if (!Ty->isBlockPointerType() && !Ty->isFunctionPointerType() && !Ty->isFunctionProtoType()) return false; VariadicCallType CallType; if (!Proto || !Proto->isVariadic()) { CallType = VariadicDoesNotApply; } else if (Ty->isBlockPointerType()) { CallType = VariadicBlock; } else { // Ty->isFunctionPointerType() CallType = VariadicFunction; } checkCall(NDecl, Proto, llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; } /// Checks function calls when a FunctionDecl or a NamedDecl is not available, /// such as function pointers returned from functions. bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { VariadicCallType CallType = getVariadicCallType(/*FDecl=*/nullptr, Proto, TheCall->getCallee()); checkCall(/*FDecl=*/nullptr, Proto, llvm::makeArrayRef(TheCall->getArgs(), TheCall->getNumArgs()), /*IsMemberFunction=*/false, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); return false; } static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { if (!llvm::isValidAtomicOrderingCABI(Ordering)) return false; auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering; switch (Op) { case AtomicExpr::AO__c11_atomic_init: llvm_unreachable("There is no ordering argument for an init"); case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: return OrderingCABI != llvm::AtomicOrderingCABI::release && OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: return OrderingCABI != llvm::AtomicOrderingCABI::consume && OrderingCABI != llvm::AtomicOrderingCABI::acquire && OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; default: return true; } } ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast(TheCallResult.get()); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); // All these operations take one of the following forms: enum { // C __c11_atomic_init(A *, C) Init, // C __c11_atomic_load(A *, int) Load, // void __atomic_load(A *, CP, int) LoadCopy, // void __atomic_store(A *, CP, int) Copy, // C __c11_atomic_add(A *, M, int) Arithmetic, // C __atomic_exchange_n(A *, CP, int) Xchg, // void __atomic_exchange(A *, C *, CP, int) GNUXchg, // bool __c11_atomic_compare_exchange_strong(A *, C *, CP, int, int) C11CmpXchg, // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) GNUCmpXchg } Form = Init; const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: // C is an appropriate type, // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, // CP is C for __c11 builtins and GNU _n builtins and is C * otherwise, // M is C if C is an integer, and ptrdiff_t if C is a pointer, and // the int parameters are for orderings. static_assert(AtomicExpr::AO__c11_atomic_init == 0 && AtomicExpr::AO__c11_atomic_fetch_xor + 1 == AtomicExpr::AO__atomic_load, "need to update code for modified C11 atomics"); bool IsC11 = Op >= AtomicExpr::AO__c11_atomic_init && Op <= AtomicExpr::AO__c11_atomic_fetch_xor; bool IsN = Op == AtomicExpr::AO__atomic_load_n || Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: Form = Init; break; case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__atomic_load_n: Form = Load; break; case AtomicExpr::AO__atomic_load: Form = LoadCopy; break; case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; break; case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_sub_fetch: IsAddSub = true; // Fall through. case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__atomic_fetch_xor: case AtomicExpr::AO__atomic_fetch_nand: case AtomicExpr::AO__atomic_and_fetch: case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: Form = Arithmetic; break; case AtomicExpr::AO__c11_atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: Form = Xchg; break; case AtomicExpr::AO__atomic_exchange: Form = GNUXchg; break; case AtomicExpr::AO__c11_atomic_compare_exchange_strong: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: Form = C11CmpXchg; break; case AtomicExpr::AO__atomic_compare_exchange: case AtomicExpr::AO__atomic_compare_exchange_n: Form = GNUCmpXchg; break; } // Check we have the right number of arguments. if (TheCall->getNumArgs() < NumArgs[Form]) { Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 << NumArgs[Form] << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } else if (TheCall->getNumArgs() > NumArgs[Form]) { Diag(TheCall->getArg(NumArgs[Form])->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 << NumArgs[Form] << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } // Inspect the first argument of the atomic operation. Expr *Ptr = TheCall->getArg(0); ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); if (ConvertedPtr.isInvalid()) return ExprError(); Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } // For a __c11 builtin, this should be a pointer to an _Atomic type. QualType AtomTy = pointerType->getPointeeType(); // 'A' QualType ValType = AtomTy; // 'C' if (IsC11) { if (!AtomTy->isAtomicType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if (AtomTy.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } ValType = AtomTy->getAs()->getValueType(); } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } } // For an arithmetic operation, the implied arithmetic must be well-formed. if (Form == Arithmetic) { // gcc does not enforce these rules for GNU atomics, but we do so for sanity. if (IsAddSub && !ValType->isIntegerType() && !ValType->isPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if (!IsAddSub && !ValType->isIntegerType()) { Diag(DRE->getLocStart(), diag::err_atomic_op_bitwise_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if (IsC11 && ValType->isPointerType() && RequireCompleteType(Ptr->getLocStart(), ValType->getPointeeType(), diag::err_incomplete_type)) { return ExprError(); } } else if (IsN && !ValType->isIntegerType() && !ValType->isPointerType()) { // For __atomic_*_n operations, the value type must be a scalar integral or // pointer type which is 1, 2, 4, 8 or 16 bytes in length. Diag(DRE->getLocStart(), diag::err_atomic_op_needs_atomic_int_or_ptr) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } if (!IsC11 && !AtomTy.isTriviallyCopyableType(Context) && !AtomTy->isScalarType()) { // For GNU atomics, require a trivially-copyable type. This is not part of // the GNU atomics specification, but we enforce it for sanity. Diag(DRE->getLocStart(), diag::err_atomic_op_needs_trivial_copy) << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: // okay break; case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: case Qualifiers::OCL_Autoreleasing: // FIXME: Can this happen? By this point, ValType should be known // to be trivially copyable. Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) << ValType << Ptr->getSourceRange(); return ExprError(); } // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the // volatile-ness of the pointee-type inject itself into the result or the // other operands. Similarly atomic_load can take a pointer to a const 'A'. ValType.removeLocalVolatile(); ValType.removeLocalConst(); QualType ResultType = ValType; if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; // The type of a parameter passed 'by value'. In the GNU atomics, such // arguments are actually passed as pointers. QualType ByValType = ValType; // 'CP' if (!IsC11 && !IsN) ByValType = Ptr->getType(); // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. for (unsigned i = 1; i != NumArgs[Form]; ++i) { QualType Ty; if (i < NumVals[Form] + 1) { switch (i) { case 1: // The second argument is the non-atomic operand. For arithmetic, this // is always passed by value, and for a compare_exchange it is always // passed by address. For the rest, GNU uses by-address and C11 uses // by-value. assert(Form != Load); if (Form == Init || (Form == Arithmetic && ValType->isIntegerType())) Ty = ValType; else if (Form == Copy || Form == Xchg) Ty = ByValType; else if (Form == Arithmetic) Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); unsigned AS = 0; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = ValArg->getType()->getAs()) { AS = PtrTy->getPointeeType().getAddressSpace(); } Ty = Context.getPointerType( Context.getAddrSpaceQualType(ValType.getUnqualifiedType(), AS)); } break; case 2: // The third argument to compare_exchange / GNU exchange is a // (pointer to a) desired value. Ty = ByValType; break; case 3: // The fourth argument to GNU compare_exchange is a 'weak' flag. Ty = Context.BoolTy; break; } } else { // The order(s) are always converted to int. Ty = Context.IntTy; } InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Ty, false); ExprResult Arg = TheCall->getArg(i); Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; TheCall->setArg(i, Arg.get()); } // Permute the arguments into a 'consistent' order. SmallVector SubExprs; SubExprs.push_back(Ptr); switch (Form) { case Init: // Note, AtomicExpr::getVal1() has a special case for this atomic. SubExprs.push_back(TheCall->getArg(1)); // Val1 break; case Load: SubExprs.push_back(TheCall->getArg(1)); // Order break; case LoadCopy: case Copy: case Arithmetic: case Xchg: SubExprs.push_back(TheCall->getArg(2)); // Order SubExprs.push_back(TheCall->getArg(1)); // Val1 break; case GNUXchg: // Note, AtomicExpr::getVal2() has a special case for this atomic. SubExprs.push_back(TheCall->getArg(3)); // Order SubExprs.push_back(TheCall->getArg(1)); // Val1 SubExprs.push_back(TheCall->getArg(2)); // Val2 break; case C11CmpXchg: SubExprs.push_back(TheCall->getArg(3)); // Order SubExprs.push_back(TheCall->getArg(1)); // Val1 SubExprs.push_back(TheCall->getArg(4)); // OrderFail SubExprs.push_back(TheCall->getArg(2)); // Val2 break; case GNUCmpXchg: SubExprs.push_back(TheCall->getArg(4)); // Order SubExprs.push_back(TheCall->getArg(1)); // Val1 SubExprs.push_back(TheCall->getArg(5)); // OrderFail SubExprs.push_back(TheCall->getArg(2)); // Val2 SubExprs.push_back(TheCall->getArg(3)); // Weak break; } if (SubExprs.size() >= 2 && Form != Init) { llvm::APSInt Result(32); if (SubExprs[1]->isIntegerConstantExpr(Result, Context) && !isValidOrderingForOp(Result.getSExtValue(), Op)) Diag(SubExprs[1]->getLocStart(), diag::warn_atomic_op_has_invalid_memory_order) << SubExprs[1]->getSourceRange(); } AtomicExpr *AE = new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), SubExprs, ResultType, Op, TheCall->getRParenLoc()); if ((Op == AtomicExpr::AO__c11_atomic_load || (Op == AtomicExpr::AO__c11_atomic_store)) && Context.AtomicUsesUnsupportedLibcall(AE)) Diag(AE->getLocStart(), diag::err_atomic_load_store_uses_lib) << ((Op == AtomicExpr::AO__c11_atomic_load) ? 0 : 1); return AE; } /// checkBuiltinArgument - Given a call to a builtin function, perform /// normal type-checking on the given argument, updating the call in /// place. This is useful when a builtin function requires custom /// type-checking for some of its arguments but not necessarily all of /// them. /// /// Returns true on error. static bool checkBuiltinArgument(Sema &S, CallExpr *E, unsigned ArgIndex) { FunctionDecl *Fn = E->getDirectCallee(); assert(Fn && "builtin call without direct callee!"); ParmVarDecl *Param = Fn->getParamDecl(ArgIndex); InitializedEntity Entity = InitializedEntity::InitializeParameter(S.Context, Param); ExprResult Arg = E->getArg(0); Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; E->setArg(ArgIndex, Arg.get()); return false; } /// SemaBuiltinAtomicOverloaded - We have a call to a function like /// __sync_fetch_and_add, which is an overloaded function based on the pointer /// type of its first argument. The main ActOnCallExpr routines have already /// promoted the types of arguments because all of these calls are prototyped as /// void(...). /// /// This function goes through and does final semantic checking for these /// builtins, ExprResult Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = (CallExpr *)TheCallResult.get(); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); // Ensure that we have at least one argument to do type inference from. if (TheCall->getNumArgs() < 1) { Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) << 0 << 1 << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } // Inspect the first argument of the atomic builtin. This should always be // a pointer type, whose element is an integral scalar or pointer type. // Because it is a pointer type, we don't have to worry about any implicit // casts here. // FIXME: We don't allow floating point scalars as input. Expr *FirstArg = TheCall->getArg(0); ExprResult FirstArgResult = DefaultFunctionArrayLvalueConversion(FirstArg); if (FirstArgResult.isInvalid()) return ExprError(); FirstArg = FirstArgResult.get(); TheCall->setArg(0, FirstArg); const PointerType *pointerType = FirstArg->getType()->getAs(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) << FirstArg->getType() << FirstArg->getSourceRange(); return ExprError(); } QualType ValType = pointerType->getPointeeType(); if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType()) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer_intptr) << FirstArg->getType() << FirstArg->getSourceRange(); return ExprError(); } switch (ValType.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: // okay break; case Qualifiers::OCL_Weak: case Qualifiers::OCL_Strong: case Qualifiers::OCL_Autoreleasing: Diag(DRE->getLocStart(), diag::err_arc_atomic_ownership) << ValType << FirstArg->getSourceRange(); return ExprError(); } // Strip any qualifiers off ValType. ValType = ValType.getUnqualifiedType(); // The majority of builtins return a value, but a few have special return // types, so allow them to override appropriately below. QualType ResultType = ValType; // We need to figure out which concrete builtin this maps onto. For example, // __sync_fetch_and_add with a 2 byte object turns into // __sync_fetch_and_add_2. #define BUILTIN_ROW(x) \ { Builtin::BI##x##_1, Builtin::BI##x##_2, Builtin::BI##x##_4, \ Builtin::BI##x##_8, Builtin::BI##x##_16 } static const unsigned BuiltinIndices[][5] = { BUILTIN_ROW(__sync_fetch_and_add), BUILTIN_ROW(__sync_fetch_and_sub), BUILTIN_ROW(__sync_fetch_and_or), BUILTIN_ROW(__sync_fetch_and_and), BUILTIN_ROW(__sync_fetch_and_xor), BUILTIN_ROW(__sync_fetch_and_nand), BUILTIN_ROW(__sync_add_and_fetch), BUILTIN_ROW(__sync_sub_and_fetch), BUILTIN_ROW(__sync_and_and_fetch), BUILTIN_ROW(__sync_or_and_fetch), BUILTIN_ROW(__sync_xor_and_fetch), BUILTIN_ROW(__sync_nand_and_fetch), BUILTIN_ROW(__sync_val_compare_and_swap), BUILTIN_ROW(__sync_bool_compare_and_swap), BUILTIN_ROW(__sync_lock_test_and_set), BUILTIN_ROW(__sync_lock_release), BUILTIN_ROW(__sync_swap) }; #undef BUILTIN_ROW // Determine the index of the size. unsigned SizeIndex; switch (Context.getTypeSizeInChars(ValType).getQuantity()) { case 1: SizeIndex = 0; break; case 2: SizeIndex = 1; break; case 4: SizeIndex = 2; break; case 8: SizeIndex = 3; break; case 16: SizeIndex = 4; break; default: Diag(DRE->getLocStart(), diag::err_atomic_builtin_pointer_size) << FirstArg->getType() << FirstArg->getSourceRange(); return ExprError(); } // Each of these builtins has one pointer argument, followed by some number of // values (0, 1 or 2) followed by a potentially empty varags list of stuff // that we ignore. Find out which row of BuiltinIndices to read from as well // as the number of fixed args. unsigned BuiltinID = FDecl->getBuiltinID(); unsigned BuiltinIndex, NumFixed = 1; bool WarnAboutSemanticsChange = false; switch (BuiltinID) { default: llvm_unreachable("Unknown overloaded atomic builtin!"); case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: case Builtin::BI__sync_fetch_and_add_4: case Builtin::BI__sync_fetch_and_add_8: case Builtin::BI__sync_fetch_and_add_16: BuiltinIndex = 0; break; case Builtin::BI__sync_fetch_and_sub: case Builtin::BI__sync_fetch_and_sub_1: case Builtin::BI__sync_fetch_and_sub_2: case Builtin::BI__sync_fetch_and_sub_4: case Builtin::BI__sync_fetch_and_sub_8: case Builtin::BI__sync_fetch_and_sub_16: BuiltinIndex = 1; break; case Builtin::BI__sync_fetch_and_or: case Builtin::BI__sync_fetch_and_or_1: case Builtin::BI__sync_fetch_and_or_2: case Builtin::BI__sync_fetch_and_or_4: case Builtin::BI__sync_fetch_and_or_8: case Builtin::BI__sync_fetch_and_or_16: BuiltinIndex = 2; break; case Builtin::BI__sync_fetch_and_and: case Builtin::BI__sync_fetch_and_and_1: case Builtin::BI__sync_fetch_and_and_2: case Builtin::BI__sync_fetch_and_and_4: case Builtin::BI__sync_fetch_and_and_8: case Builtin::BI__sync_fetch_and_and_16: BuiltinIndex = 3; break; case Builtin::BI__sync_fetch_and_xor: case Builtin::BI__sync_fetch_and_xor_1: case Builtin::BI__sync_fetch_and_xor_2: case Builtin::BI__sync_fetch_and_xor_4: case Builtin::BI__sync_fetch_and_xor_8: case Builtin::BI__sync_fetch_and_xor_16: BuiltinIndex = 4; break; case Builtin::BI__sync_fetch_and_nand: case Builtin::BI__sync_fetch_and_nand_1: case Builtin::BI__sync_fetch_and_nand_2: case Builtin::BI__sync_fetch_and_nand_4: case Builtin::BI__sync_fetch_and_nand_8: case Builtin::BI__sync_fetch_and_nand_16: BuiltinIndex = 5; WarnAboutSemanticsChange = true; break; case Builtin::BI__sync_add_and_fetch: case Builtin::BI__sync_add_and_fetch_1: case Builtin::BI__sync_add_and_fetch_2: case Builtin::BI__sync_add_and_fetch_4: case Builtin::BI__sync_add_and_fetch_8: case Builtin::BI__sync_add_and_fetch_16: BuiltinIndex = 6; break; case Builtin::BI__sync_sub_and_fetch: case Builtin::BI__sync_sub_and_fetch_1: case Builtin::BI__sync_sub_and_fetch_2: case Builtin::BI__sync_sub_and_fetch_4: case Builtin::BI__sync_sub_and_fetch_8: case Builtin::BI__sync_sub_and_fetch_16: BuiltinIndex = 7; break; case Builtin::BI__sync_and_and_fetch: case Builtin::BI__sync_and_and_fetch_1: case Builtin::BI__sync_and_and_fetch_2: case Builtin::BI__sync_and_and_fetch_4: case Builtin::BI__sync_and_and_fetch_8: case Builtin::BI__sync_and_and_fetch_16: BuiltinIndex = 8; break; case Builtin::BI__sync_or_and_fetch: case Builtin::BI__sync_or_and_fetch_1: case Builtin::BI__sync_or_and_fetch_2: case Builtin::BI__sync_or_and_fetch_4: case Builtin::BI__sync_or_and_fetch_8: case Builtin::BI__sync_or_and_fetch_16: BuiltinIndex = 9; break; case Builtin::BI__sync_xor_and_fetch: case Builtin::BI__sync_xor_and_fetch_1: case Builtin::BI__sync_xor_and_fetch_2: case Builtin::BI__sync_xor_and_fetch_4: case Builtin::BI__sync_xor_and_fetch_8: case Builtin::BI__sync_xor_and_fetch_16: BuiltinIndex = 10; break; case Builtin::BI__sync_nand_and_fetch: case Builtin::BI__sync_nand_and_fetch_1: case Builtin::BI__sync_nand_and_fetch_2: case Builtin::BI__sync_nand_and_fetch_4: case Builtin::BI__sync_nand_and_fetch_8: case Builtin::BI__sync_nand_and_fetch_16: BuiltinIndex = 11; WarnAboutSemanticsChange = true; break; case Builtin::BI__sync_val_compare_and_swap: case Builtin::BI__sync_val_compare_and_swap_1: case Builtin::BI__sync_val_compare_and_swap_2: case Builtin::BI__sync_val_compare_and_swap_4: case Builtin::BI__sync_val_compare_and_swap_8: case Builtin::BI__sync_val_compare_and_swap_16: BuiltinIndex = 12; NumFixed = 2; break; case Builtin::BI__sync_bool_compare_and_swap: case Builtin::BI__sync_bool_compare_and_swap_1: case Builtin::BI__sync_bool_compare_and_swap_2: case Builtin::BI__sync_bool_compare_and_swap_4: case Builtin::BI__sync_bool_compare_and_swap_8: case Builtin::BI__sync_bool_compare_and_swap_16: BuiltinIndex = 13; NumFixed = 2; ResultType = Context.BoolTy; break; case Builtin::BI__sync_lock_test_and_set: case Builtin::BI__sync_lock_test_and_set_1: case Builtin::BI__sync_lock_test_and_set_2: case Builtin::BI__sync_lock_test_and_set_4: case Builtin::BI__sync_lock_test_and_set_8: case Builtin::BI__sync_lock_test_and_set_16: BuiltinIndex = 14; break; case Builtin::BI__sync_lock_release: case Builtin::BI__sync_lock_release_1: case Builtin::BI__sync_lock_release_2: case Builtin::BI__sync_lock_release_4: case Builtin::BI__sync_lock_release_8: case Builtin::BI__sync_lock_release_16: BuiltinIndex = 15; NumFixed = 0; ResultType = Context.VoidTy; break; case Builtin::BI__sync_swap: case Builtin::BI__sync_swap_1: case Builtin::BI__sync_swap_2: case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: BuiltinIndex = 16; break; } // Now that we know how many fixed arguments we expect, first check that we // have at least that many. if (TheCall->getNumArgs() < 1+NumFixed) { Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) << 0 << 1+NumFixed << TheCall->getNumArgs() << TheCall->getCallee()->getSourceRange(); return ExprError(); } if (WarnAboutSemanticsChange) { Diag(TheCall->getLocEnd(), diag::warn_sync_fetch_and_nand_semantics_change) << TheCall->getCallee()->getSourceRange(); } // Get the decl for the concrete builtin from this, we can tell what the // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; const char *NewBuiltinName = Context.BuiltinInfo.getName(NewBuiltinID); FunctionDecl *NewBuiltinDecl; if (NewBuiltinID == BuiltinID) NewBuiltinDecl = FDecl; else { // Perform builtin lookup to avoid redeclaring it. DeclarationName DN(&Context.Idents.get(NewBuiltinName)); LookupResult Res(*this, DN, DRE->getLocStart(), LookupOrdinaryName); LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true); assert(Res.getFoundDecl()); NewBuiltinDecl = dyn_cast(Res.getFoundDecl()); if (!NewBuiltinDecl) return ExprError(); } // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. for (unsigned i = 0; i != NumFixed; ++i) { ExprResult Arg = TheCall->getArg(i+1); // GCC does an implicit conversion to the pointer or integer ValType. This // can fail in some cases (1i -> int**), check for this error case now. // Initialize the argument. InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, ValType, /*consume*/ false); Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return ExprError(); // Okay, we have something that *can* be converted to the right type. Check // to see if there is a potentially weird extension going on here. This can // happen when you do an atomic operation on something like an char* and // pass in 42. The 42 gets converted to char. This is even more strange // for things like 45.123 -> char, etc. // FIXME: Do this check. TheCall->setArg(i+1, Arg.get()); } ASTContext& Context = this->getASTContext(); // Create a new DeclRefExpr to refer to the new decl. DeclRefExpr* NewDRE = DeclRefExpr::Create( Context, DRE->getQualifierLoc(), SourceLocation(), NewBuiltinDecl, /*enclosing*/ false, DRE->getLocation(), Context.BuiltinFnTy, DRE->getValueKind()); // Set the callee in the CallExpr. // FIXME: This loses syntactic information. QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType()); ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy, CK_BuiltinFnToFnPtr); TheCall->setCallee(PromotedCall.get()); // Change the result type of the call to match the original value type. This // is arbitrary, but the codegen for these builtins ins design to handle it // gracefully. TheCall->setType(ResultType); return TheCallResult; } /// SemaBuiltinNontemporalOverloaded - We have a call to /// __builtin_nontemporal_store or __builtin_nontemporal_load, which is an /// overloaded function based on the pointer type of its last argument. /// /// This function goes through and does final semantic checking for these /// builtins. ExprResult Sema::SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = (CallExpr *)TheCallResult.get(); DeclRefExpr *DRE = cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); unsigned BuiltinID = FDecl->getBuiltinID(); assert((BuiltinID == Builtin::BI__builtin_nontemporal_store || BuiltinID == Builtin::BI__builtin_nontemporal_load) && "Unexpected nontemporal load/store builtin!"); bool isStore = BuiltinID == Builtin::BI__builtin_nontemporal_store; unsigned numArgs = isStore ? 2 : 1; // Ensure that we have the proper number of arguments. if (checkArgCount(*this, TheCall, numArgs)) return ExprError(); // Inspect the last argument of the nontemporal builtin. This should always // be a pointer type, from which we imply the type of the memory access. // Because it is a pointer type, we don't have to worry about any implicit // casts here. Expr *PointerArg = TheCall->getArg(numArgs - 1); ExprResult PointerArgResult = DefaultFunctionArrayLvalueConversion(PointerArg); if (PointerArgResult.isInvalid()) return ExprError(); PointerArg = PointerArgResult.get(); TheCall->setArg(numArgs - 1, PointerArg); const PointerType *pointerType = PointerArg->getType()->getAs(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_nontemporal_builtin_must_be_pointer) << PointerArg->getType() << PointerArg->getSourceRange(); return ExprError(); } QualType ValType = pointerType->getPointeeType(); // Strip any qualifiers off ValType. ValType = ValType.getUnqualifiedType(); if (!ValType->isIntegerType() && !ValType->isAnyPointerType() && !ValType->isBlockPointerType() && !ValType->isFloatingType() && !ValType->isVectorType()) { Diag(DRE->getLocStart(), diag::err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector) << PointerArg->getType() << PointerArg->getSourceRange(); return ExprError(); } if (!isStore) { TheCall->setType(ValType); return TheCallResult; } ExprResult ValArg = TheCall->getArg(0); InitializedEntity Entity = InitializedEntity::InitializeParameter( Context, ValType, /*consume*/ false); ValArg = PerformCopyInitialization(Entity, SourceLocation(), ValArg); if (ValArg.isInvalid()) return ExprError(); TheCall->setArg(0, ValArg.get()); TheCall->setType(Context.VoidTy); return TheCallResult; } /// CheckObjCString - Checks that the argument to the builtin /// CFString constructor is correct /// Note: It might also make sense to do the UTF-16 conversion here (would /// simplify the backend). bool Sema::CheckObjCString(Expr *Arg) { Arg = Arg->IgnoreParenCasts(); StringLiteral *Literal = dyn_cast(Arg); if (!Literal || !Literal->isAscii()) { Diag(Arg->getLocStart(), diag::err_cfstring_literal_not_string_constant) << Arg->getSourceRange(); return true; } if (Literal->containsNonAsciiOrNull()) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); SmallVector ToBuf(NumBytes); const UTF8 *FromPtr = (const UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr, ToPtr + NumBytes, strictConversion); // Check for conversion failure. if (Result != conversionOK) Diag(Arg->getLocStart(), diag::warn_cfstring_truncated) << Arg->getSourceRange(); } return false; } /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { Expr *Fn = TheCall->getCallee(); if (TheCall->getNumArgs() > 2) { Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << 2 << TheCall->getNumArgs() << Fn->getSourceRange() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); return true; } if (TheCall->getNumArgs() < 2) { return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) << 0 /*function call*/ << 2 << TheCall->getNumArgs(); } // Type-check the first argument normally. if (checkBuiltinArgument(*this, TheCall, 0)) return true; // Determine whether the current function is variadic or not. BlockScopeInfo *CurBlock = getCurBlock(); bool isVariadic; if (CurBlock) isVariadic = CurBlock->TheDecl->isVariadic(); else if (FunctionDecl *FD = getCurFunctionDecl()) isVariadic = FD->isVariadic(); else isVariadic = getCurMethodDecl()->isVariadic(); if (!isVariadic) { Diag(Fn->getLocStart(), diag::err_va_start_used_in_non_variadic_function); return true; } // Verify that the second argument to the builtin is the last argument of the // current function or method. bool SecondArgIsLastNamedArgument = false; const Expr *Arg = TheCall->getArg(1)->IgnoreParenCasts(); // These are valid if SecondArgIsLastNamedArgument is false after the next // block. QualType Type; SourceLocation ParamLoc; bool IsCRegister = false; if (const DeclRefExpr *DR = dyn_cast(Arg)) { if (const ParmVarDecl *PV = dyn_cast(DR->getDecl())) { // FIXME: This isn't correct for methods (results in bogus warning). // Get the last formal in the current function. const ParmVarDecl *LastArg; if (CurBlock) LastArg = CurBlock->TheDecl->parameters().back(); else if (FunctionDecl *FD = getCurFunctionDecl()) LastArg = FD->parameters().back(); else LastArg = getCurMethodDecl()->parameters().back(); SecondArgIsLastNamedArgument = PV == LastArg; Type = PV->getType(); ParamLoc = PV->getLocation(); IsCRegister = PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; } } if (!SecondArgIsLastNamedArgument) Diag(TheCall->getArg(1)->getLocStart(), diag::warn_second_arg_of_va_start_not_last_named_param); else if (IsCRegister || Type->isReferenceType() || Type->isPromotableIntegerType() || Type->isSpecificBuiltinType(BuiltinType::Float)) { unsigned Reason = 0; if (Type->isReferenceType()) Reason = 1; else if (IsCRegister) Reason = 2; Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason; Diag(ParamLoc, diag::note_parameter_type) << Type; } TheCall->setType(Context.VoidTy); return false; } /// Check the arguments to '__builtin_va_start' for validity, and that /// it was called from a function of the native ABI. /// Emit an error and return true on failure; return false on success. bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) { // On x86-64 Unix, don't allow this in Win64 ABI functions. // On x64 Windows, don't allow this in System V ABI functions. // (Yes, that means there's no corresponding way to support variadic // System V ABI functions on Windows.) if (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) { unsigned OS = Context.getTargetInfo().getTriple().getOS(); clang::CallingConv CC = CC_C; if (const FunctionDecl *FD = getCurFunctionDecl()) CC = FD->getType()->getAs()->getCallConv(); if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) || (OS != llvm::Triple::Win32 && CC == CC_X86_64Win64)) return Diag(TheCall->getCallee()->getLocStart(), diag::err_va_start_used_in_wrong_abi_function) << (OS != llvm::Triple::Win32); } return SemaBuiltinVAStartImpl(TheCall); } /// Check the arguments to '__builtin_ms_va_start' for validity, and that /// it was called from a Win64 ABI function. /// Emit an error and return true on failure; return false on success. bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) { // This only makes sense for x86-64. const llvm::Triple &TT = Context.getTargetInfo().getTriple(); Expr *Callee = TheCall->getCallee(); if (TT.getArch() != llvm::Triple::x86_64) return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt); // Don't allow this in System V ABI functions. clang::CallingConv CC = CC_C; if (const FunctionDecl *FD = getCurFunctionDecl()) CC = FD->getType()->getAs()->getCallConv(); if (CC == CC_X86_64SysV || (TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64)) return Diag(Callee->getLocStart(), diag::err_ms_va_start_used_in_sysv_function); return SemaBuiltinVAStartImpl(TheCall); } bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) { // void __va_start(va_list *ap, const char *named_addr, size_t slot_size, // const char *named_addr); Expr *Func = Call->getCallee(); if (Call->getNumArgs() < 3) return Diag(Call->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) << 0 /*function call*/ << 3 << Call->getNumArgs(); // Determine whether the current function is variadic or not. bool IsVariadic; if (BlockScopeInfo *CurBlock = getCurBlock()) IsVariadic = CurBlock->TheDecl->isVariadic(); else if (FunctionDecl *FD = getCurFunctionDecl()) IsVariadic = FD->isVariadic(); else if (ObjCMethodDecl *MD = getCurMethodDecl()) IsVariadic = MD->isVariadic(); else llvm_unreachable("unexpected statement type"); if (!IsVariadic) { Diag(Func->getLocStart(), diag::err_va_start_used_in_non_variadic_function); return true; } // Type-check the first argument normally. if (checkBuiltinArgument(*this, Call, 0)) return true; const struct { unsigned ArgNo; QualType Type; } ArgumentTypes[] = { { 1, Context.getPointerType(Context.CharTy.withConst()) }, { 2, Context.getSizeType() }, }; for (const auto &AT : ArgumentTypes) { const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens(); if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType()) continue; Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible) << Arg->getType() << AT.Type << 1 /* different class */ << 0 /* qualifier difference */ << 3 /* parameter mismatch */ << AT.ArgNo + 1 << Arg->getType() << AT.Type; } return false; } /// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 << 2 << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > 2) return Diag(TheCall->getArg(2)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << 2 << TheCall->getNumArgs() << SourceRange(TheCall->getArg(2)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); ExprResult OrigArg0 = TheCall->getArg(0); ExprResult OrigArg1 = TheCall->getArg(1); // Do standard promotions between the two arguments, returning their common // type. QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) return true; // Make sure any conversions are pushed back into the call; this is // type safe since unordered compare builtins are declared as "_Bool // foo(...)". TheCall->setArg(0, OrigArg0.get()); TheCall->setArg(1, OrigArg1.get()); if (OrigArg0.get()->isTypeDependent() || OrigArg1.get()->isTypeDependent()) return false; // If the common type isn't a real floating type, then the arguments were // invalid for this operation. if (Res.isNull() || !Res->isRealFloatingType()) return Diag(OrigArg0.get()->getLocStart(), diag::err_typecheck_call_invalid_ordered_compare) << OrigArg0.get()->getType() << OrigArg1.get()->getType() << SourceRange(OrigArg0.get()->getLocStart(), OrigArg1.get()->getLocEnd()); return false; } /// SemaBuiltinSemaBuiltinFPClassification - Handle functions like /// __builtin_isnan and friends. This is declared to take (...), so we have /// to check everything. We expect the last argument to be a floating point /// value. bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { if (TheCall->getNumArgs() < NumArgs) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) << 0 << NumArgs << TheCall->getNumArgs()/*function call*/; if (TheCall->getNumArgs() > NumArgs) return Diag(TheCall->getArg(NumArgs)->getLocStart(), diag::err_typecheck_call_too_many_args) << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() << SourceRange(TheCall->getArg(NumArgs)->getLocStart(), (*(TheCall->arg_end()-1))->getLocEnd()); Expr *OrigArg = TheCall->getArg(NumArgs-1); if (OrigArg->isTypeDependent()) return false; // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) return Diag(OrigArg->getLocStart(), diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); // If this is an implicit conversion from float -> double, remove it. if (ImplicitCastExpr *Cast = dyn_cast(OrigArg)) { Expr *CastArg = Cast->getSubExpr(); if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && "promotion from float to double is the only expected cast here"); Cast->setSubExpr(nullptr); TheCall->setArg(NumArgs-1, CastArg); } } return false; } /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return ExprError(Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args_at_least) << 0 /*function call*/ << 2 << TheCall->getNumArgs() << TheCall->getSourceRange()); // Determine which of the following types of shufflevector we're checking: // 1) unary, vector mask: (lhs, mask) // 2) binary, scalar mask: (lhs, rhs, index, ..., index) QualType resType = TheCall->getArg(0)->getType(); unsigned numElements = 0; if (!TheCall->getArg(0)->isTypeDependent() && !TheCall->getArg(1)->isTypeDependent()) { QualType LHSType = TheCall->getArg(0)->getType(); QualType RHSType = TheCall->getArg(1)->getType(); if (!LHSType->isVectorType() || !RHSType->isVectorType()) return ExprError(Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector) << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); numElements = LHSType->getAs()->getNumElements(); unsigned numResElements = TheCall->getNumArgs() - 2; // Check to see if we have a call with 2 vector arguments, the unary shuffle // with mask. If so, verify that RHS is an integer vector type with the // same number of elts as lhs. if (TheCall->getNumArgs() == 2) { if (!RHSType->hasIntegerRepresentation() || RHSType->getAs()->getNumElements() != numElements) return ExprError(Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) << SourceRange(TheCall->getArg(1)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { return ExprError(Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector) << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (numElements != numResElements) { QualType eltType = LHSType->getAs()->getElementType(); resType = Context.getVectorType(eltType, numResElements, VectorType::GenericVector); } } for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { if (TheCall->getArg(i)->isTypeDependent() || TheCall->getArg(i)->isValueDependent()) continue; llvm::APSInt Result(32); if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) return ExprError(Diag(TheCall->getLocStart(), diag::err_shufflevector_nonconstant_argument) << TheCall->getArg(i)->getSourceRange()); // Allow -1 which will be translated to undef in the IR. if (Result.isSigned() && Result.isAllOnesValue()) continue; if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) return ExprError(Diag(TheCall->getLocStart(), diag::err_shufflevector_argument_too_large) << TheCall->getArg(i)->getSourceRange()); } SmallVector exprs; for (unsigned i = 0, e = TheCall->getNumArgs(); i != e; i++) { exprs.push_back(TheCall->getArg(i)); TheCall->setArg(i, nullptr); } return new (Context) ShuffleVectorExpr(Context, exprs, resType, TheCall->getCallee()->getLocStart(), TheCall->getRParenLoc()); } /// SemaConvertVectorExpr - Handle __builtin_convertvector ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, SourceLocation BuiltinLoc, SourceLocation RParenLoc) { ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType DstTy = TInfo->getType(); QualType SrcTy = E->getType(); if (!SrcTy->isVectorType() && !SrcTy->isDependentType()) return ExprError(Diag(BuiltinLoc, diag::err_convertvector_non_vector) << E->getSourceRange()); if (!DstTy->isVectorType() && !DstTy->isDependentType()) return ExprError(Diag(BuiltinLoc, diag::err_convertvector_non_vector_type)); if (!SrcTy->isDependentType() && !DstTy->isDependentType()) { unsigned SrcElts = SrcTy->getAs()->getNumElements(); unsigned DstElts = DstTy->getAs()->getNumElements(); if (SrcElts != DstElts) return ExprError(Diag(BuiltinLoc, diag::err_convertvector_incompatible_vector) << E->getSourceRange()); } return new (Context) ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc); } /// SemaBuiltinPrefetch - Handle __builtin_prefetch. // This is declared to take (const void*, ...) and can take two // optional constant int args. bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args_at_most) << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange(); // Argument 0 is checked for us and the remaining arguments must be // constant integers. for (unsigned i = 1; i != NumArgs; ++i) if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) return true; return false; } /// SemaBuiltinAssume - Handle __assume (MS Extension). // __assume does not evaluate its arguments, and should warn if its argument // has side effects. bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); if (Arg->isInstantiationDependent()) return false; if (Arg->HasSideEffects(Context)) Diag(Arg->getLocStart(), diag::warn_assume_side_effects) << Arg->getSourceRange() << cast(TheCall->getCalleeDecl())->getIdentifier(); return false; } /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args_at_most) << 0 /*function call*/ << 3 << NumArgs << TheCall->getSourceRange(); // The alignment must be a constant integer. Expr *Arg = TheCall->getArg(1); // We can't check the value of a dependent argument. if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { llvm::APSInt Result; if (SemaBuiltinConstantArg(TheCall, 1, Result)) return true; if (!Result.isPowerOf2()) return Diag(TheCall->getLocStart(), diag::err_alignment_not_power_of_two) << Arg->getSourceRange(); } if (NumArgs > 2) { ExprResult Arg(TheCall->getArg(2)); InitializedEntity Entity = InitializedEntity::InitializeParameter(Context, Context.getSizeType(), false); Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); if (Arg.isInvalid()) return true; TheCall->setArg(2, Arg.get()); } return false; } /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result) { Expr *Arg = TheCall->getArg(ArgNum); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; if (!Arg->isIntegerConstantExpr(Result, Context)) return Diag(TheCall->getLocStart(), diag::err_constant_integer_arg_type) << FDecl->getDeclName() << Arg->getSourceRange(); return false; } /// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High) { llvm::APSInt Result; // We can't check the value of a dependent argument. Expr *Arg = TheCall->getArg(ArgNum); if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; // Check constant-ness first. if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result.getSExtValue() < Low || Result.getSExtValue() > High) return Diag(TheCall->getLocStart(), diag::err_argument_invalid_range) << Low << High << Arg->getSourceRange(); return false; } +/// SemaBuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr +/// TheCall is a constant expression is a multiple of Num.. +bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Num) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + if (Result.getSExtValue() % Num != 0) + return Diag(TheCall->getLocStart(), diag::err_argument_not_multiple) + << Num << Arg->getSourceRange(); + + return false; +} + /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, unsigned ExpectedFieldNum, bool AllowName) { bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64 || BuiltinID == ARM::BI__builtin_arm_rsr || BuiltinID == ARM::BI__builtin_arm_rsrp || BuiltinID == ARM::BI__builtin_arm_wsr || BuiltinID == ARM::BI__builtin_arm_wsrp; bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64 || BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || BuiltinID == AArch64::BI__builtin_arm_wsrp; assert((IsARMBuiltin || IsAArch64Builtin) && "Unexpected ARM builtin."); // We can't check the value of a dependent argument. Expr *Arg = TheCall->getArg(ArgNum); if (Arg->isTypeDependent() || Arg->isValueDependent()) return false; // Check if the argument is a string literal. if (!isa(Arg->IgnoreParenImpCasts())) return Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal) << Arg->getSourceRange(); // Check the type of special register given. StringRef Reg = cast(Arg->IgnoreParenImpCasts())->getString(); SmallVector Fields; Reg.split(Fields, ":"); if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1)) return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) << Arg->getSourceRange(); // If the string is the name of a register then we cannot check that it is // valid here but if the string is of one the forms described in ACLE then we // can check that the supplied fields are integers and within the valid // ranges. if (Fields.size() > 1) { bool FiveFields = Fields.size() == 5; bool ValidString = true; if (IsARMBuiltin) { ValidString &= Fields[0].startswith_lower("cp") || Fields[0].startswith_lower("p"); if (ValidString) Fields[0] = Fields[0].drop_front(Fields[0].startswith_lower("cp") ? 2 : 1); ValidString &= Fields[2].startswith_lower("c"); if (ValidString) Fields[2] = Fields[2].drop_front(1); if (FiveFields) { ValidString &= Fields[3].startswith_lower("c"); if (ValidString) Fields[3] = Fields[3].drop_front(1); } } SmallVector Ranges; if (FiveFields) Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 7, 15, 15}); else Ranges.append({15, 7, 15}); for (unsigned i=0; i= 0 && IntField <= Ranges[i]); } if (!ValidString) return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg) << Arg->getSourceRange(); } else if (IsAArch64Builtin && Fields.size() == 1) { // If the register name is one of those that appear in the condition below // and the special register builtin being used is one of the write builtins, // then we require that the argument provided for writing to the register // is an integer constant expression. This is because it will be lowered to // an MSR (immediate) instruction, so we need to know the immediate at // compile time. if (TheCall->getNumArgs() != 2) return false; std::string RegLower = Reg.lower(); if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" && RegLower != "pan" && RegLower != "uao") return false; return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); } return false; } /// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_unsupported) << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd()); Expr *Arg = TheCall->getArg(1); llvm::APSInt Result; // TODO: This is less than ideal. Overload this to take a value. if (SemaBuiltinConstantArg(TheCall, 1, Result)) return true; if (Result != 1) return Diag(TheCall->getLocStart(), diag::err_builtin_longjmp_invalid_val) << SourceRange(Arg->getLocStart(), Arg->getLocEnd()); return false; } /// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). /// This checks that the target supports __builtin_setjmp. bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getLocStart(), diag::err_builtin_setjmp_unsupported) << SourceRange(TheCall->getLocStart(), TheCall->getLocEnd()); return false; } namespace { class UncoveredArgHandler { enum { Unknown = -1, AllCovered = -2 }; signed FirstUncoveredArg; SmallVector DiagnosticExprs; public: UncoveredArgHandler() : FirstUncoveredArg(Unknown) { } bool hasUncoveredArg() const { return (FirstUncoveredArg >= 0); } unsigned getUncoveredArg() const { assert(hasUncoveredArg() && "no uncovered argument"); return FirstUncoveredArg; } void setAllCovered() { // A string has been found with all arguments covered, so clear out // the diagnostics. DiagnosticExprs.clear(); FirstUncoveredArg = AllCovered; } void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) { assert(NewFirstUncoveredArg >= 0 && "Outside range"); // Don't update if a previous string covers all arguments. if (FirstUncoveredArg == AllCovered) return; // UncoveredArgHandler tracks the highest uncovered argument index // and with it all the strings that match this index. if (NewFirstUncoveredArg == FirstUncoveredArg) DiagnosticExprs.push_back(StrExpr); else if (NewFirstUncoveredArg > FirstUncoveredArg) { DiagnosticExprs.clear(); DiagnosticExprs.push_back(StrExpr); FirstUncoveredArg = NewFirstUncoveredArg; } } void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr); }; enum StringLiteralCheckType { SLCT_NotALiteral, SLCT_UncheckedLiteral, SLCT_CheckedLiteral }; } // end anonymous namespace static void CheckFormatString(Sema &S, const StringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a // format string, we will usually need to emit a warning. // True string literals are then checked by CheckFormatString. static StringLiteralCheckType checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) { tryAgain: if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; E = E->IgnoreParenCasts(); if (E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) // Technically -Wformat-nonliteral does not warn about this case. // The behavior of printf and friends in this case is implementation // dependent. Ideally if the format string cannot be null then // it should have a 'nonnull' attribute in the function prototype. return SLCT_UncheckedLiteral; switch (E->getStmtClass()) { case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { // The expression is a literal if both sub-expressions were, and it was // completely checked only if both sub-expressions were checked. const AbstractConditionalOperator *C = cast(E); // Determine whether it is necessary to check both sub-expressions, for // example, because the condition expression is a constant that can be // evaluated at compile time. bool CheckLeft = true, CheckRight = true; bool Cond; if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) { if (Cond) CheckRight = false; else CheckLeft = false; } StringLiteralCheckType Left; if (!CheckLeft) Left = SLCT_UncheckedLiteral; else { Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg); if (Left == SLCT_NotALiteral || !CheckRight) return Left; } StringLiteralCheckType Right = checkFormatStringExpr(S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg); return (CheckLeft && Left < Right) ? Left : Right; } case Stmt::ImplicitCastExprClass: { E = cast(E)->getSubExpr(); goto tryAgain; } case Stmt::OpaqueValueExprClass: if (const Expr *src = cast(E)->getSourceExpr()) { E = src; goto tryAgain; } return SLCT_NotALiteral; case Stmt::PredefinedExprClass: // While __func__, etc., are technically not string literals, they // cannot contain format specifiers and thus are not a security // liability. return SLCT_UncheckedLiteral; case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast(E); // As an exception, do not flag errors for variables binding to // const string literals. if (const VarDecl *VD = dyn_cast(DR->getDecl())) { bool isConstant = false; QualType T = DR->getType(); if (const ArrayType *AT = S.Context.getAsArrayType(T)) { isConstant = AT->getElementType().isConstant(S.Context); } else if (const PointerType *PT = T->getAs()) { isConstant = T.isConstant(S.Context) && PT->getPointeeType().isConstant(S.Context); } else if (T->isObjCObjectPointerType()) { // In ObjC, there is usually no "const ObjectPointer" type, // so don't check if the pointee type is constant. isConstant = T.isConstant(S.Context); } if (isConstant) { if (const Expr *Init = VD->getAnyInitializer()) { // Look through initializers like const char c[] = { "foo" } if (const InitListExpr *InitList = dyn_cast(Init)) { if (InitList->isStringLiteralInit()) Init = InitList->getInit(0)->IgnoreParenImpCasts(); } return checkFormatStringExpr(S, Init, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, /*InFunctionCall*/false, CheckedVarArgs, UncoveredArg); } } // For vprintf* functions (i.e., HasVAListArg==true), we add a // special check to see if the format string is a function parameter // of the function calling the printf function. If the function // has an attribute indicating it is a printf-like function, then we // should suppress warnings concerning non-literals being used in a call // to a vprintf function. For example: // // void // logmessage(char const *fmt __attribute__ (format (printf, 1, 2)), ...){ // va_list ap; // va_start(ap, fmt); // vprintf(fmt, ap); // Do NOT emit a warning about "fmt". // ... // } if (HasVAListArg) { if (const ParmVarDecl *PV = dyn_cast(VD)) { if (const NamedDecl *ND = dyn_cast(PV->getDeclContext())) { int PVIndex = PV->getFunctionScopeIndex() + 1; for (const auto *PVFormat : ND->specific_attrs()) { // adjust for implicit parameter if (const CXXMethodDecl *MD = dyn_cast(ND)) if (MD->isInstance()) ++PVIndex; // We also check if the formats are compatible. // We can't pass a 'scanf' string to a 'printf' function. if (PVIndex == PVFormat->getFormatIdx() && Type == S.GetFormatStringType(PVFormat)) return SLCT_UncheckedLiteral; } } } } } return SLCT_NotALiteral; } case Stmt::CallExprClass: case Stmt::CXXMemberCallExprClass: { const CallExpr *CE = cast(E); if (const NamedDecl *ND = dyn_cast_or_null(CE->getCalleeDecl())) { if (const FormatArgAttr *FA = ND->getAttr()) { unsigned ArgIndex = FA->getFormatIdx(); if (const CXXMethodDecl *MD = dyn_cast(ND)) if (MD->isInstance()) --ArgIndex; const Expr *Arg = CE->getArg(ArgIndex - 1); return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg); } else if (const FunctionDecl *FD = dyn_cast(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || BuiltinID == Builtin::BI__builtin___NSStringMakeConstantString) { const Expr *Arg = CE->getArg(0); return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, UncoveredArg); } } } return SLCT_NotALiteral; } case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: { const StringLiteral *StrE = nullptr; if (const ObjCStringLiteral *ObjCFExpr = dyn_cast(E)) StrE = ObjCFExpr->getString(); else StrE = cast(E); if (StrE) { CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx, firstDataArg, Type, InFunctionCall, CallType, CheckedVarArgs, UncoveredArg); return SLCT_CheckedLiteral; } return SLCT_NotALiteral; } default: return SLCT_NotALiteral; } } Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch(Format->getType()->getName()) .Case("scanf", FST_Scanf) .Cases("printf", "printf0", FST_Printf) .Cases("NSString", "CFString", FST_NSString) .Case("strftime", FST_Strftime) .Case("strfmon", FST_Strfmon) .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) .Case("freebsd_kprintf", FST_FreeBSDKPrintf) .Case("os_trace", FST_OSTrace) .Default(FST_Unknown); } /// CheckFormatArguments - Check calls to printf and scanf (and similar /// functions) for correct use of format strings. /// Returns true if a format string has been fully checked. bool Sema::CheckFormatArguments(const FormatAttr *Format, ArrayRef Args, bool IsCXXMember, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs) { FormatStringInfo FSI; if (getFormatStringInfo(Format, IsCXXMember, &FSI)) return CheckFormatArguments(Args, FSI.HasVAListArg, FSI.FormatIdx, FSI.FirstDataArg, GetFormatStringType(Format), CallType, Loc, Range, CheckedVarArgs); return false; } bool Sema::CheckFormatArguments(ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, FormatStringType Type, VariadicCallType CallType, SourceLocation Loc, SourceRange Range, llvm::SmallBitVector &CheckedVarArgs) { // CHECK: printf/scanf-like function is called with no format string. if (format_idx >= Args.size()) { Diag(Loc, diag::warn_missing_format_string) << Range; return false; } const Expr *OrigFormatExpr = Args[format_idx]->IgnoreParenCasts(); // CHECK: format string is not a string literal. // // Dynamically generated format strings are difficult to // automatically vet at compile time. Requiring that format strings // are string literals: (1) permits the checking of format strings by // the compiler and thereby (2) can practically remove the source of // many format string exploits. // Format string can be either ObjC string (e.g. @"%d") or // C string (e.g. "%d") // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. UncoveredArgHandler UncoveredArg; StringLiteralCheckType CT = checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, /*IsFunctionCall*/true, CheckedVarArgs, UncoveredArg); // Generate a diagnostic where an uncovered argument is detected. if (UncoveredArg.hasUncoveredArg()) { unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg; assert(ArgIdx < Args.size() && "ArgIdx outside bounds"); UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]); } if (CT != SLCT_NotALiteral) // Literal format string found, check done! return CT == SLCT_CheckedLiteral; // Strftime is particular as it always uses a single 'time' argument, // so it is safe to pass a non-literal string. if (Type == FST_Strftime) return false; // Do not emit diag when the string param is a macro expansion and the // format is either NSString or CFString. This is a hack to prevent // diag when using the NSLocalizedString and CFCopyLocalizedString macros // which are usually used in place of NS and CF string literals. SourceLocation FormatLoc = Args[format_idx]->getLocStart(); if (Type == FST_NSString && SourceMgr.isInSystemMacro(FormatLoc)) return false; // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. if (Args.size() == firstDataArg) { Diag(FormatLoc, diag::warn_format_nonliteral_noargs) << OrigFormatExpr->getSourceRange(); switch (Type) { default: break; case FST_Kprintf: case FST_FreeBSDKPrintf: case FST_Printf: Diag(FormatLoc, diag::note_format_security_fixit) << FixItHint::CreateInsertion(FormatLoc, "\"%s\", "); break; case FST_NSString: Diag(FormatLoc, diag::note_format_security_fixit) << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", "); break; } } else { Diag(FormatLoc, diag::warn_format_nonliteral) << OrigFormatExpr->getSourceRange(); } return false; } namespace { class CheckFormatHandler : public analyze_format_string::FormatStringHandler { protected: Sema &S; const StringLiteral *FExpr; const Expr *OrigFormatExpr; const unsigned FirstDataArg; const unsigned NumDataArgs; const char *Beg; // Start of format string. const bool HasVAListArg; ArrayRef Args; unsigned FormatIdx; llvm::SmallBitVector CoveredArgs; bool usesPositionalArgs; bool atFirstArg; bool inFunctionCall; Sema::VariadicCallType CallType; llvm::SmallBitVector &CheckedVarArgs; UncoveredArgHandler &UncoveredArg; public: CheckFormatHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, ArrayRef Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType callType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), usesPositionalArgs(false), atFirstArg(true), inFunctionCall(inFunctionCall), CallType(callType), CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } void DoneProcessing(); void HandleIncompleteSpecifier(const char *startSpecifier, unsigned specifierLen) override; void HandleInvalidLengthModifier( const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, unsigned DiagID); void HandleNonStandardLengthModifier( const analyze_format_string::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen); void HandleNonStandardConversionSpecifier( const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen); void HandlePosition(const char *startPos, unsigned posLen) override; void HandleInvalidPosition(const char *startSpecifier, unsigned specifierLen, analyze_format_string::PositionContext p) override; void HandleZeroPosition(const char *startPos, unsigned posLen) override; void HandleNullChar(const char *nullCharacter) override; template static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, const PartialDiagnostic &PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, ArrayRef Fixit = None); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, const char *startSpec, unsigned specifierLen, const char *csStart, unsigned csLen); void HandlePositionalNonpositionalArgs(SourceLocation Loc, const char *startSpec, unsigned specifierLen); SourceRange getFormatStringRange(); CharSourceRange getSpecifierRange(const char *startSpecifier, unsigned specifierLen); SourceLocation getLocationOfByte(const char *x); const Expr *getDataArg(unsigned i) const; bool CheckNumArgs(const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, unsigned argIndex); template void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, ArrayRef Fixit = None); }; } // end anonymous namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); } CharSourceRange CheckFormatHandler:: getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { SourceLocation Start = getLocationOfByte(startSpecifier); SourceLocation End = getLocationOfByte(startSpecifier + specifierLen - 1); // Advance the end SourceLocation by one due to half-open ranges. End = End.getLocWithOffset(1); return CharSourceRange::getCharRange(Start, End); } SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) { return S.getLocationOfStringLiteralByte(FExpr, x - Beg); } void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, unsigned specifierLen){ EmitFormatDiagnostic(S.PDiag(diag::warn_printf_incomplete_specifier), getLocationOfByte(startSpecifier), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); } void CheckFormatHandler::HandleInvalidLengthModifier( const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, unsigned DiagID) { using namespace analyze_format_string; const LengthModifier &LM = FS.getLengthModifier(); CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); // See if we know how to fix this length modifier. Optional FixedLM = FS.getCorrectedLengthModifier(); if (FixedLM) { EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), getLocationOfByte(LM.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) << FixedLM->toString() << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); } else { FixItHint Hint; if (DiagID == diag::warn_format_nonsensical_length) Hint = FixItHint::CreateRemoval(LMRange); EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), getLocationOfByte(LM.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen), Hint); } } void CheckFormatHandler::HandleNonStandardLengthModifier( const analyze_format_string::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { using namespace analyze_format_string; const LengthModifier &LM = FS.getLengthModifier(); CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); // See if we know how to fix this length modifier. Optional FixedLM = FS.getCorrectedLengthModifier(); if (FixedLM) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString() << 0, getLocationOfByte(LM.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) << FixedLM->toString() << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); } else { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString() << 0, getLocationOfByte(LM.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); } } void CheckFormatHandler::HandleNonStandardConversionSpecifier( const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen) { using namespace analyze_format_string; // See if we know how to fix this conversion specifier. Optional FixedCS = CS.getStandardSpecifier(); if (FixedCS) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString() << /*conversion specifier*/1, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength()); S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier) << FixedCS->toString() << FixItHint::CreateReplacement(CSRange, FixedCS->toString()); } else { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString() << /*conversion specifier*/1, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); } } void CheckFormatHandler::HandlePosition(const char *startPos, unsigned posLen) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_positional_arg), getLocationOfByte(startPos), /*IsStringLocation*/true, getSpecifierRange(startPos, posLen)); } void CheckFormatHandler::HandleInvalidPosition(const char *startPos, unsigned posLen, analyze_format_string::PositionContext p) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_positional_specifier) << (unsigned) p, getLocationOfByte(startPos), /*IsStringLocation*/true, getSpecifierRange(startPos, posLen)); } void CheckFormatHandler::HandleZeroPosition(const char *startPos, unsigned posLen) { EmitFormatDiagnostic(S.PDiag(diag::warn_format_zero_positional_specifier), getLocationOfByte(startPos), /*IsStringLocation*/true, getSpecifierRange(startPos, posLen)); } void CheckFormatHandler::HandleNullChar(const char *nullCharacter) { if (!isa(OrigFormatExpr)) { // The presence of a null character is likely an error. EmitFormatDiagnostic( S.PDiag(diag::warn_printf_format_string_contains_null_char), getLocationOfByte(nullCharacter), /*IsStringLocation*/true, getFormatStringRange()); } } // Note that this may return NULL if there was an error parsing or building // one of the argument expressions. const Expr *CheckFormatHandler::getDataArg(unsigned i) const { return Args[FirstDataArg + i]; } void CheckFormatHandler::DoneProcessing() { // Does the number of data arguments exceed the number of // format conversions in the format string? if (!HasVAListArg) { // Find any arguments that weren't covered. CoveredArgs.flip(); signed notCoveredArg = CoveredArgs.find_first(); if (notCoveredArg >= 0) { assert((unsigned)notCoveredArg < NumDataArgs); UncoveredArg.Update(notCoveredArg, OrigFormatExpr); } else { UncoveredArg.setAllCovered(); } } } void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr) { assert(hasUncoveredArg() && DiagnosticExprs.size() > 0 && "Invalid state"); if (!ArgExpr) return; SourceLocation Loc = ArgExpr->getLocStart(); if (S.getSourceManager().isInSystemMacro(Loc)) return; PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used); for (auto E : DiagnosticExprs) PDiag << E->getSourceRange(); CheckFormatHandler::EmitFormatDiagnostic( S, IsFunctionCall, DiagnosticExprs[0], PDiag, Loc, /*IsStringLocation*/false, DiagnosticExprs[0]->getSourceRange()); } bool CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, const char *startSpec, unsigned specifierLen, const char *csStart, unsigned csLen) { bool keepGoing = true; if (argIndex < NumDataArgs) { // Consider the argument coverered, even though the specifier doesn't // make sense. CoveredArgs.set(argIndex); } else { // If argIndex exceeds the number of data arguments we // don't issue a warning because that is just a cascade of warnings (and // they may have intended '%%' anyway). We don't want to continue processing // the format string after this point, however, as we will like just get // gibberish when trying to match arguments. keepGoing = false; } StringRef Specifier(csStart, csLen); // If the specifier in non-printable, it could be the first byte of a UTF-8 // sequence. In that case, print the UTF-8 code point. If not, print the byte // hex value. std::string CodePointStr; if (!llvm::sys::locale::isPrint(*csStart)) { UTF32 CodePoint; const UTF8 **B = reinterpret_cast(&csStart); const UTF8 *E = reinterpret_cast(csStart + csLen); ConversionResult Result = llvm::convertUTF8Sequence(B, E, &CodePoint, strictConversion); if (Result != conversionOK) { unsigned char FirstChar = *csStart; CodePoint = (UTF32)FirstChar; } llvm::raw_string_ostream OS(CodePointStr); if (CodePoint < 256) OS << "\\x" << llvm::format("%02x", CodePoint); else if (CodePoint <= 0xFFFF) OS << "\\u" << llvm::format("%04x", CodePoint); else OS << "\\U" << llvm::format("%08x", CodePoint); OS.flush(); Specifier = CodePointStr; } EmitFormatDiagnostic( S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc, /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen)); return keepGoing; } void CheckFormatHandler::HandlePositionalNonpositionalArgs(SourceLocation Loc, const char *startSpec, unsigned specifierLen) { EmitFormatDiagnostic( S.PDiag(diag::warn_format_mix_positional_nonpositional_args), Loc, /*isStringLoc*/true, getSpecifierRange(startSpec, specifierLen)); } bool CheckFormatHandler::CheckNumArgs( const analyze_format_string::FormatSpecifier &FS, const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen, unsigned argIndex) { if (argIndex >= NumDataArgs) { PartialDiagnostic PDiag = FS.usesPositionalArg() ? (S.PDiag(diag::warn_printf_positional_arg_exceeds_data_args) << (argIndex+1) << NumDataArgs) : S.PDiag(diag::warn_printf_insufficient_data_args); EmitFormatDiagnostic( PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); // Since more arguments than conversion tokens are given, by extension // all arguments are covered, so mark this as so. UncoveredArg.setAllCovered(); return false; } return true; } template void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation Loc, bool IsStringLocation, Range StringRange, ArrayRef FixIt) { EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag, Loc, IsStringLocation, StringRange, FixIt); } /// \brief If the format string is not within the funcion call, emit a note /// so that the function call and string are in diagnostic messages. /// /// \param InFunctionCall if true, the format string is within the function /// call and only one diagnostic message will be produced. Otherwise, an /// extra note will be emitted pointing to location of the format string. /// /// \param ArgumentExpr the expression that is passed as the format string /// argument in the function call. Used for getting locations when two /// diagnostics are emitted. /// /// \param PDiag the callee should already have provided any strings for the /// diagnostic message. This function only adds locations and fixits /// to diagnostics. /// /// \param Loc primary location for diagnostic. If two diagnostics are /// required, one will be at Loc and a new SourceLocation will be created for /// the other one. /// /// \param IsStringLocation if true, Loc points to the format string should be /// used for the note. Otherwise, Loc points to the argument list and will /// be used with PDiag. /// /// \param StringRange some or all of the string to highlight. This is /// templated so it can accept either a CharSourceRange or a SourceRange. /// /// \param FixIt optional fix it hint for the format string. template void CheckFormatHandler::EmitFormatDiagnostic( Sema &S, bool InFunctionCall, const Expr *ArgumentExpr, const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation, Range StringRange, ArrayRef FixIt) { if (InFunctionCall) { const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); D << StringRange; D << FixIt; } else { S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag) << ArgumentExpr->getSourceRange(); const Sema::SemaDiagnosticBuilder &Note = S.Diag(IsStringLocation ? Loc : StringRange.getBegin(), diag::note_format_string_defined); Note << StringRange; Note << FixIt; } } //===--- CHECK: Printf format string checking ------------------------------===// namespace { class CheckPrintfHandler : public CheckFormatHandler { bool ObjCContext; public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, bool isObjC, const char *beg, bool hasVAListArg, ArrayRef Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, formatIdx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg), ObjCContext(isObjC) {} bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; bool checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, const Expr *E); bool HandleAmount(const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen); void HandleInvalidAmount(const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalAmount &Amt, unsigned type, const char *startSpecifier, unsigned specifierLen); void HandleFlag(const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen); void HandleIgnoredFlag(const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &ignoredFlag, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen); bool checkForCStrMembers(const analyze_printf::ArgType &AT, const Expr *E); void HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) override; void HandleInvalidObjCModifierFlag(const char *startFlag, unsigned flagLen) override; void HandleObjCFlagsWithNonObjCConversion(const char *flagsStart, const char *flagsEnd, const char *conversionPosition) override; }; } // end anonymous namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier(FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, specifierLen, CS.getStart(), CS.getLength()); } bool CheckPrintfHandler::HandleAmount( const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen) { if (Amt.hasDataArgument()) { if (!HasVAListArg) { unsigned argIndex = Amt.getArgIndex(); if (argIndex >= NumDataArgs) { EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_missing_arg) << k, getLocationOfByte(Amt.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); // Don't do any more checking. We will just emit // spurious errors. return false; } // Type check the data argument. It should be an 'int'. // Although not in conformance with C99, we also allow the argument to be // an 'unsigned int' as that is a reasonably safe case. GCC also // doesn't emit a warning for that case. CoveredArgs.set(argIndex); const Expr *Arg = getDataArg(argIndex); if (!Arg) return false; QualType T = Arg->getType(); const analyze_printf::ArgType &AT = Amt.getArgType(S.Context); assert(AT.isValid()); if (!AT.matchesType(S.Context, T)) { EmitFormatDiagnostic(S.PDiag(diag::warn_printf_asterisk_wrong_type) << k << AT.getRepresentativeTypeName(S.Context) << T << Arg->getSourceRange(), getLocationOfByte(Amt.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); // Don't do any more checking. We will just emit // spurious errors. return false; } } } return true; } void CheckPrintfHandler::HandleInvalidAmount( const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalAmount &Amt, unsigned type, const char *startSpecifier, unsigned specifierLen) { const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); FixItHint fixit = Amt.getHowSpecified() == analyze_printf::OptionalAmount::Constant ? FixItHint::CreateRemoval(getSpecifierRange(Amt.getStart(), Amt.getConstantLength())) : FixItHint(); EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_optional_amount) << type << CS.toString(), getLocationOfByte(Amt.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen), fixit); } void CheckPrintfHandler::HandleFlag(const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen) { // Warn about pointless flag with a fixit removal. const analyze_printf::PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); EmitFormatDiagnostic(S.PDiag(diag::warn_printf_nonsensical_flag) << flag.toString() << CS.toString(), getLocationOfByte(flag.getPosition()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen), FixItHint::CreateRemoval( getSpecifierRange(flag.getPosition(), 1))); } void CheckPrintfHandler::HandleIgnoredFlag( const analyze_printf::PrintfSpecifier &FS, const analyze_printf::OptionalFlag &ignoredFlag, const analyze_printf::OptionalFlag &flag, const char *startSpecifier, unsigned specifierLen) { // Warn about ignored flag with a fixit removal. EmitFormatDiagnostic(S.PDiag(diag::warn_printf_ignored_flag) << ignoredFlag.toString() << flag.toString(), getLocationOfByte(ignoredFlag.getPosition()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen), FixItHint::CreateRemoval( getSpecifierRange(ignoredFlag.getPosition(), 1))); } // void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, // bool IsStringLocation, Range StringRange, // ArrayRef Fixit = None); void CheckPrintfHandler::HandleEmptyObjCModifierFlag(const char *startFlag, unsigned flagLen) { // Warn about an empty flag. EmitFormatDiagnostic(S.PDiag(diag::warn_printf_empty_objc_flag), getLocationOfByte(startFlag), /*IsStringLocation*/true, getSpecifierRange(startFlag, flagLen)); } void CheckPrintfHandler::HandleInvalidObjCModifierFlag(const char *startFlag, unsigned flagLen) { // Warn about an invalid flag. auto Range = getSpecifierRange(startFlag, flagLen); StringRef flag(startFlag, flagLen); EmitFormatDiagnostic(S.PDiag(diag::warn_printf_invalid_objc_flag) << flag, getLocationOfByte(startFlag), /*IsStringLocation*/true, Range, FixItHint::CreateRemoval(Range)); } void CheckPrintfHandler::HandleObjCFlagsWithNonObjCConversion( const char *flagsStart, const char *flagsEnd, const char *conversionPosition) { // Warn about using '[...]' without a '@' conversion. auto Range = getSpecifierRange(flagsStart, flagsEnd - flagsStart + 1); auto diag = diag::warn_printf_ObjCflags_without_ObjCConversion; EmitFormatDiagnostic(S.PDiag(diag) << StringRef(conversionPosition, 1), getLocationOfByte(conversionPosition), /*IsStringLocation*/true, Range, FixItHint::CreateRemoval(Range)); } // Determines if the specified is a C++ class or struct containing // a member with the specified name and kind (e.g. a CXXMethodDecl named // "c_str()"). template static llvm::SmallPtrSet CXXRecordMembersNamed(StringRef Name, Sema &S, QualType Ty) { const RecordType *RT = Ty->getAs(); llvm::SmallPtrSet Results; if (!RT) return Results; const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD || !RD->getDefinition()) return Results; LookupResult R(S, &S.Context.Idents.get(Name), SourceLocation(), Sema::LookupMemberName); R.suppressDiagnostics(); // We just need to include all members of the right kind turned up by the // filter, at this point. if (S.LookupQualifiedName(R, RT->getDecl())) for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { NamedDecl *decl = (*I)->getUnderlyingDecl(); if (MemberKind *FK = dyn_cast(decl)) Results.insert(FK); } return Results; } /// Check if we could call '.c_str()' on an object. /// /// FIXME: This returns the wrong results in some cases (if cv-qualifiers don't /// allow the call, or if it would be ambiguous). bool Sema::hasCStrMethod(const Expr *E) { typedef llvm::SmallPtrSet MethodSet; MethodSet Results = CXXRecordMembersNamed("c_str", *this, E->getType()); for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); MI != ME; ++MI) if ((*MI)->getMinRequiredArguments() == 0) return true; return false; } // Check if a (w)string was passed when a (w)char* was needed, and offer a // better diagnostic if so. AT is assumed to be valid. // Returns true when a c_str() conversion method is found. bool CheckPrintfHandler::checkForCStrMembers( const analyze_printf::ArgType &AT, const Expr *E) { typedef llvm::SmallPtrSet MethodSet; MethodSet Results = CXXRecordMembersNamed("c_str", S, E->getType()); for (MethodSet::iterator MI = Results.begin(), ME = Results.end(); MI != ME; ++MI) { const CXXMethodDecl *Method = *MI; if (Method->getMinRequiredArguments() == 0 && AT.matchesType(S.Context, Method->getReturnType())) { // FIXME: Suggest parens if the expression needs them. SourceLocation EndLoc = S.getLocForEndOfToken(E->getLocEnd()); S.Diag(E->getLocStart(), diag::note_printf_c_str) << "c_str()" << FixItHint::CreateInsertion(EndLoc, ".c_str()"); return true; } } return false; } bool CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { using namespace analyze_format_string; using namespace analyze_printf; const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); if (FS.consumesDataArgument()) { if (atFirstArg) { atFirstArg = false; usesPositionalArgs = FS.usesPositionalArg(); } else if (usesPositionalArgs != FS.usesPositionalArg()) { HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()), startSpecifier, specifierLen); return false; } } // First check if the field width, precision, and conversion specifier // have matching data arguments. if (!HandleAmount(FS.getFieldWidth(), /* field width */ 0, startSpecifier, specifierLen)) { return false; } if (!HandleAmount(FS.getPrecision(), /* precision */ 1, startSpecifier, specifierLen)) { return false; } if (!CS.consumesDataArgument()) { // FIXME: Technically specifying a precision or field width here // makes no sense. Worth issuing a warning at some point. return true; } // Consume the argument. unsigned argIndex = FS.getArgIndex(); if (argIndex < NumDataArgs) { // The check to see if the argIndex is valid will come later. // We set the bit here because we may exit early from this // function if we encounter some other error. CoveredArgs.set(argIndex); } // FreeBSD kernel extensions. if (CS.getKind() == ConversionSpecifier::FreeBSDbArg || CS.getKind() == ConversionSpecifier::FreeBSDDArg) { // We need at least two arguments. if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex + 1)) return false; // Claim the second argument. CoveredArgs.set(argIndex + 1); // Type check the first argument (int for %b, pointer for %D) const Expr *Ex = getDataArg(argIndex); const analyze_printf::ArgType &AT = (CS.getKind() == ConversionSpecifier::FreeBSDbArg) ? ArgType(S.Context.IntTy) : ArgType::CPointerTy; if (AT.isValid() && !AT.matchesType(S.Context, Ex->getType())) EmitFormatDiagnostic( S.PDiag(diag::warn_format_conversion_argument_type_mismatch) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/false, getSpecifierRange(startSpecifier, specifierLen)); // Type check the second argument (char * for both %b and %D) Ex = getDataArg(argIndex + 1); const analyze_printf::ArgType &AT2 = ArgType::CStrTy; if (AT2.isValid() && !AT2.matchesType(S.Context, Ex->getType())) EmitFormatDiagnostic( S.PDiag(diag::warn_format_conversion_argument_type_mismatch) << AT2.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/false, getSpecifierRange(startSpecifier, specifierLen)); return true; } // Check for using an Objective-C specific conversion specifier // in a non-ObjC literal. if (!ObjCContext && CS.isObjCArg()) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, specifierLen); } // Check for invalid use of field width if (!FS.hasValidFieldWidth()) { HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, startSpecifier, specifierLen); } // Check for invalid use of precision if (!FS.hasValidPrecision()) { HandleInvalidAmount(FS, FS.getPrecision(), /* precision */ 1, startSpecifier, specifierLen); } // Check each flag does not conflict with any other component. if (!FS.hasValidThousandsGroupingPrefix()) HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); if (!FS.hasValidLeadingZeros()) HandleFlag(FS, FS.hasLeadingZeros(), startSpecifier, specifierLen); if (!FS.hasValidPlusPrefix()) HandleFlag(FS, FS.hasPlusPrefix(), startSpecifier, specifierLen); if (!FS.hasValidSpacePrefix()) HandleFlag(FS, FS.hasSpacePrefix(), startSpecifier, specifierLen); if (!FS.hasValidAlternativeForm()) HandleFlag(FS, FS.hasAlternativeForm(), startSpecifier, specifierLen); if (!FS.hasValidLeftJustified()) HandleFlag(FS, FS.isLeftJustified(), startSpecifier, specifierLen); // Check that flags are not ignored by another flag if (FS.hasSpacePrefix() && FS.hasPlusPrefix()) // ' ' ignored by '+' HandleIgnoredFlag(FS, FS.hasSpacePrefix(), FS.hasPlusPrefix(), startSpecifier, specifierLen); if (FS.hasLeadingZeros() && FS.isLeftJustified()) // '0' ignored by '-' HandleIgnoredFlag(FS, FS.hasLeadingZeros(), FS.isLeftJustified(), startSpecifier, specifierLen); // Check the length modifier is valid with the given conversion specifier. if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); else if (!FS.hasStandardLengthConversionCombination()) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_non_standard_conversion_spec); if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); // The remaining checks depend on the data arguments. if (HasVAListArg) return true; if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; const Expr *Arg = getDataArg(argIndex); if (!Arg) return true; return checkFormatExpr(FS, startSpecifier, specifierLen, Arg); } static bool requiresParensToAddCast(const Expr *E) { // FIXME: We should have a general way to reason about operator // precedence and whether parens are actually needed here. // Take care of a few common cases where they aren't. const Expr *Inside = E->IgnoreImpCasts(); if (const PseudoObjectExpr *POE = dyn_cast(Inside)) Inside = POE->getSyntacticForm()->IgnoreImpCasts(); switch (Inside->getStmtClass()) { case Stmt::ArraySubscriptExprClass: case Stmt::CallExprClass: case Stmt::CharacterLiteralClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::DeclRefExprClass: case Stmt::FloatingLiteralClass: case Stmt::IntegerLiteralClass: case Stmt::MemberExprClass: case Stmt::ObjCArrayLiteralClass: case Stmt::ObjCBoolLiteralExprClass: case Stmt::ObjCBoxedExprClass: case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCEncodeExprClass: case Stmt::ObjCIvarRefExprClass: case Stmt::ObjCMessageExprClass: case Stmt::ObjCPropertyRefExprClass: case Stmt::ObjCStringLiteralClass: case Stmt::ObjCSubscriptRefExprClass: case Stmt::ParenExprClass: case Stmt::StringLiteralClass: case Stmt::UnaryOperatorClass: return false; default: return true; } } static std::pair shouldNotPrintDirectly(const ASTContext &Context, QualType IntendedTy, const Expr *E) { // Use a 'while' to peel off layers of typedefs. QualType TyTy = IntendedTy; while (const TypedefType *UserTy = TyTy->getAs()) { StringRef Name = UserTy->getDecl()->getName(); QualType CastTy = llvm::StringSwitch(Name) .Case("NSInteger", Context.LongTy) .Case("NSUInteger", Context.UnsignedLongTy) .Case("SInt32", Context.IntTy) .Case("UInt32", Context.UnsignedIntTy) .Default(QualType()); if (!CastTy.isNull()) return std::make_pair(CastTy, Name); TyTy = UserTy->desugar(); } // Strip parens if necessary. if (const ParenExpr *PE = dyn_cast(E)) return shouldNotPrintDirectly(Context, PE->getSubExpr()->getType(), PE->getSubExpr()); // If this is a conditional expression, then its result type is constructed // via usual arithmetic conversions and thus there might be no necessary // typedef sugar there. Recurse to operands to check for NSInteger & // Co. usage condition. if (const ConditionalOperator *CO = dyn_cast(E)) { QualType TrueTy, FalseTy; StringRef TrueName, FalseName; std::tie(TrueTy, TrueName) = shouldNotPrintDirectly(Context, CO->getTrueExpr()->getType(), CO->getTrueExpr()); std::tie(FalseTy, FalseName) = shouldNotPrintDirectly(Context, CO->getFalseExpr()->getType(), CO->getFalseExpr()); if (TrueTy == FalseTy) return std::make_pair(TrueTy, TrueName); else if (TrueTy.isNull()) return std::make_pair(FalseTy, FalseName); else if (FalseTy.isNull()) return std::make_pair(TrueTy, TrueName); } return std::make_pair(QualType(), StringRef()); } bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, unsigned SpecifierLen, const Expr *E) { using namespace analyze_format_string; using namespace analyze_printf; // Now type check the data expression that matches the // format specifier. const analyze_printf::ArgType &AT = FS.getArgType(S.Context, ObjCContext); if (!AT.isValid()) return true; QualType ExprTy = E->getType(); while (const TypeOfExprType *TET = dyn_cast(ExprTy)) { ExprTy = TET->getUnderlyingExpr()->getType(); } analyze_printf::ArgType::MatchKind match = AT.matchesType(S.Context, ExprTy); if (match == analyze_printf::ArgType::Match) { return true; } // Look through argument promotions for our error message's reported type. // This includes the integral and floating promotions, but excludes array // and function pointer decay; seeing that an argument intended to be a // string has type 'char [6]' is probably more confusing than 'char *'. if (const ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() == CK_IntegralCast || ICE->getCastKind() == CK_FloatingCast) { E = ICE->getSubExpr(); ExprTy = E->getType(); // Check if we didn't match because of an implicit cast from a 'char' // or 'short' to an 'int'. This is done because printf is a varargs // function. if (ICE->getType() == S.Context.IntTy || ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression. if (AT.matchesType(S.Context, ExprTy)) return true; } } } else if (const CharacterLiteral *CL = dyn_cast(E)) { // Special case for 'a', which has type 'int' in C. // Note, however, that we do /not/ want to treat multibyte constants like // 'MooV' as characters! This form is deprecated but still exists. if (ExprTy == S.Context.IntTy) if (llvm::isUIntN(S.Context.getCharWidth(), CL->getValue())) ExprTy = S.Context.CharTy; } // Look through enums to their underlying type. bool IsEnum = false; if (auto EnumTy = ExprTy->getAs()) { ExprTy = EnumTy->getDecl()->getIntegerType(); IsEnum = true; } // %C in an Objective-C context prints a unichar, not a wchar_t. // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. QualType IntendedTy = ExprTy; if (ObjCContext && FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { if (ExprTy->isIntegralOrUnscopedEnumerationType() && !ExprTy->isCharType()) { // 'unichar' is defined as a typedef of unsigned short, but we should // prefer using the typedef if it is visible. IntendedTy = S.Context.UnsignedShortTy; // While we are here, check if the value is an IntegerLiteral that happens // to be within the valid range. if (const IntegerLiteral *IL = dyn_cast(E)) { const llvm::APInt &V = IL->getValue(); if (V.getActiveBits() <= S.Context.getTypeSize(IntendedTy)) return true; } LookupResult Result(S, &S.Context.Idents.get("unichar"), E->getLocStart(), Sema::LookupOrdinaryName); if (S.LookupName(Result, S.getCurScope())) { NamedDecl *ND = Result.getFoundDecl(); if (TypedefNameDecl *TD = dyn_cast(ND)) if (TD->getUnderlyingType() == IntendedTy) IntendedTy = S.Context.getTypedefType(TD); } } } // Special-case some of Darwin's platform-independence types by suggesting // casts to primitive types that are known to be large enough. bool ShouldNotPrintDirectly = false; StringRef CastTyName; if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { QualType CastTy; std::tie(CastTy, CastTyName) = shouldNotPrintDirectly(S.Context, IntendedTy, E); if (!CastTy.isNull()) { IntendedTy = CastTy; ShouldNotPrintDirectly = true; } } // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, ObjCContext); if (success) { // Get the fix string from the fixed format specifier SmallString<16> buf; llvm::raw_svector_ostream os(buf); fixedFS.toString(os); CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); if (IntendedTy == ExprTy && !ShouldNotPrintDirectly) { unsigned diag = diag::warn_format_conversion_argument_type_mismatch; if (match == analyze_format_string::ArgType::NoMatchPedantic) { diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; } // In this case, the specifier is wrong and should be changed to match // the argument. EmitFormatDiagnostic(S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << IntendedTy << IsEnum << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/ false, SpecRange, FixItHint::CreateReplacement(SpecRange, os.str())); } else { // The canonical type for formatting this value is different from the // actual type of the expression. (This occurs, for example, with Darwin's // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but // should be printed as 'long' for 64-bit compatibility.) // Rather than emitting a normal format/argument mismatch, we want to // add a cast to the recommended type (and correct the format string // if necessary). SmallString<16> CastBuf; llvm::raw_svector_ostream CastFix(CastBuf); CastFix << "("; IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); CastFix << ")"; SmallVector Hints; if (!AT.matchesType(S.Context, IntendedTy)) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast(E)) { // If there's already a cast present, just replace it. SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc()); Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str())); } else if (!requiresParensToAddCast(E)) { // If the expression has high enough precedence, // just write the C-style cast. Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(), CastFix.str())); } else { // Otherwise, add parens around the expression as well as the cast. CastFix << "("; Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(), CastFix.str())); SourceLocation After = S.getLocForEndOfToken(E->getLocEnd()); Hints.push_back(FixItHint::CreateInsertion(After, ")")); } if (ShouldNotPrintDirectly) { // The expression has a type that should not be printed directly. // We extract the name from the typedef because we don't want to show // the underlying type in the diagnostic. StringRef Name; if (const TypedefType *TypedefTy = dyn_cast(ExprTy)) Name = TypedefTy->getDecl()->getName(); else Name = CastTyName; EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) << Name << IntendedTy << IsEnum << E->getSourceRange(), E->getLocStart(), /*IsStringLocation=*/false, SpecRange, Hints); } else { // In this case, the expression could be printed using a different // specifier, but we've decided that the specifier is probably correct // and we should cast instead. Just use the normal warning message. EmitFormatDiagnostic( S.PDiag(diag::warn_format_conversion_argument_type_mismatch) << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/false, SpecRange, Hints); } } } else { const CharSourceRange &CSR = getSpecifierRange(StartSpecifier, SpecifierLen); // Since the warning for passing non-POD types to variadic functions // was deferred until now, we emit a warning for non-POD // arguments here. switch (S.isValidVarArgType(ExprTy)) { case Sema::VAK_Valid: case Sema::VAK_ValidInCXX11: { unsigned diag = diag::warn_format_conversion_argument_type_mismatch; if (match == analyze_printf::ArgType::NoMatchPedantic) { diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; } EmitFormatDiagnostic( S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << ExprTy << IsEnum << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/ false, CSR); break; } case Sema::VAK_Undefined: case Sema::VAK_MSVCUndefined: EmitFormatDiagnostic( S.PDiag(diag::warn_non_pod_vararg_with_format_string) << S.getLangOpts().CPlusPlus11 << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/false, CSR); checkForCStrMembers(AT, E); break; case Sema::VAK_Invalid: if (ExprTy->isObjCObjectType()) EmitFormatDiagnostic( S.PDiag(diag::err_cannot_pass_objc_interface_to_vararg_format) << S.getLangOpts().CPlusPlus11 << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << CSR << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/false, CSR); else // FIXME: If this is an initializer list, suggest removing the braces // or inserting a cast to the target type. S.Diag(E->getLocStart(), diag::err_cannot_pass_to_vararg_format) << isa(E) << ExprTy << CallType << AT.getRepresentativeTypeName(S.Context) << E->getSourceRange(); break; } assert(FirstDataArg + FS.getArgIndex() < CheckedVarArgs.size() && "format string specifier index out of range"); CheckedVarArgs[FirstDataArg + FS.getArgIndex()] = true; } return true; } //===--- CHECK: Scanf format string checking ------------------------------===// namespace { class CheckScanfHandler : public CheckFormatHandler { public: CheckScanfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, ArrayRef Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, formatIdx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg) {} bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; bool HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; void HandleIncompleteScanList(const char *start, const char *end) override; }; } // end anonymous namespace void CheckScanfHandler::HandleIncompleteScanList(const char *start, const char *end) { EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_scanlist_incomplete), getLocationOfByte(end), /*IsStringLocation*/true, getSpecifierRange(start, end - start)); } bool CheckScanfHandler::HandleInvalidScanfConversionSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { const analyze_scanf::ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); return HandleInvalidConversionSpecifier(FS.getArgIndex(), getLocationOfByte(CS.getStart()), startSpecifier, specifierLen, CS.getStart(), CS.getLength()); } bool CheckScanfHandler::HandleScanfSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { using namespace analyze_scanf; using namespace analyze_format_string; const ScanfConversionSpecifier &CS = FS.getConversionSpecifier(); // Handle case where '%' and '*' don't consume an argument. These shouldn't // be used to decide if we are using positional arguments consistently. if (FS.consumesDataArgument()) { if (atFirstArg) { atFirstArg = false; usesPositionalArgs = FS.usesPositionalArg(); } else if (usesPositionalArgs != FS.usesPositionalArg()) { HandlePositionalNonpositionalArgs(getLocationOfByte(CS.getStart()), startSpecifier, specifierLen); return false; } } // Check if the field with is non-zero. const OptionalAmount &Amt = FS.getFieldWidth(); if (Amt.getHowSpecified() == OptionalAmount::Constant) { if (Amt.getConstantAmount() == 0) { const CharSourceRange &R = getSpecifierRange(Amt.getStart(), Amt.getConstantLength()); EmitFormatDiagnostic(S.PDiag(diag::warn_scanf_nonzero_width), getLocationOfByte(Amt.getStart()), /*IsStringLocation*/true, R, FixItHint::CreateRemoval(R)); } } if (!FS.consumesDataArgument()) { // FIXME: Technically specifying a precision or field width here // makes no sense. Worth issuing a warning at some point. return true; } // Consume the argument. unsigned argIndex = FS.getArgIndex(); if (argIndex < NumDataArgs) { // The check to see if the argIndex is valid will come later. // We set the bit here because we may exit early from this // function if we encounter some other error. CoveredArgs.set(argIndex); } // Check the length modifier is valid with the given conversion specifier. if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_nonsensical_length); else if (!FS.hasStandardLengthModifier()) HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); else if (!FS.hasStandardLengthConversionCombination()) HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, diag::warn_format_non_standard_conversion_spec); if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); // The remaining checks depend on the data arguments. if (HasVAListArg) return true; if (!CheckNumArgs(FS, CS, startSpecifier, specifierLen, argIndex)) return false; // Check that the argument type matches the format specifier. const Expr *Ex = getDataArg(argIndex); if (!Ex) return true; const analyze_format_string::ArgType &AT = FS.getArgType(S.Context); if (!AT.isValid()) { return true; } analyze_format_string::ArgType::MatchKind match = AT.matchesType(S.Context, Ex->getType()); if (match == analyze_format_string::ArgType::Match) { return true; } ScanfSpecifier fixedFS = FS; bool success = fixedFS.fixType(Ex->getType(), Ex->IgnoreImpCasts()->getType(), S.getLangOpts(), S.Context); unsigned diag = diag::warn_format_conversion_argument_type_mismatch; if (match == analyze_format_string::ArgType::NoMatchPedantic) { diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; } if (success) { // Get the fix string from the fixed format specifier. SmallString<128> buf; llvm::raw_svector_ostream os(buf); fixedFS.toString(os); EmitFormatDiagnostic( S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/ false, getSpecifierRange(startSpecifier, specifierLen), FixItHint::CreateReplacement( getSpecifierRange(startSpecifier, specifierLen), os.str())); } else { EmitFormatDiagnostic(S.PDiag(diag) << AT.getRepresentativeTypeName(S.Context) << Ex->getType() << false << Ex->getSourceRange(), Ex->getLocStart(), /*IsStringLocation*/ false, getSpecifierRange(startSpecifier, specifierLen)); } return true; } static void CheckFormatString(Sema &S, const StringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( S, inFunctionCall, Args[format_idx], S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } // Str - The format string. NOTE: this is NOT null-terminated! StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); // Account for cases where the string literal is truncated in a declaration. const ConstantArrayType *T = S.Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); size_t TypeSize = T->getSize().getZExtValue(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); const unsigned numDataArgs = Args.size() - firstDataArg; // Emit a warning if the string literal is truncated and does not contain an // embedded null character. if (TypeSize <= StrRef.size() && StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) { CheckFormatHandler::EmitFormatDiagnostic( S, inFunctionCall, Args[format_idx], S.PDiag(diag::warn_printf_format_string_not_null_terminated), FExpr->getLocStart(), /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange()); return; } // CHECK: empty format string? if (StrLen == 0 && numDataArgs > 0) { CheckFormatHandler::EmitFormatDiagnostic( S, inFunctionCall, Args[format_idx], S.PDiag(diag::warn_empty_format_string), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) { CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, HasVAListArg, Args, format_idx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo(), Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, Str, HasVAListArg, Args, format_idx, inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, S.getLangOpts(), S.Context.getTargetInfo())) H.DoneProcessing(); } // TODO: handle other formats } bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) { // Str - The format string. NOTE: this is NOT null-terminated! StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); // Account for cases where the string literal is truncated in a declaration. const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); size_t TypeSize = T->getSize().getZExtValue(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen, getLangOpts(), Context.getTargetInfo()); } //===--- CHECK: Warn on use of wrong absolute value function. -------------===// // Returns the related absolute value function that is larger, of 0 if one // does not exist. static unsigned getLargerAbsoluteValueFunction(unsigned AbsFunction) { switch (AbsFunction) { default: return 0; case Builtin::BI__builtin_abs: return Builtin::BI__builtin_labs; case Builtin::BI__builtin_labs: return Builtin::BI__builtin_llabs; case Builtin::BI__builtin_llabs: return 0; case Builtin::BI__builtin_fabsf: return Builtin::BI__builtin_fabs; case Builtin::BI__builtin_fabs: return Builtin::BI__builtin_fabsl; case Builtin::BI__builtin_fabsl: return 0; case Builtin::BI__builtin_cabsf: return Builtin::BI__builtin_cabs; case Builtin::BI__builtin_cabs: return Builtin::BI__builtin_cabsl; case Builtin::BI__builtin_cabsl: return 0; case Builtin::BIabs: return Builtin::BIlabs; case Builtin::BIlabs: return Builtin::BIllabs; case Builtin::BIllabs: return 0; case Builtin::BIfabsf: return Builtin::BIfabs; case Builtin::BIfabs: return Builtin::BIfabsl; case Builtin::BIfabsl: return 0; case Builtin::BIcabsf: return Builtin::BIcabs; case Builtin::BIcabs: return Builtin::BIcabsl; case Builtin::BIcabsl: return 0; } } // Returns the argument type of the absolute value function. static QualType getAbsoluteValueArgumentType(ASTContext &Context, unsigned AbsType) { if (AbsType == 0) return QualType(); ASTContext::GetBuiltinTypeError Error = ASTContext::GE_None; QualType BuiltinType = Context.GetBuiltinType(AbsType, Error); if (Error != ASTContext::GE_None) return QualType(); const FunctionProtoType *FT = BuiltinType->getAs(); if (!FT) return QualType(); if (FT->getNumParams() != 1) return QualType(); return FT->getParamType(0); } // Returns the best absolute value function, or zero, based on type and // current absolute value function. static unsigned getBestAbsFunction(ASTContext &Context, QualType ArgType, unsigned AbsFunctionKind) { unsigned BestKind = 0; uint64_t ArgSize = Context.getTypeSize(ArgType); for (unsigned Kind = AbsFunctionKind; Kind != 0; Kind = getLargerAbsoluteValueFunction(Kind)) { QualType ParamType = getAbsoluteValueArgumentType(Context, Kind); if (Context.getTypeSize(ParamType) >= ArgSize) { if (BestKind == 0) BestKind = Kind; else if (Context.hasSameType(ParamType, ArgType)) { BestKind = Kind; break; } } } return BestKind; } enum AbsoluteValueKind { AVK_Integer, AVK_Floating, AVK_Complex }; static AbsoluteValueKind getAbsoluteValueKind(QualType T) { if (T->isIntegralOrEnumerationType()) return AVK_Integer; if (T->isRealFloatingType()) return AVK_Floating; if (T->isAnyComplexType()) return AVK_Complex; llvm_unreachable("Type not integer, floating, or complex"); } // Changes the absolute value function to a different type. Preserves whether // the function is a builtin. static unsigned changeAbsFunction(unsigned AbsKind, AbsoluteValueKind ValueKind) { switch (ValueKind) { case AVK_Integer: switch (AbsKind) { default: return 0; case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsl: case Builtin::BI__builtin_cabsf: case Builtin::BI__builtin_cabs: case Builtin::BI__builtin_cabsl: return Builtin::BI__builtin_abs; case Builtin::BIfabsf: case Builtin::BIfabs: case Builtin::BIfabsl: case Builtin::BIcabsf: case Builtin::BIcabs: case Builtin::BIcabsl: return Builtin::BIabs; } case AVK_Floating: switch (AbsKind) { default: return 0; case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: case Builtin::BI__builtin_cabsf: case Builtin::BI__builtin_cabs: case Builtin::BI__builtin_cabsl: return Builtin::BI__builtin_fabsf; case Builtin::BIabs: case Builtin::BIlabs: case Builtin::BIllabs: case Builtin::BIcabsf: case Builtin::BIcabs: case Builtin::BIcabsl: return Builtin::BIfabsf; } case AVK_Complex: switch (AbsKind) { default: return 0; case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsl: return Builtin::BI__builtin_cabsf; case Builtin::BIabs: case Builtin::BIlabs: case Builtin::BIllabs: case Builtin::BIfabsf: case Builtin::BIfabs: case Builtin::BIfabsl: return Builtin::BIcabsf; } } llvm_unreachable("Unable to convert function"); } static unsigned getAbsoluteValueFunctionKind(const FunctionDecl *FDecl) { const IdentifierInfo *FnInfo = FDecl->getIdentifier(); if (!FnInfo) return 0; switch (FDecl->getBuiltinID()) { default: return 0; case Builtin::BI__builtin_abs: case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: case Builtin::BI__builtin_cabs: case Builtin::BI__builtin_cabsf: case Builtin::BI__builtin_cabsl: case Builtin::BIabs: case Builtin::BIlabs: case Builtin::BIllabs: case Builtin::BIfabs: case Builtin::BIfabsf: case Builtin::BIfabsl: case Builtin::BIcabs: case Builtin::BIcabsf: case Builtin::BIcabsl: return FDecl->getBuiltinID(); } llvm_unreachable("Unknown Builtin type"); } // If the replacement is valid, emit a note with replacement function. // Additionally, suggest including the proper header if not already included. static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, unsigned AbsKind, QualType ArgType) { bool EmitHeaderHint = true; const char *HeaderName = nullptr; const char *FunctionName = nullptr; if (S.getLangOpts().CPlusPlus && !ArgType->isAnyComplexType()) { FunctionName = "std::abs"; if (ArgType->isIntegralOrEnumerationType()) { HeaderName = "cstdlib"; } else if (ArgType->isRealFloatingType()) { HeaderName = "cmath"; } else { llvm_unreachable("Invalid Type"); } // Lookup all std::abs if (NamespaceDecl *Std = S.getStdNamespace()) { LookupResult R(S, &S.Context.Idents.get("abs"), Loc, Sema::LookupAnyName); R.suppressDiagnostics(); S.LookupQualifiedName(R, Std); for (const auto *I : R) { const FunctionDecl *FDecl = nullptr; if (const UsingShadowDecl *UsingD = dyn_cast(I)) { FDecl = dyn_cast(UsingD->getTargetDecl()); } else { FDecl = dyn_cast(I); } if (!FDecl) continue; // Found std::abs(), check that they are the right ones. if (FDecl->getNumParams() != 1) continue; // Check that the parameter type can handle the argument. QualType ParamType = FDecl->getParamDecl(0)->getType(); if (getAbsoluteValueKind(ArgType) == getAbsoluteValueKind(ParamType) && S.Context.getTypeSize(ArgType) <= S.Context.getTypeSize(ParamType)) { // Found a function, don't need the header hint. EmitHeaderHint = false; break; } } } } else { FunctionName = S.Context.BuiltinInfo.getName(AbsKind); HeaderName = S.Context.BuiltinInfo.getHeaderName(AbsKind); if (HeaderName) { DeclarationName DN(&S.Context.Idents.get(FunctionName)); LookupResult R(S, DN, Loc, Sema::LookupAnyName); R.suppressDiagnostics(); S.LookupName(R, S.getCurScope()); if (R.isSingleResult()) { FunctionDecl *FD = dyn_cast(R.getFoundDecl()); if (FD && FD->getBuiltinID() == AbsKind) { EmitHeaderHint = false; } else { return; } } else if (!R.empty()) { return; } } } S.Diag(Loc, diag::note_replace_abs_function) << FunctionName << FixItHint::CreateReplacement(Range, FunctionName); if (!HeaderName) return; if (!EmitHeaderHint) return; S.Diag(Loc, diag::note_include_header_or_declare) << HeaderName << FunctionName; } static bool IsFunctionStdAbs(const FunctionDecl *FDecl) { if (!FDecl) return false; if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr("abs")) return false; const NamespaceDecl *ND = dyn_cast(FDecl->getDeclContext()); while (ND && ND->isInlineNamespace()) { ND = dyn_cast(ND->getDeclContext()); } if (!ND || !ND->getIdentifier() || !ND->getIdentifier()->isStr("std")) return false; if (!isa(ND->getDeclContext())) return false; return true; } // Warn when using the wrong abs() function. void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl, IdentifierInfo *FnInfo) { if (Call->getNumArgs() != 1) return; unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl); bool IsStdAbs = IsFunctionStdAbs(FDecl); if (AbsKind == 0 && !IsStdAbs) return; QualType ArgType = Call->getArg(0)->IgnoreParenImpCasts()->getType(); QualType ParamType = Call->getArg(0)->getType(); // Unsigned types cannot be negative. Suggest removing the absolute value // function call. if (ArgType->isUnsignedIntegerType()) { const char *FunctionName = IsStdAbs ? "std::abs" : Context.BuiltinInfo.getName(AbsKind); Diag(Call->getExprLoc(), diag::warn_unsigned_abs) << ArgType << ParamType; Diag(Call->getExprLoc(), diag::note_remove_abs) << FunctionName << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()); return; } // Taking the absolute value of a pointer is very suspicious, they probably // wanted to index into an array, dereference a pointer, call a function, etc. if (ArgType->isPointerType() || ArgType->canDecayToPointerType()) { unsigned DiagType = 0; if (ArgType->isFunctionType()) DiagType = 1; else if (ArgType->isArrayType()) DiagType = 2; Diag(Call->getExprLoc(), diag::warn_pointer_abs) << DiagType << ArgType; return; } // std::abs has overloads which prevent most of the absolute value problems // from occurring. if (IsStdAbs) return; AbsoluteValueKind ArgValueKind = getAbsoluteValueKind(ArgType); AbsoluteValueKind ParamValueKind = getAbsoluteValueKind(ParamType); // The argument and parameter are the same kind. Check if they are the right // size. if (ArgValueKind == ParamValueKind) { if (Context.getTypeSize(ArgType) <= Context.getTypeSize(ParamType)) return; unsigned NewAbsKind = getBestAbsFunction(Context, ArgType, AbsKind); Diag(Call->getExprLoc(), diag::warn_abs_too_small) << FDecl << ArgType << ParamType; if (NewAbsKind == 0) return; emitReplacement(*this, Call->getExprLoc(), Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); return; } // ArgValueKind != ParamValueKind // The wrong type of absolute value function was used. Attempt to find the // proper one. unsigned NewAbsKind = changeAbsFunction(AbsKind, ArgValueKind); NewAbsKind = getBestAbsFunction(Context, ArgType, NewAbsKind); if (NewAbsKind == 0) return; Diag(Call->getExprLoc(), diag::warn_wrong_absolute_value_type) << FDecl << ParamValueKind << ArgValueKind; emitReplacement(*this, Call->getExprLoc(), Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); } //===--- CHECK: Standard memory functions ---------------------------------===// /// \brief Takes the expression passed to the size_t parameter of functions /// such as memcmp, strncat, etc and warns if it's a comparison. /// /// This is to catch typos like `if (memcmp(&a, &b, sizeof(a) > 0))`. static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E, IdentifierInfo *FnName, SourceLocation FnLoc, SourceLocation RParenLoc) { const BinaryOperator *Size = dyn_cast(E); if (!Size) return false; // if E is binop and op is >, <, >=, <=, ==, &&, ||: if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp()) return false; SourceRange SizeRange = Size->getSourceRange(); S.Diag(Size->getOperatorLoc(), diag::warn_memsize_comparison) << SizeRange << FnName; S.Diag(FnLoc, diag::note_memsize_comparison_paren) << FnName << FixItHint::CreateInsertion( S.getLocForEndOfToken(Size->getLHS()->getLocEnd()), ")") << FixItHint::CreateRemoval(RParenLoc); S.Diag(SizeRange.getBegin(), diag::note_memsize_comparison_cast_silence) << FixItHint::CreateInsertion(SizeRange.getBegin(), "(size_t)(") << FixItHint::CreateInsertion(S.getLocForEndOfToken(SizeRange.getEnd()), ")"); return true; } /// \brief Determine whether the given type is or contains a dynamic class type /// (e.g., whether it has a vtable). static const CXXRecordDecl *getContainedDynamicClass(QualType T, bool &IsContained) { // Look through array types while ignoring qualifiers. const Type *Ty = T->getBaseElementTypeUnsafe(); IsContained = false; const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); RD = RD ? RD->getDefinition() : nullptr; if (!RD || RD->isInvalidDecl()) return nullptr; if (RD->isDynamicClass()) return RD; // Check all the fields. If any bases were dynamic, the class is dynamic. // It's impossible for a class to transitively contain itself by value, so // infinite recursion is impossible. for (auto *FD : RD->fields()) { bool SubContained; if (const CXXRecordDecl *ContainedRD = getContainedDynamicClass(FD->getType(), SubContained)) { IsContained = true; return ContainedRD; } } return nullptr; } /// \brief If E is a sizeof expression, returns its argument expression, /// otherwise returns NULL. static const Expr *getSizeOfExprArg(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast(E)) if (SizeOf->getKind() == clang::UETT_SizeOf && !SizeOf->isArgumentType()) return SizeOf->getArgumentExpr()->IgnoreParenImpCasts(); return nullptr; } /// \brief If E is a sizeof expression, returns its argument type. static QualType getSizeOfArgType(const Expr *E) { if (const UnaryExprOrTypeTraitExpr *SizeOf = dyn_cast(E)) if (SizeOf->getKind() == clang::UETT_SizeOf) return SizeOf->getTypeOfArgument(); return QualType(); } /// \brief Check for dangerous or invalid arguments to memset(). /// /// This issues warnings on known problematic, dangerous or unspecified /// arguments to the standard 'memset', 'memcpy', 'memmove', and 'memcmp' /// function calls. /// /// \param Call The call expression to diagnose. void Sema::CheckMemaccessArguments(const CallExpr *Call, unsigned BId, IdentifierInfo *FnName) { assert(BId != 0); // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3); if (Call->getNumArgs() < ExpectedNumArgs) return; unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIstrndup ? 1 : 2); unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2); const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); if (CheckMemorySizeofForComparison(*this, LenExpr, FnName, Call->getLocStart(), Call->getRParenLoc())) return; // We have special checking when the length is a sizeof expression. QualType SizeOfArgTy = getSizeOfArgType(LenExpr); const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); llvm::FoldingSetNodeID SizeOfArgID; for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); QualType DestTy = Dest->getType(); QualType PointeeTy; if (const PointerType *DestPtrTy = DestTy->getAs()) { PointeeTy = DestPtrTy->getPointeeType(); // Never warn about void type pointers. This can be used to suppress // false positives. if (PointeeTy->isVoidType()) continue; // Catch "memset(p, 0, sizeof(p))" -- needs to be sizeof(*p). Do this by // actually comparing the expressions for equality. Because computing the // expression IDs can be expensive, we only do this if the diagnostic is // enabled. if (SizeOfArg && !Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, SizeOfArg->getExprLoc())) { // We only compute IDs for expressions if the warning is enabled, and // cache the sizeof arg's ID. if (SizeOfArgID == llvm::FoldingSetNodeID()) SizeOfArg->Profile(SizeOfArgID, Context, true); llvm::FoldingSetNodeID DestID; Dest->Profile(DestID, Context, true); if (DestID == SizeOfArgID) { // TODO: For strncpy() and friends, this could suggest sizeof(dst) // over sizeof(src) as well. unsigned ActionIdx = 0; // Default is to suggest dereferencing. StringRef ReadableName = FnName->getName(); if (const UnaryOperator *UnaryOp = dyn_cast(Dest)) if (UnaryOp->getOpcode() == UO_AddrOf) ActionIdx = 1; // If its an address-of operator, just remove it. if (!PointeeTy->isIncompleteType() && (Context.getTypeSize(PointeeTy) == Context.getCharWidth())) ActionIdx = 2; // If the pointee's size is sizeof(char), // suggest an explicit length. // If the function is defined as a builtin macro, do not show macro // expansion. SourceLocation SL = SizeOfArg->getExprLoc(); SourceRange DSR = Dest->getSourceRange(); SourceRange SSR = SizeOfArg->getSourceRange(); SourceManager &SM = getSourceManager(); if (SM.isMacroArgExpansion(SL)) { ReadableName = Lexer::getImmediateMacroName(SL, SM, LangOpts); SL = SM.getSpellingLoc(SL); DSR = SourceRange(SM.getSpellingLoc(DSR.getBegin()), SM.getSpellingLoc(DSR.getEnd())); SSR = SourceRange(SM.getSpellingLoc(SSR.getBegin()), SM.getSpellingLoc(SSR.getEnd())); } DiagRuntimeBehavior(SL, SizeOfArg, PDiag(diag::warn_sizeof_pointer_expr_memaccess) << ReadableName << PointeeTy << DestTy << DSR << SSR); DiagRuntimeBehavior(SL, SizeOfArg, PDiag(diag::warn_sizeof_pointer_expr_memaccess_note) << ActionIdx << SSR); break; } } // Also check for cases where the sizeof argument is the exact same // type as the memory argument, and where it points to a user-defined // record type. if (SizeOfArgTy != QualType()) { if (PointeeTy->isRecordType() && Context.typesAreCompatible(SizeOfArgTy, DestTy)) { DiagRuntimeBehavior(LenExpr->getExprLoc(), Dest, PDiag(diag::warn_sizeof_pointer_type_memaccess) << FnName << SizeOfArgTy << ArgIdx << PointeeTy << Dest->getSourceRange() << LenExpr->getSourceRange()); break; } } } else if (DestTy->isArrayType()) { PointeeTy = DestTy; } if (PointeeTy == QualType()) continue; // Always complain about dynamic classes. bool IsContained; if (const CXXRecordDecl *ContainedRD = getContainedDynamicClass(PointeeTy, IsContained)) { unsigned OperationType = 0; // "overwritten" if we're warning about the destination for any call // but memcmp; otherwise a verb appropriate to the call. if (ArgIdx != 0 || BId == Builtin::BImemcmp) { if (BId == Builtin::BImemcpy) OperationType = 1; else if(BId == Builtin::BImemmove) OperationType = 2; else if (BId == Builtin::BImemcmp) OperationType = 3; } DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_dyn_class_memaccess) << (BId == Builtin::BImemcmp ? ArgIdx + 2 : ArgIdx) << FnName << IsContained << ContainedRD << OperationType << Call->getCallee()->getSourceRange()); } else if (PointeeTy.hasNonTrivialObjCLifetime() && BId != Builtin::BImemset) DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::warn_arc_object_memaccess) << ArgIdx << FnName << PointeeTy << Call->getCallee()->getSourceRange()); else continue; DiagRuntimeBehavior( Dest->getExprLoc(), Dest, PDiag(diag::note_bad_memaccess_silence) << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); break; } } // A little helper routine: ignore addition and subtraction of integer literals. // This intentionally does not ignore all integer constant expressions because // we don't want to remove sizeof(). static const Expr *ignoreLiteralAdditions(const Expr *Ex, ASTContext &Ctx) { Ex = Ex->IgnoreParenCasts(); for (;;) { const BinaryOperator * BO = dyn_cast(Ex); if (!BO || !BO->isAdditiveOp()) break; const Expr *RHS = BO->getRHS()->IgnoreParenCasts(); const Expr *LHS = BO->getLHS()->IgnoreParenCasts(); if (isa(RHS)) Ex = LHS; else if (isa(LHS)) Ex = RHS; else break; } return Ex; } static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty, ASTContext &Context) { // Only handle constant-sized or VLAs, but not flexible members. if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) { // Only issue the FIXIT for arrays of size > 1. if (CAT->getSize().getSExtValue() <= 1) return false; } else if (!Ty->isVariableArrayType()) { return false; } return true; } // Warn if the user has made the 'size' argument to strlcpy or strlcat // be the size of the source, instead of the destination. void Sema::CheckStrlcpycatArguments(const CallExpr *Call, IdentifierInfo *FnName) { // Don't crash if the user has the wrong number of arguments unsigned NumArgs = Call->getNumArgs(); if ((NumArgs != 3) && (NumArgs != 4)) return; const Expr *SrcArg = ignoreLiteralAdditions(Call->getArg(1), Context); const Expr *SizeArg = ignoreLiteralAdditions(Call->getArg(2), Context); const Expr *CompareWithSrc = nullptr; if (CheckMemorySizeofForComparison(*this, SizeArg, FnName, Call->getLocStart(), Call->getRParenLoc())) return; // Look for 'strlcpy(dst, x, sizeof(x))' if (const Expr *Ex = getSizeOfExprArg(SizeArg)) CompareWithSrc = Ex; else { // Look for 'strlcpy(dst, x, strlen(x))' if (const CallExpr *SizeCall = dyn_cast(SizeArg)) { if (SizeCall->getBuiltinCallee() == Builtin::BIstrlen && SizeCall->getNumArgs() == 1) CompareWithSrc = ignoreLiteralAdditions(SizeCall->getArg(0), Context); } } if (!CompareWithSrc) return; // Determine if the argument to sizeof/strlen is equal to the source // argument. In principle there's all kinds of things you could do // here, for instance creating an == expression and evaluating it with // EvaluateAsBooleanCondition, but this uses a more direct technique: const DeclRefExpr *SrcArgDRE = dyn_cast(SrcArg); if (!SrcArgDRE) return; const DeclRefExpr *CompareWithSrcDRE = dyn_cast(CompareWithSrc); if (!CompareWithSrcDRE || SrcArgDRE->getDecl() != CompareWithSrcDRE->getDecl()) return; const Expr *OriginalSizeArg = Call->getArg(2); Diag(CompareWithSrcDRE->getLocStart(), diag::warn_strlcpycat_wrong_size) << OriginalSizeArg->getSourceRange() << FnName; // Output a FIXIT hint if the destination is an array (rather than a // pointer to an array). This could be enhanced to handle some // pointers if we know the actual size, like if DstArg is 'array+2' // we could say 'sizeof(array)-2'. const Expr *DstArg = Call->getArg(0)->IgnoreParenImpCasts(); if (!isConstantSizeArrayWithMoreThanOneElement(DstArg->getType(), Context)) return; SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; DstArg->printPretty(OS, nullptr, getPrintingPolicy()); OS << ")"; Diag(OriginalSizeArg->getLocStart(), diag::note_strlcpycat_wrong_size) << FixItHint::CreateReplacement(OriginalSizeArg->getSourceRange(), OS.str()); } /// Check if two expressions refer to the same declaration. static bool referToTheSameDecl(const Expr *E1, const Expr *E2) { if (const DeclRefExpr *D1 = dyn_cast_or_null(E1)) if (const DeclRefExpr *D2 = dyn_cast_or_null(E2)) return D1->getDecl() == D2->getDecl(); return false; } static const Expr *getStrlenExprArg(const Expr *E) { if (const CallExpr *CE = dyn_cast(E)) { const FunctionDecl *FD = CE->getDirectCallee(); if (!FD || FD->getMemoryFunctionKind() != Builtin::BIstrlen) return nullptr; return CE->getArg(0)->IgnoreParenCasts(); } return nullptr; } // Warn on anti-patterns as the 'size' argument to strncat. // The correct size argument should look like following: // strncat(dst, src, sizeof(dst) - strlen(dest) - 1); void Sema::CheckStrncatArguments(const CallExpr *CE, IdentifierInfo *FnName) { // Don't crash if the user has the wrong number of arguments. if (CE->getNumArgs() < 3) return; const Expr *DstArg = CE->getArg(0)->IgnoreParenCasts(); const Expr *SrcArg = CE->getArg(1)->IgnoreParenCasts(); const Expr *LenArg = CE->getArg(2)->IgnoreParenCasts(); if (CheckMemorySizeofForComparison(*this, LenArg, FnName, CE->getLocStart(), CE->getRParenLoc())) return; // Identify common expressions, which are wrongly used as the size argument // to strncat and may lead to buffer overflows. unsigned PatternType = 0; if (const Expr *SizeOfArg = getSizeOfExprArg(LenArg)) { // - sizeof(dst) if (referToTheSameDecl(SizeOfArg, DstArg)) PatternType = 1; // - sizeof(src) else if (referToTheSameDecl(SizeOfArg, SrcArg)) PatternType = 2; } else if (const BinaryOperator *BE = dyn_cast(LenArg)) { if (BE->getOpcode() == BO_Sub) { const Expr *L = BE->getLHS()->IgnoreParenCasts(); const Expr *R = BE->getRHS()->IgnoreParenCasts(); // - sizeof(dst) - strlen(dst) if (referToTheSameDecl(DstArg, getSizeOfExprArg(L)) && referToTheSameDecl(DstArg, getStrlenExprArg(R))) PatternType = 1; // - sizeof(src) - (anything) else if (referToTheSameDecl(SrcArg, getSizeOfExprArg(L))) PatternType = 2; } } if (PatternType == 0) return; // Generate the diagnostic. SourceLocation SL = LenArg->getLocStart(); SourceRange SR = LenArg->getSourceRange(); SourceManager &SM = getSourceManager(); // If the function is defined as a builtin macro, do not show macro expansion. if (SM.isMacroArgExpansion(SL)) { SL = SM.getSpellingLoc(SL); SR = SourceRange(SM.getSpellingLoc(SR.getBegin()), SM.getSpellingLoc(SR.getEnd())); } // Check if the destination is an array (rather than a pointer to an array). QualType DstTy = DstArg->getType(); bool isKnownSizeArray = isConstantSizeArrayWithMoreThanOneElement(DstTy, Context); if (!isKnownSizeArray) { if (PatternType == 1) Diag(SL, diag::warn_strncat_wrong_size) << SR; else Diag(SL, diag::warn_strncat_src_size) << SR; return; } if (PatternType == 1) Diag(SL, diag::warn_strncat_large_size) << SR; else Diag(SL, diag::warn_strncat_src_size) << SR; SmallString<128> sizeString; llvm::raw_svector_ostream OS(sizeString); OS << "sizeof("; DstArg->printPretty(OS, nullptr, getPrintingPolicy()); OS << ") - "; OS << "strlen("; DstArg->printPretty(OS, nullptr, getPrintingPolicy()); OS << ") - 1"; Diag(SL, diag::note_strncat_wrong_size) << FixItHint::CreateReplacement(SR, OS.str()); } //===--- CHECK: Return Address of Stack Variable --------------------------===// static const Expr *EvalVal(const Expr *E, SmallVectorImpl &refVars, const Decl *ParentDecl); static const Expr *EvalAddr(const Expr *E, SmallVectorImpl &refVars, const Decl *ParentDecl); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. static void CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { const Expr *stackE = nullptr; SmallVector refVars; // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. if (lhsType->isPointerType() || (!S.getLangOpts().ObjCAutoRefCount && lhsType->isBlockPointerType())) { stackE = EvalAddr(RetValExp, refVars, /*ParentDecl=*/nullptr); } else if (lhsType->isReferenceType()) { stackE = EvalVal(RetValExp, refVars, /*ParentDecl=*/nullptr); } if (!stackE) return; // Nothing suspicious was found. // Parameters are initalized in the calling scope, so taking the address // of a parameter reference doesn't need a warning. for (auto *DRE : refVars) if (isa(DRE->getDecl())) return; SourceLocation diagLoc; SourceRange diagRange; if (refVars.empty()) { diagLoc = stackE->getLocStart(); diagRange = stackE->getSourceRange(); } else { // We followed through a reference variable. 'stackE' contains the // problematic expression but we will warn at the return statement pointing // at the reference variable. We will later display the "trail" of // reference variables using notes. diagLoc = refVars[0]->getLocStart(); diagRange = refVars[0]->getSourceRange(); } if (const DeclRefExpr *DR = dyn_cast(stackE)) { // address of local var S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() << DR->getDecl()->getDeclName() << diagRange; } else if (isa(stackE)) { // local block. S.Diag(diagLoc, diag::err_ret_local_block) << diagRange; } else if (isa(stackE)) { // address of label. S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; } else { // local temporary. // If there is an LValue->RValue conversion, then the value of the // reference type is used, not the reference. if (auto *ICE = dyn_cast(RetValExp)) { if (ICE->getCastKind() == CK_LValueToRValue) { return; } } S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) << lhsType->isReferenceType() << diagRange; } // Display the "trail" of reference variables that we followed until we // found the problematic expression using notes. for (unsigned i = 0, e = refVars.size(); i != e; ++i) { const VarDecl *VD = cast(refVars[i]->getDecl()); // If this var binds to another reference var, show the range of the next // var, otherwise the var binds to the problematic expression, in which case // show the range of the expression. SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() : stackE->getSourceRange(); S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) << VD->getDeclName() << range; } } /// EvalAddr - EvalAddr and EvalVal are mutually recursive functions that /// check if the expression in a return statement evaluates to an address /// to a location on the stack, a local block, an address of a label, or a /// reference to local temporary. The recursion is used to traverse the /// AST of the return expression, with recursion backtracking when we /// encounter a subexpression that (1) clearly does not lead to one of the /// above problematic expressions (2) is something we cannot determine leads to /// a problematic expression based on such local checking. /// /// Both EvalAddr and EvalVal follow through reference variables to evaluate /// the expression that they point to. Such variables are added to the /// 'refVars' vector so that we know what the reference variable "trail" was. /// /// EvalAddr processes expressions that are pointers that are used as /// references (and not L-values). EvalVal handles all other values. /// At the base case of the recursion is a check for the above problematic /// expressions. /// /// This implementation handles: /// /// * pointer-to-pointer casts /// * implicit conversions from array references to pointers /// * taking the address of fields /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack static const Expr *EvalAddr(const Expr *E, SmallVectorImpl &refVars, const Decl *ParentDecl) { if (E->isTypeDependent()) return nullptr; // We should only be called for evaluating pointer expressions. assert((E->getType()->isAnyPointerType() || E->getType()->isBlockPointerType() || E->getType()->isObjCQualifiedIdType()) && "EvalAddr only works on pointers"); E = E->IgnoreParens(); // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: { const DeclRefExpr *DR = cast(E); // If we leave the immediate function, the lifetime isn't about to end. if (DR->refersToEnclosingVariableOrCapture()) return nullptr; if (const VarDecl *V = dyn_cast(DR->getDecl())) // If this is a reference variable, follow through to the expression that // it points to. if (V->hasLocalStorage() && V->getType()->isReferenceType() && V->hasInit()) { // Add the reference variable to the "trail". refVars.push_back(DR); return EvalAddr(V->getInit(), refVars, ParentDecl); } return nullptr; } case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is AddrOf. All others don't make sense as pointers. const UnaryOperator *U = cast(E); if (U->getOpcode() == UO_AddrOf) return EvalVal(U->getSubExpr(), refVars, ParentDecl); return nullptr; } case Stmt::BinaryOperatorClass: { // Handle pointer arithmetic. All other binary operators are not valid // in this context. const BinaryOperator *B = cast(E); BinaryOperatorKind op = B->getOpcode(); if (op != BO_Add && op != BO_Sub) return nullptr; const Expr *Base = B->getLHS(); // Determine which argument is the real pointer base. It could be // the RHS argument instead of the LHS. if (!Base->getType()->isPointerType()) Base = B->getRHS(); assert(Base->getType()->isPointerType()); return EvalAddr(Base, refVars, ParentDecl); } // For conditional operators we need to see if either the LHS or RHS are // valid DeclRefExpr*s. If one of them is valid, we return it. case Stmt::ConditionalOperatorClass: { const ConditionalOperator *C = cast(E); // Handle the GNU extension for missing LHS. // FIXME: That isn't a ConditionalOperator, so doesn't get here. if (const Expr *LHSExpr = C->getLHS()) { // In C++, we can have a throw-expression, which has 'void' type. if (!LHSExpr->getType()->isVoidType()) if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) return LHS; } // In C++, we can have a throw-expression, which has 'void' type. if (C->getRHS()->getType()->isVoidType()) return nullptr; return EvalAddr(C->getRHS(), refVars, ParentDecl); } case Stmt::BlockExprClass: if (cast(E)->getBlockDecl()->hasCaptures()) return E; // local block. return nullptr; case Stmt::AddrLabelExprClass: return E; // address of label. case Stmt::ExprWithCleanupsClass: return EvalAddr(cast(E)->getSubExpr(), refVars, ParentDecl); // For casts, we need to handle conversions from arrays to // pointer values, and pointer-to-pointer conversions. case Stmt::ImplicitCastExprClass: case Stmt::CStyleCastExprClass: case Stmt::CXXFunctionalCastExprClass: case Stmt::ObjCBridgedCastExprClass: case Stmt::CXXStaticCastExprClass: case Stmt::CXXDynamicCastExprClass: case Stmt::CXXConstCastExprClass: case Stmt::CXXReinterpretCastExprClass: { const Expr* SubExpr = cast(E)->getSubExpr(); switch (cast(E)->getCastKind()) { case CK_LValueToRValue: case CK_NoOp: case CK_BaseToDerived: case CK_DerivedToBase: case CK_UncheckedDerivedToBase: case CK_Dynamic: case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: return EvalAddr(SubExpr, refVars, ParentDecl); case CK_ArrayToPointerDecay: return EvalVal(SubExpr, refVars, ParentDecl); case CK_BitCast: if (SubExpr->getType()->isAnyPointerType() || SubExpr->getType()->isBlockPointerType() || SubExpr->getType()->isObjCQualifiedIdType()) return EvalAddr(SubExpr, refVars, ParentDecl); else return nullptr; default: return nullptr; } } case Stmt::MaterializeTemporaryExprClass: if (const Expr *Result = EvalAddr(cast(E)->GetTemporaryExpr(), refVars, ParentDecl)) return Result; return E; // Everything else: we simply don't reason about them. default: return nullptr; } } /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. static const Expr *EvalVal(const Expr *E, SmallVectorImpl &refVars, const Decl *ParentDecl) { do { // We should only be called for evaluating non-pointer expressions, or // expressions with a pointer type that are not used as references but // instead // are l-values (e.g., DeclRefExpr with a pointer type). // Our "symbolic interpreter" is just a dispatch off the currently // viewed AST node. We then recursively traverse the AST by calling // EvalAddr and EvalVal appropriately. E = E->IgnoreParens(); switch (E->getStmtClass()) { case Stmt::ImplicitCastExprClass: { const ImplicitCastExpr *IE = cast(E); if (IE->getValueKind() == VK_LValue) { E = IE->getSubExpr(); continue; } return nullptr; } case Stmt::ExprWithCleanupsClass: return EvalVal(cast(E)->getSubExpr(), refVars, ParentDecl); case Stmt::DeclRefExprClass: { // When we hit a DeclRefExpr we are looking at code that refers to a // variable's name. If it's not a reference variable we check if it has // local storage within the function, and if so, return the expression. const DeclRefExpr *DR = cast(E); // If we leave the immediate function, the lifetime isn't about to end. if (DR->refersToEnclosingVariableOrCapture()) return nullptr; if (const VarDecl *V = dyn_cast(DR->getDecl())) { // Check if it refers to itself, e.g. "int& i = i;". if (V == ParentDecl) return DR; if (V->hasLocalStorage()) { if (!V->getType()->isReferenceType()) return DR; // Reference variable, follow through to the expression that // it points to. if (V->hasInit()) { // Add the reference variable to the "trail". refVars.push_back(DR); return EvalVal(V->getInit(), refVars, V); } } } return nullptr; } case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is Deref. All others don't resolve to a "name." This includes // handling all sorts of rvalues passed to a unary operator. const UnaryOperator *U = cast(E); if (U->getOpcode() == UO_Deref) return EvalAddr(U->getSubExpr(), refVars, ParentDecl); return nullptr; } case Stmt::ArraySubscriptExprClass: { // Array subscripts are potential references to data on the stack. We // retrieve the DeclRefExpr* for the array variable if it indeed // has local storage. const auto *ASE = cast(E); if (ASE->isTypeDependent()) return nullptr; return EvalAddr(ASE->getBase(), refVars, ParentDecl); } case Stmt::OMPArraySectionExprClass: { return EvalAddr(cast(E)->getBase(), refVars, ParentDecl); } case Stmt::ConditionalOperatorClass: { // For conditional operators we need to see if either the LHS or RHS are // non-NULL Expr's. If one is non-NULL, we return it. const ConditionalOperator *C = cast(E); // Handle the GNU extension for missing LHS. if (const Expr *LHSExpr = C->getLHS()) { // In C++, we can have a throw-expression, which has 'void' type. if (!LHSExpr->getType()->isVoidType()) if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) return LHS; } // In C++, we can have a throw-expression, which has 'void' type. if (C->getRHS()->getType()->isVoidType()) return nullptr; return EvalVal(C->getRHS(), refVars, ParentDecl); } // Accesses to members are potential references to data on the stack. case Stmt::MemberExprClass: { const MemberExpr *M = cast(E); // Check for indirect access. We only want direct field accesses. if (M->isArrow()) return nullptr; // Check whether the member type is itself a reference, in which case // we're not going to refer to the member, but to what the member refers // to. if (M->getMemberDecl()->getType()->isReferenceType()) return nullptr; return EvalVal(M->getBase(), refVars, ParentDecl); } case Stmt::MaterializeTemporaryExprClass: if (const Expr *Result = EvalVal(cast(E)->GetTemporaryExpr(), refVars, ParentDecl)) return Result; return E; default: // Check that we don't return or take the address of a reference to a // temporary. This is only useful in C++. if (!E->isTypeDependent() && E->isRValue()) return E; // Everything else: we simply don't reason about them. return nullptr; } } while (true); } void Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc, bool isObjCMethod, const AttrVec *Attrs, const FunctionDecl *FD) { CheckReturnStackAddr(*this, RetValExp, lhsType, ReturnLoc); // Check if the return value is null but should not be. if (((Attrs && hasSpecificAttr(*Attrs)) || (!isObjCMethod && isNonNullType(Context, lhsType))) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_null_ret) << (isObjCMethod ? 1 : 0) << RetValExp->getSourceRange(); // C++11 [basic.stc.dynamic.allocation]p4: // If an allocation function declared with a non-throwing // exception-specification fails to allocate storage, it shall return // a null pointer. Any other allocation function that fails to allocate // storage shall indicate failure only by throwing an exception [...] if (FD) { OverloadedOperatorKind Op = FD->getOverloadedOperator(); if (Op == OO_New || Op == OO_Array_New) { const FunctionProtoType *Proto = FD->getType()->castAs(); if (!Proto->isNothrow(Context, /*ResultIfDependent*/true) && CheckNonNullExpr(*this, RetValExp)) Diag(ReturnLoc, diag::warn_operator_new_returns_null) << FD << getLangOpts().CPlusPlus11; } } } //===--- CHECK: Floating-Point comparisons (-Wfloat-equal) ---------------===// /// Check for comparisons of floating point operands using != and ==. /// Issue a warning if these are no self-comparisons, as they are not likely /// to do what the programmer intended. void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { Expr* LeftExprSansParen = LHS->IgnoreParenImpCasts(); Expr* RightExprSansParen = RHS->IgnoreParenImpCasts(); // Special case: check for x == x (which is OK). // Do not emit warnings for such cases. if (DeclRefExpr* DRL = dyn_cast(LeftExprSansParen)) if (DeclRefExpr* DRR = dyn_cast(RightExprSansParen)) if (DRL->getDecl() == DRR->getDecl()) return; // Special case: check for comparisons against literals that can be exactly // represented by APFloat. In such cases, do not emit a warning. This // is a heuristic: often comparison against such literals are used to // detect if a value in a variable has not changed. This clearly can // lead to false negatives. if (FloatingLiteral* FLL = dyn_cast(LeftExprSansParen)) { if (FLL->isExact()) return; } else if (FloatingLiteral* FLR = dyn_cast(RightExprSansParen)) if (FLR->isExact()) return; // Check for comparisons with builtin types. if (CallExpr* CL = dyn_cast(LeftExprSansParen)) if (CL->getBuiltinCallee()) return; if (CallExpr* CR = dyn_cast(RightExprSansParen)) if (CR->getBuiltinCallee()) return; // Emit the diagnostic. Diag(Loc, diag::warn_floatingpoint_eq) << LHS->getSourceRange() << RHS->getSourceRange(); } //===--- CHECK: Integer mixed-sign comparisons (-Wsign-compare) --------===// //===--- CHECK: Lossy implicit conversions (-Wconversion) --------------===// namespace { /// Structure recording the 'active' range of an integer-valued /// expression. struct IntRange { /// The number of bits active in the int. unsigned Width; /// True if the int is known not to have negative values. bool NonNegative; IntRange(unsigned Width, bool NonNegative) : Width(Width), NonNegative(NonNegative) {} /// Returns the range of the bool type. static IntRange forBoolType() { return IntRange(1, true); } /// Returns the range of an opaque value of the given integral type. static IntRange forValueOfType(ASTContext &C, QualType T) { return forValueOfCanonicalType(C, T->getCanonicalTypeInternal().getTypePtr()); } /// Returns the range of an opaque value of a canonical integral type. static IntRange forValueOfCanonicalType(ASTContext &C, const Type *T) { assert(T->isCanonicalUnqualified()); if (const VectorType *VT = dyn_cast(T)) T = VT->getElementType().getTypePtr(); if (const ComplexType *CT = dyn_cast(T)) T = CT->getElementType().getTypePtr(); if (const AtomicType *AT = dyn_cast(T)) T = AT->getValueType().getTypePtr(); // For enum types, use the known bit width of the enumerators. if (const EnumType *ET = dyn_cast(T)) { EnumDecl *Enum = ET->getDecl(); if (!Enum->isCompleteDefinition()) return IntRange(C.getIntWidth(QualType(T, 0)), false); unsigned NumPositive = Enum->getNumPositiveBits(); unsigned NumNegative = Enum->getNumNegativeBits(); if (NumNegative == 0) return IntRange(NumPositive, true/*NonNegative*/); else return IntRange(std::max(NumPositive + 1, NumNegative), false/*NonNegative*/); } const BuiltinType *BT = cast(T); assert(BT->isInteger()); return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); } /// Returns the "target" range of a canonical integral type, i.e. /// the range of values expressible in the type. /// /// This matches forValueOfCanonicalType except that enums have the /// full range of their type, not the range of their enumerators. static IntRange forTargetOfCanonicalType(ASTContext &C, const Type *T) { assert(T->isCanonicalUnqualified()); if (const VectorType *VT = dyn_cast(T)) T = VT->getElementType().getTypePtr(); if (const ComplexType *CT = dyn_cast(T)) T = CT->getElementType().getTypePtr(); if (const AtomicType *AT = dyn_cast(T)) T = AT->getValueType().getTypePtr(); if (const EnumType *ET = dyn_cast(T)) T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr(); const BuiltinType *BT = cast(T); assert(BT->isInteger()); return IntRange(C.getIntWidth(QualType(T, 0)), BT->isUnsignedInteger()); } /// Returns the supremum of two ranges: i.e. their conservative merge. static IntRange join(IntRange L, IntRange R) { return IntRange(std::max(L.Width, R.Width), L.NonNegative && R.NonNegative); } /// Returns the infinum of two ranges: i.e. their aggressive merge. static IntRange meet(IntRange L, IntRange R) { return IntRange(std::min(L.Width, R.Width), L.NonNegative || R.NonNegative); } }; IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) return IntRange(value.getMinSignedBits(), false); if (value.getBitWidth() > MaxWidth) value = value.trunc(MaxWidth); // isNonNegative() just checks the sign bit without considering // signedness. return IntRange(value.getActiveBits(), true); } IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, unsigned MaxWidth) { if (result.isInt()) return GetValueRange(C, result.getInt(), MaxWidth); if (result.isVector()) { IntRange R = GetValueRange(C, result.getVectorElt(0), Ty, MaxWidth); for (unsigned i = 1, e = result.getVectorLength(); i != e; ++i) { IntRange El = GetValueRange(C, result.getVectorElt(i), Ty, MaxWidth); R = IntRange::join(R, El); } return R; } if (result.isComplexInt()) { IntRange R = GetValueRange(C, result.getComplexIntReal(), MaxWidth); IntRange I = GetValueRange(C, result.getComplexIntImag(), MaxWidth); return IntRange::join(R, I); } // This can happen with lossless casts to intptr_t of "based" lvalues. // Assume it might use arbitrary bits. // FIXME: The only reason we need to pass the type in here is to get // the sign right on this one case. It would be nice if APValue // preserved this. assert(result.isLValue() || result.isAddrLabelDiff()); return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } QualType GetExprType(const Expr *E) { QualType Ty = E->getType(); if (const AtomicType *AtomicRHS = Ty->getAs()) Ty = AtomicRHS->getValueType(); return Ty; } /// Pseudo-evaluate the given integer expression, estimating the /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { E = E->IgnoreParens(); // Try a full evaluation first. Expr::EvalResult result; if (E->EvaluateAsRValue(result, C)) return GetValueRange(C, result.Val, GetExprType(E), MaxWidth); // I think we only want to look through implicit casts here; if the // user has an explicit widening cast, we should treat the value as // being of the new, wider type. if (const auto *CE = dyn_cast(E)) { if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) return GetExprRange(C, CE->getSubExpr(), MaxWidth); IntRange OutputTypeRange = IntRange::forValueOfType(C, GetExprType(CE)); bool isIntegerCast = CE->getCastKind() == CK_IntegralCast || CE->getCastKind() == CK_BooleanToSignedIntegral; // Assume that non-integer casts can span the full range of the type. if (!isIntegerCast) return OutputTypeRange; IntRange SubRange = GetExprRange(C, CE->getSubExpr(), std::min(MaxWidth, OutputTypeRange.Width)); // Bail out if the subexpr's range is as wide as the cast type. if (SubRange.Width >= OutputTypeRange.Width) return OutputTypeRange; // Otherwise, we take the smaller width, and we're non-negative if // either the output type or the subexpr is. return IntRange(SubRange.Width, SubRange.NonNegative || OutputTypeRange.NonNegative); } if (const auto *CO = dyn_cast(E)) { // If we can fold the condition, just take that operand. bool CondResult; if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) return GetExprRange(C, CondResult ? CO->getTrueExpr() : CO->getFalseExpr(), MaxWidth); // Otherwise, conservatively merge. IntRange L = GetExprRange(C, CO->getTrueExpr(), MaxWidth); IntRange R = GetExprRange(C, CO->getFalseExpr(), MaxWidth); return IntRange::join(L, R); } if (const auto *BO = dyn_cast(E)) { switch (BO->getOpcode()) { // Boolean-valued operations are single-bit and positive. case BO_LAnd: case BO_LOr: case BO_LT: case BO_GT: case BO_LE: case BO_GE: case BO_EQ: case BO_NE: return IntRange::forBoolType(); // The type of the assignments is the type of the LHS, so the RHS // is not necessarily the same type. case BO_MulAssign: case BO_DivAssign: case BO_RemAssign: case BO_AddAssign: case BO_SubAssign: case BO_XorAssign: case BO_OrAssign: // TODO: bitfields? return IntRange::forValueOfType(C, GetExprType(E)); // Simple assignments just pass through the RHS, which will have // been coerced to the LHS type. case BO_Assign: // TODO: bitfields? return GetExprRange(C, BO->getRHS(), MaxWidth); // Operations with opaque sources are black-listed. case BO_PtrMemD: case BO_PtrMemI: return IntRange::forValueOfType(C, GetExprType(E)); // Bitwise-and uses the *infinum* of the two source ranges. case BO_And: case BO_AndAssign: return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth), GetExprRange(C, BO->getRHS(), MaxWidth)); // Left shift gets black-listed based on a judgement call. case BO_Shl: // ...except that we want to treat '1 << (blah)' as logically // positive. It's an important idiom. if (IntegerLiteral *I = dyn_cast(BO->getLHS()->IgnoreParenCasts())) { if (I->getValue() == 1) { IntRange R = IntRange::forValueOfType(C, GetExprType(E)); return IntRange(R.Width, /*NonNegative*/ true); } } // fallthrough case BO_ShlAssign: return IntRange::forValueOfType(C, GetExprType(E)); // Right shift by a constant can narrow its left argument. case BO_Shr: case BO_ShrAssign: { IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); // If the shift amount is a positive constant, drop the width by // that much. llvm::APSInt shift; if (BO->getRHS()->isIntegerConstantExpr(shift, C) && shift.isNonNegative()) { unsigned zext = shift.getZExtValue(); if (zext >= L.Width) L.Width = (L.NonNegative ? 0 : 1); else L.Width -= zext; } return L; } // Comma acts as its right operand. case BO_Comma: return GetExprRange(C, BO->getRHS(), MaxWidth); // Black-list pointer subtractions. case BO_Sub: if (BO->getLHS()->getType()->isPointerType()) return IntRange::forValueOfType(C, GetExprType(E)); break; // The width of a division result is mostly determined by the size // of the LHS. case BO_Div: { // Don't 'pre-truncate' the operands. unsigned opWidth = C.getIntWidth(GetExprType(E)); IntRange L = GetExprRange(C, BO->getLHS(), opWidth); // If the divisor is constant, use that. llvm::APSInt divisor; if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) { unsigned log2 = divisor.logBase2(); // floor(log_2(divisor)) if (log2 >= L.Width) L.Width = (L.NonNegative ? 0 : 1); else L.Width = std::min(L.Width - log2, MaxWidth); return L; } // Otherwise, just use the LHS's width. IntRange R = GetExprRange(C, BO->getRHS(), opWidth); return IntRange(L.Width, L.NonNegative && R.NonNegative); } // The result of a remainder can't be larger than the result of // either side. case BO_Rem: { // Don't 'pre-truncate' the operands. unsigned opWidth = C.getIntWidth(GetExprType(E)); IntRange L = GetExprRange(C, BO->getLHS(), opWidth); IntRange R = GetExprRange(C, BO->getRHS(), opWidth); IntRange meet = IntRange::meet(L, R); meet.Width = std::min(meet.Width, MaxWidth); return meet; } // The default behavior is okay for these. case BO_Mul: case BO_Add: case BO_Xor: case BO_Or: break; } // The default case is to treat the operation as if it were closed // on the narrowest type that encompasses both operands. IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth); IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth); return IntRange::join(L, R); } if (const auto *UO = dyn_cast(E)) { switch (UO->getOpcode()) { // Boolean-valued operations are white-listed. case UO_LNot: return IntRange::forBoolType(); // Operations with opaque sources are black-listed. case UO_Deref: case UO_AddrOf: // should be impossible return IntRange::forValueOfType(C, GetExprType(E)); default: return GetExprRange(C, UO->getSubExpr(), MaxWidth); } } if (const auto *OVE = dyn_cast(E)) return GetExprRange(C, OVE->getSourceExpr(), MaxWidth); if (const auto *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); return IntRange::forValueOfType(C, GetExprType(E)); } IntRange GetExprRange(ASTContext &C, const Expr *E) { return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. bool IsSameFloatAfterCast(const llvm::APFloat &value, const llvm::fltSemantics &Src, const llvm::fltSemantics &Tgt) { llvm::APFloat truncated = value; bool ignored; truncated.convert(Src, llvm::APFloat::rmNearestTiesToEven, &ignored); truncated.convert(Tgt, llvm::APFloat::rmNearestTiesToEven, &ignored); return truncated.bitwiseIsEqual(value); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. /// /// The value might be a vector of floats (or a complex number). bool IsSameFloatAfterCast(const APValue &value, const llvm::fltSemantics &Src, const llvm::fltSemantics &Tgt) { if (value.isFloat()) return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); if (value.isVector()) { for (unsigned i = 0, e = value.getVectorLength(); i != e; ++i) if (!IsSameFloatAfterCast(value.getVectorElt(i), Src, Tgt)) return false; return true; } assert(value.isComplexFloat()); return (IsSameFloatAfterCast(value.getComplexFloatReal(), Src, Tgt) && IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); bool IsZero(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. if (const DeclRefExpr *DR = dyn_cast(E->IgnoreParenImpCasts())) if (isa(DR->getDecl())) return false; // Suppress cases where the '0' value is expanded from a macro. if (E->getLocStart().isMacroID()) return false; llvm::APSInt Value; return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; } bool HasEnumType(Expr *E) { // Strip off implicit integral promotions. while (ImplicitCastExpr *ICE = dyn_cast(E)) { if (ICE->getCastKind() != CK_IntegralCast && ICE->getCastKind() != CK_NoOp) break; E = ICE->getSubExpr(); } return E->getType()->isEnumeralType(); } void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; BinaryOperatorKind op = E->getOpcode(); if (E->isValueDependent()) return; if (op == BO_LT && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) << "< 0" << "false" << HasEnumType(E->getLHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_GE && IsZero(S, E->getRHS())) { S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison) << ">= 0" << "true" << HasEnumType(E->getLHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_GT && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) << "0 >" << "false" << HasEnumType(E->getRHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } else if (op == BO_LE && IsZero(S, E->getLHS())) { S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison) << "0 <=" << "true" << HasEnumType(E->getRHS()) << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); } } void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, Expr *Other, const llvm::APSInt &Value, bool RhsConstant) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; // TODO: Investigate using GetExprRange() to get tighter bounds // on the bit ranges. QualType OtherT = Other->getType(); if (const auto *AT = OtherT->getAs()) OtherT = AT->getValueType(); IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); unsigned OtherWidth = OtherRange.Width; bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue(); // 0 values are handled later by CheckTrivialUnsignedComparison(). if ((Value == 0) && (!OtherIsBooleanType)) return; BinaryOperatorKind op = E->getOpcode(); bool IsTrue = true; // Used for diagnostic printout. enum { LiteralConstant = 0, CXXBoolLiteralTrue, CXXBoolLiteralFalse } LiteralOrBoolConstant = LiteralConstant; if (!OtherIsBooleanType) { QualType ConstantT = Constant->getType(); QualType CommonT = E->getLHS()->getType(); if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) return; assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) && "comparison with non-integer type"); bool ConstantSigned = ConstantT->isSignedIntegerType(); bool CommonSigned = CommonT->isSignedIntegerType(); bool EqualityOnly = false; if (CommonSigned) { // The common type is signed, therefore no signed to unsigned conversion. if (!OtherRange.NonNegative) { // Check that the constant is representable in type OtherT. if (ConstantSigned) { if (OtherWidth >= Value.getMinSignedBits()) return; } else { // !ConstantSigned if (OtherWidth >= Value.getActiveBits() + 1) return; } } else { // !OtherSigned // Check that the constant is representable in type OtherT. // Negative values are out of range. if (ConstantSigned) { if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits()) return; } else { // !ConstantSigned if (OtherWidth >= Value.getActiveBits()) return; } } } else { // !CommonSigned if (OtherRange.NonNegative) { if (OtherWidth >= Value.getActiveBits()) return; } else { // OtherSigned assert(!ConstantSigned && "Two signed types converted to unsigned types."); // Check to see if the constant is representable in OtherT. if (OtherWidth > Value.getActiveBits()) return; // Check to see if the constant is equivalent to a negative value // cast to CommonT. if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) && Value.isNegative() && Value.getMinSignedBits() <= OtherWidth) return; // The constant value rests between values that OtherT can represent // after conversion. Relational comparison still works, but equality // comparisons will be tautological. EqualityOnly = true; } } bool PositiveConstant = !ConstantSigned || Value.isNonNegative(); if (op == BO_EQ || op == BO_NE) { IsTrue = op == BO_NE; } else if (EqualityOnly) { return; } else if (RhsConstant) { if (op == BO_GT || op == BO_GE) IsTrue = !PositiveConstant; else // op == BO_LT || op == BO_LE IsTrue = PositiveConstant; } else { if (op == BO_LT || op == BO_LE) IsTrue = !PositiveConstant; else // op == BO_GT || op == BO_GE IsTrue = PositiveConstant; } } else { // Other isKnownToHaveBooleanValue enum CompareBoolWithConstantResult { AFals, ATrue, Unkwn }; enum ConstantValue { LT_Zero, Zero, One, GT_One, SizeOfConstVal }; enum ConstantSide { Lhs, Rhs, SizeOfConstSides }; static const struct LinkedConditions { CompareBoolWithConstantResult BO_LT_OP[SizeOfConstSides][SizeOfConstVal]; CompareBoolWithConstantResult BO_GT_OP[SizeOfConstSides][SizeOfConstVal]; CompareBoolWithConstantResult BO_LE_OP[SizeOfConstSides][SizeOfConstVal]; CompareBoolWithConstantResult BO_GE_OP[SizeOfConstSides][SizeOfConstVal]; CompareBoolWithConstantResult BO_EQ_OP[SizeOfConstSides][SizeOfConstVal]; CompareBoolWithConstantResult BO_NE_OP[SizeOfConstSides][SizeOfConstVal]; } TruthTable = { // Constant on LHS. | Constant on RHS. | // LT_Zero| Zero | One |GT_One| LT_Zero| Zero | One |GT_One| { { ATrue, Unkwn, AFals, AFals }, { AFals, AFals, Unkwn, ATrue } }, { { AFals, AFals, Unkwn, ATrue }, { ATrue, Unkwn, AFals, AFals } }, { { ATrue, ATrue, Unkwn, AFals }, { AFals, Unkwn, ATrue, ATrue } }, { { AFals, Unkwn, ATrue, ATrue }, { ATrue, ATrue, Unkwn, AFals } }, { { AFals, Unkwn, Unkwn, AFals }, { AFals, Unkwn, Unkwn, AFals } }, { { ATrue, Unkwn, Unkwn, ATrue }, { ATrue, Unkwn, Unkwn, ATrue } } }; bool ConstantIsBoolLiteral = isa(Constant); enum ConstantValue ConstVal = Zero; if (Value.isUnsigned() || Value.isNonNegative()) { if (Value == 0) { LiteralOrBoolConstant = ConstantIsBoolLiteral ? CXXBoolLiteralFalse : LiteralConstant; ConstVal = Zero; } else if (Value == 1) { LiteralOrBoolConstant = ConstantIsBoolLiteral ? CXXBoolLiteralTrue : LiteralConstant; ConstVal = One; } else { LiteralOrBoolConstant = LiteralConstant; ConstVal = GT_One; } } else { ConstVal = LT_Zero; } CompareBoolWithConstantResult CmpRes; switch (op) { case BO_LT: CmpRes = TruthTable.BO_LT_OP[RhsConstant][ConstVal]; break; case BO_GT: CmpRes = TruthTable.BO_GT_OP[RhsConstant][ConstVal]; break; case BO_LE: CmpRes = TruthTable.BO_LE_OP[RhsConstant][ConstVal]; break; case BO_GE: CmpRes = TruthTable.BO_GE_OP[RhsConstant][ConstVal]; break; case BO_EQ: CmpRes = TruthTable.BO_EQ_OP[RhsConstant][ConstVal]; break; case BO_NE: CmpRes = TruthTable.BO_NE_OP[RhsConstant][ConstVal]; break; default: CmpRes = Unkwn; break; } if (CmpRes == AFals) { IsTrue = false; } else if (CmpRes == ATrue) { IsTrue = true; } else { return; } } // If this is a comparison to an enum constant, include that // constant in the diagnostic. const EnumConstantDecl *ED = nullptr; if (const DeclRefExpr *DR = dyn_cast(Constant)) ED = dyn_cast(DR->getDecl()); SmallString<64> PrettySourceValue; llvm::raw_svector_ostream OS(PrettySourceValue); if (ED) OS << '\'' << *ED << "' (" << Value << ")"; else OS << Value; S.DiagRuntimeBehavior( E->getOperatorLoc(), E, S.PDiag(diag::warn_out_of_range_compare) << OS.str() << LiteralOrBoolConstant << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); } /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } /// \brief Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); // Only analyze comparison operators where both sides have been converted to // the same type. if (!S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())) return AnalyzeImpConvsInComparison(S, E); // Don't analyze value-dependent comparisons directly. if (E->isValueDependent()) return AnalyzeImpConvsInComparison(S, E); Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); bool IsComparisonConstant = false; // Check whether an integer constant comparison results in a value // of 'true' or 'false'. if (T->isIntegralType(S.Context)) { llvm::APSInt RHSValue; bool IsRHSIntegralLiteral = RHS->isIntegerConstantExpr(RHSValue, S.Context); llvm::APSInt LHSValue; bool IsLHSIntegralLiteral = LHS->isIntegerConstantExpr(LHSValue, S.Context); if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral) DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true); else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral) DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false); else IsComparisonConstant = (IsRHSIntegralLiteral && IsLHSIntegralLiteral); } else if (!T->hasUnsignedIntegerRepresentation()) IsComparisonConstant = E->isIntegerConstantExpr(S.Context); // We don't do anything special if this isn't an unsigned integral // comparison: we're only interested in integral comparisons, and // signed comparisons only happen in cases we don't care to warn about. // // We also don't care about value-dependent expressions or expressions // whose result is a constant. if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant) return AnalyzeImpConvsInComparison(S, E); // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; if (LHS->getType()->hasSignedIntegerRepresentation()) { assert(!RHS->getType()->hasSignedIntegerRepresentation() && "unsigned comparison between two signed integer expressions?"); signedOperand = LHS; unsignedOperand = RHS; } else if (RHS->getType()->hasSignedIntegerRepresentation()) { signedOperand = RHS; unsignedOperand = LHS; } else { CheckTrivialUnsignedComparison(S, E); return AnalyzeImpConvsInComparison(S, E); } // Otherwise, calculate the effective range of the signed operand. IntRange signedRange = GetExprRange(S.Context, signedOperand); // Go ahead and analyze implicit conversions in the operands. Note // that we skip the implicit conversions on both sides. AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc()); AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc()); // If the signed range is non-negative, -Wsign-compare won't fire, // but we should still check for comparisons which are always true // or false. if (signedRange.NonNegative) return CheckTrivialUnsignedComparison(S, E); // For (in)equality comparisons, if the unsigned operand is a // constant which cannot collide with a overflowed signed operand, // then reinterpreting the signed operand as unsigned will not // change the result of the comparison. if (E->isEqualityOp()) { unsigned comparisonWidth = S.Context.getIntWidth(T); IntRange unsignedRange = GetExprRange(S.Context, unsignedOperand); // We should never be unable to prove that the unsigned operand is // non-negative. assert(unsignedRange.NonNegative && "unsigned range includes negative?"); if (unsignedRange.Width < comparisonWidth) return; } S.DiagRuntimeBehavior(E->getOperatorLoc(), E, S.PDiag(diag::warn_mixed_sign_comparison) << LHS->getType() << RHS->getType() << LHS->getSourceRange() << RHS->getSourceRange()); } /// Analyzes an attempt to assign the given value to a bitfield. /// /// Returns true if there was something fishy about the attempt. bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, SourceLocation InitLoc) { assert(Bitfield->isBitField()); if (Bitfield->isInvalidDecl()) return false; // White-list bool bitfields. if (Bitfield->getType()->isBooleanType()) return false; // Ignore value- or type-dependent expressions. if (Bitfield->getBitWidth()->isValueDependent() || Bitfield->getBitWidth()->isTypeDependent() || Init->isValueDependent() || Init->isTypeDependent()) return false; Expr *OriginalInit = Init->IgnoreParenImpCasts(); llvm::APSInt Value; if (!OriginalInit->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) return false; unsigned OriginalWidth = Value.getBitWidth(); unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); if (Value.isSigned() && Value.isNegative()) if (UnaryOperator *UO = dyn_cast(OriginalInit)) if (UO->getOpcode() == UO_Minus) if (isa(UO->getSubExpr())) OriginalWidth = Value.getMinSignedBits(); if (OriginalWidth <= FieldWidth) return false; // Compute the value which the bitfield will contain. llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType()); // Check whether the stored value is equal to the original value. TruncatedValue = TruncatedValue.extend(OriginalWidth); if (llvm::APSInt::isSameValue(Value, TruncatedValue)) return false; // Special-case bitfields of width 1: booleans are naturally 0/1, and // therefore don't strictly fit into a signed bitfield of width 1. if (FieldWidth == 1 && Value == 1) return false; std::string PrettyValue = Value.toString(10); std::string PrettyTrunc = TruncatedValue.toString(10); S.Diag(InitLoc, diag::warn_impcast_bitfield_precision_constant) << PrettyValue << PrettyTrunc << OriginalInit->getType() << Init->getSourceRange(); return true; } /// Analyze the given simple or compound assignment for warning-worthy /// operations. void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // Just recurse on the LHS. AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); // We want to recurse on the RHS as normal unless we're assigning to // a bitfield. if (FieldDecl *Bitfield = E->getLHS()->getSourceBitField()) { if (AnalyzeBitFieldAssignment(S, Bitfield, E->getRHS(), E->getOperatorLoc())) { // Recurse, ignoring any implicit conversions on the RHS. return AnalyzeImplicitConversions(S, E->getRHS()->IgnoreParenImpCasts(), E->getOperatorLoc()); } } AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, SourceLocation CContext, unsigned diag, bool pruneControlFlow = false) { if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) << SourceType << T << E->getSourceRange() << SourceRange(CContext)); return; } S.Diag(E->getExprLoc(), diag) << SourceType << T << E->getSourceRange() << SourceRange(CContext); } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, unsigned diag, bool pruneControlFlow = false) { DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } /// Diagnose an implicit cast from a floating point value to an integer value. void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext) { const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty(); Expr *InnerE = E->IgnoreParenImpCasts(); // We also want to warn on, e.g., "int i = -1.234" if (UnaryOperator *UOp = dyn_cast(InnerE)) if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); const bool IsLiteral = isa(E) || isa(InnerE); llvm::APFloat Value(0.0); bool IsConstant = E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); if (!IsConstant) { return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } bool isExact = false; llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, &isExact) == llvm::APFloat::opOK && isExact) { if (IsLiteral) return; return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } unsigned DiagID = 0; if (IsLiteral) { // Warn on floating point literal to integer. DiagID = diag::warn_impcast_literal_float_to_integer; } else if (IntegerValue == 0) { if (Value.isZero()) { // Skip -0.0 to 0 conversion. return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } // Warn on non-zero to zero conversion. DiagID = diag::warn_impcast_float_to_integer_zero; } else { if (IntegerValue.isUnsigned()) { if (!IntegerValue.isMaxValue()) { return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } } else { // IntegerValue.isSigned() if (!IntegerValue.isMaxSignedValue() && !IntegerValue.isMinSignedValue()) { return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, PruneWarnings); } } // Warn on evaluatable floating point expression to integer conversion. DiagID = diag::warn_impcast_float_to_integer; } // FIXME: Force the precision of the source value down so we don't print // digits which are usually useless (we don't really care here if we // truncate a digit by accident in edge cases). Ideally, APFloat::toString // would automatically print the shortest representation, but it's a bit // tricky to implement. SmallString<16> PrettySourceValue; unsigned precision = llvm::APFloat::semanticsPrecision(Value.getSemantics()); precision = (precision * 59 + 195) / 196; Value.toString(PrettySourceValue, precision); SmallString<16> PrettyTargetValue; if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; else IntegerValue.toString(PrettyTargetValue); if (PruneWarnings) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(DiagID) << E->getType() << T.getUnqualifiedType() << PrettySourceValue << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext)); } else { S.Diag(E->getExprLoc(), DiagID) << E->getType() << T.getUnqualifiedType() << PrettySourceValue << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext); } } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { if (!Range.Width) return "0"; llvm::APSInt ValueInRange = Value; ValueInRange.setIsSigned(!Range.NonNegative); ValueInRange = ValueInRange.trunc(Range.Width); return ValueInRange.toString(10); } bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { if (!isa(Ex)) return false; Expr *InnerE = Ex->IgnoreParenImpCasts(); const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr(); const Type *Source = S.Context.getCanonicalType(InnerE->getType()).getTypePtr(); if (Target->isDependentType()) return false; const BuiltinType *FloatCandidateBT = dyn_cast(ToBool ? Source : Target); const Type *BoolCandidateType = ToBool ? Target : Source; return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) && FloatCandidateBT && (FloatCandidateBT->isFloatingPoint())); } void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, SourceLocation CC) { unsigned NumArgs = TheCall->getNumArgs(); for (unsigned i = 0; i < NumArgs; ++i) { Expr *CurrA = TheCall->getArg(i); if (!IsImplicitBoolFloatConversion(S, CurrA, true)) continue; bool IsSwapped = ((i > 0) && IsImplicitBoolFloatConversion(S, TheCall->getArg(i - 1), false)); IsSwapped |= ((i < (NumArgs - 1)) && IsImplicitBoolFloatConversion(S, TheCall->getArg(i + 1), false)); if (IsSwapped) { // Warn on this floating-point to bool conversion. DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(), CurrA->getType(), CC, diag::warn_impcast_floating_point_to_bool); } } } void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, E->getExprLoc())) return; // Don't warn on functions which have return type nullptr_t. if (isa(E)) return; // Check for NULL (GNUNull) or nullptr (CXX11_nullptr). const Expr::NullPointerConstantKind NullKind = E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull); if (NullKind != Expr::NPCK_GNUNull && NullKind != Expr::NPCK_CXX11_nullptr) return; // Return if target type is a safe conversion. if (T->isAnyPointerType() || T->isBlockPointerType() || T->isMemberPointerType() || !T->isScalarType() || T->isNullPtrType()) return; SourceLocation Loc = E->getSourceRange().getBegin(); // Venture through the macro stacks to get to the source of macro arguments. // The new location is a better location than the complete location that was // passed in. while (S.SourceMgr.isMacroArgExpansion(Loc)) Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); while (S.SourceMgr.isMacroArgExpansion(CC)) CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); // __null is usually wrapped in a macro. Go up a macro if that is the case. if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( Loc, S.SourceMgr, S.getLangOpts()); if (MacroName == "NULL") Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; } // Only warn if the null and context location are in the same macro expansion. if (S.SourceMgr.getFileID(Loc) != S.SourceMgr.getFileID(CC)) return; S.Diag(Loc, diag::warn_impcast_null_pointer_to_integer) << (NullKind == Expr::NPCK_CXX11_nullptr) << T << clang::SourceRange(CC) << FixItHint::CreateReplacement(Loc, S.getFixItZeroLiteralForType(T, Loc)); } void checkObjCArrayLiteral(Sema &S, QualType TargetType, ObjCArrayLiteral *ArrayLiteral); void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, ObjCDictionaryLiteral *DictionaryLiteral); /// Check a single element within a collection literal against the /// target element type. void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, Expr *Element, unsigned ElementKind) { // Skip a bitcast to 'id' or qualified 'id'. if (auto ICE = dyn_cast(Element)) { if (ICE->getCastKind() == CK_BitCast && ICE->getSubExpr()->getType()->getAs()) Element = ICE->getSubExpr(); } QualType ElementType = Element->getType(); ExprResult ElementResult(Element); if (ElementType->getAs() && S.CheckSingleAssignmentConstraints(TargetElementType, ElementResult, false, false) != Sema::Compatible) { S.Diag(Element->getLocStart(), diag::warn_objc_collection_literal_element) << ElementType << ElementKind << TargetElementType << Element->getSourceRange(); } if (auto ArrayLiteral = dyn_cast(Element)) checkObjCArrayLiteral(S, TargetElementType, ArrayLiteral); else if (auto DictionaryLiteral = dyn_cast(Element)) checkObjCDictionaryLiteral(S, TargetElementType, DictionaryLiteral); } /// Check an Objective-C array literal being converted to the given /// target type. void checkObjCArrayLiteral(Sema &S, QualType TargetType, ObjCArrayLiteral *ArrayLiteral) { if (!S.NSArrayDecl) return; const auto *TargetObjCPtr = TargetType->getAs(); if (!TargetObjCPtr) return; if (TargetObjCPtr->isUnspecialized() || TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != S.NSArrayDecl->getCanonicalDecl()) return; auto TypeArgs = TargetObjCPtr->getTypeArgs(); if (TypeArgs.size() != 1) return; QualType TargetElementType = TypeArgs[0]; for (unsigned I = 0, N = ArrayLiteral->getNumElements(); I != N; ++I) { checkObjCCollectionLiteralElement(S, TargetElementType, ArrayLiteral->getElement(I), 0); } } /// Check an Objective-C dictionary literal being converted to the given /// target type. void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, ObjCDictionaryLiteral *DictionaryLiteral) { if (!S.NSDictionaryDecl) return; const auto *TargetObjCPtr = TargetType->getAs(); if (!TargetObjCPtr) return; if (TargetObjCPtr->isUnspecialized() || TargetObjCPtr->getInterfaceDecl()->getCanonicalDecl() != S.NSDictionaryDecl->getCanonicalDecl()) return; auto TypeArgs = TargetObjCPtr->getTypeArgs(); if (TypeArgs.size() != 2) return; QualType TargetKeyType = TypeArgs[0]; QualType TargetObjectType = TypeArgs[1]; for (unsigned I = 0, N = DictionaryLiteral->getNumElements(); I != N; ++I) { auto Element = DictionaryLiteral->getKeyValueElement(I); checkObjCCollectionLiteralElement(S, TargetKeyType, Element.Key, 1); checkObjCCollectionLiteralElement(S, TargetObjectType, Element.Value, 2); } } // Helper function to filter out cases for constant width constant conversion. // Don't warn on char array initialization or for non-decimal values. bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { // If initializing from a constant, and the constant starts with '0', // then it is a binary, octal, or hexadecimal. Allow these constants // to fill all the bits, even if there is a sign change. if (auto *IntLit = dyn_cast(E->IgnoreParenImpCasts())) { const char FirstLiteralCharacter = S.getSourceManager().getCharacterData(IntLit->getLocStart())[0]; if (FirstLiteralCharacter == '0') return false; } // If the CC location points to a '{', and the type is char, then assume // assume it is an array initialization. if (CC.isValid() && T->isCharType()) { const char FirstContextCharacter = S.getSourceManager().getCharacterData(CC)[0]; if (FirstContextCharacter == '{') return false; } return true; } void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; const Type *Source = S.Context.getCanonicalType(E->getType()).getTypePtr(); const Type *Target = S.Context.getCanonicalType(T).getTypePtr(); if (Source == Target) return; if (Target->isDependentType()) return; // If the conversion context location is invalid don't complain. We also // don't want to emit a warning if the issue occurs from the expansion of // a system macro. The problem is that 'getSpellingLoc()' is slow, so we // delay this check as long as possible. Once we detect we are in that // scenario, we just return. if (CC.isInvalid()) return; // Diagnose implicit casts to bool. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) { if (isa(E)) // Warn on string literal to bool. Checks for string literals in logical // and expressions, for instance, assert(0 && "error here"), are // prevented by a check in AnalyzeImplicitConversions(). return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_string_literal_to_bool); if (isa(E) || isa(E) || isa(E) || isa(E)) { // This covers the literal expressions that evaluate to Objective-C // objects. return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_objective_c_literal_to_bool); } if (Source->isPointerType() || Source->canDecayToPointerType()) { // Warn on pointer to bool conversion that is always true. S.DiagnoseAlwaysNonNullPointer(E, Expr::NPCK_NotNull, /*IsEqual*/ false, SourceRange(CC)); } } // Check implicit casts from Objective-C collection literals to specialized // collection types, e.g., NSArray *. if (auto *ArrayLiteral = dyn_cast(E)) checkObjCArrayLiteral(S, QualType(Target, 0), ArrayLiteral); else if (auto *DictionaryLiteral = dyn_cast(E)) checkObjCDictionaryLiteral(S, QualType(Target, 0), DictionaryLiteral); // Strip vector types. if (isa(Source)) { if (!isa(Target)) { if (S.SourceMgr.isInSystemMacro(CC)) return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_vector_scalar); } // If the vector cast is cast between two vectors of the same size, it is // a bitcast, not a conversion. if (S.Context.getTypeSize(Source) == S.Context.getTypeSize(Target)) return; Source = cast(Source)->getElementType().getTypePtr(); Target = cast(Target)->getElementType().getTypePtr(); } if (auto VecTy = dyn_cast(Target)) Target = VecTy->getElementType().getTypePtr(); // Strip complex types. if (isa(Source)) { if (!isa(Target)) { if (S.SourceMgr.isInSystemMacro(CC)) return; return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_complex_scalar); } Source = cast(Source)->getElementType().getTypePtr(); Target = cast(Target)->getElementType().getTypePtr(); } const BuiltinType *SourceBT = dyn_cast(Source); const BuiltinType *TargetBT = dyn_cast(Target); // If the source is floating point... if (SourceBT && SourceBT->isFloatingPoint()) { // ...and the target is floating point... if (TargetBT && TargetBT->isFloatingPoint()) { // ...then warn if we're dropping FP rank. // Builtin FP kinds are ordered by increasing FP rank. if (SourceBT->getKind() > TargetBT->getKind()) { // Don't warn about float constants that are precisely // representable in the target type. Expr::EvalResult result; if (E->EvaluateAsRValue(result, S.Context)) { // Value might be a float, a float vector, or a float complex. if (IsSameFloatAfterCast(result.Val, S.Context.getFloatTypeSemantics(QualType(TargetBT, 0)), S.Context.getFloatTypeSemantics(QualType(SourceBT, 0)))) return; } if (S.SourceMgr.isInSystemMacro(CC)) return; DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); } // ... or possibly if we're increasing rank, too else if (TargetBT->getKind() > SourceBT->getKind()) { if (S.SourceMgr.isInSystemMacro(CC)) return; DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_double_promotion); } return; } // If the target is integral, always warn. if (TargetBT && TargetBT->isInteger()) { if (S.SourceMgr.isInSystemMacro(CC)) return; DiagnoseFloatingImpCast(S, E, T, CC); } // Detect the case where a call result is converted from floating-point to // to bool, and the final argument to the call is converted from bool, to // discover this typo: // // bool b = fabs(x < 1.0); // should be "bool b = fabs(x) < 1.0;" // // FIXME: This is an incredibly special case; is there some more general // way to detect this class of misplaced-parentheses bug? if (Target->isBooleanType() && isa(E)) { // Check last argument of function call to see if it is an // implicit cast from a type matching the type the result // is being cast to. CallExpr *CEx = cast(E); if (unsigned NumArgs = CEx->getNumArgs()) { Expr *LastA = CEx->getArg(NumArgs - 1); Expr *InnerE = LastA->IgnoreParenImpCasts(); if (isa(LastA) && InnerE->getType()->isBooleanType()) { // Warn on this floating-point to bool conversion DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_floating_point_to_bool); } } } return; } DiagnoseNullConversion(S, E, T, CC); if (!Source->isIntegerType() || !Target->isIntegerType()) return; // TODO: remove this early return once the false positives for constant->bool // in templates, macros, etc, are reduced or removed. if (Target->isSpecificBuiltinType(BuiltinType::Bool)) return; IntRange SourceRange = GetExprRange(S.Context, E); IntRange TargetRange = IntRange::forTargetOfCanonicalType(S.Context, Target); if (SourceRange.Width > TargetRange.Width) { // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. llvm::APSInt Value(32); if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) { if (S.SourceMgr.isInSystemMacro(CC)) return; std::string PrettySourceValue = Value.toString(10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag::warn_impcast_integer_precision_constant) << PrettySourceValue << PrettyTargetValue << E->getType() << T << E->getSourceRange() << clang::SourceRange(CC)); return; } // People want to build with -Wshorten-64-to-32 and not -Wconversion. if (S.SourceMgr.isInSystemMacro(CC)) return; if (TargetRange.Width == 32 && S.Context.getIntWidth(E->getType()) == 64) return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_64_32, /* pruneControlFlow */ true); return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); } if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative && SourceRange.NonNegative && Source->isSignedIntegerType()) { // Warn when doing a signed to signed conversion, warn if the positive // source value is exactly the width of the target type, which will // cause a negative value to be stored. llvm::APSInt Value; if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects) && !S.SourceMgr.isInSystemMacro(CC)) { if (isSameWidthConstantConversion(S, E, T, CC)) { std::string PrettySourceValue = Value.toString(10); std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); S.DiagRuntimeBehavior( E->getExprLoc(), E, S.PDiag(diag::warn_impcast_integer_precision_constant) << PrettySourceValue << PrettyTargetValue << E->getType() << T << E->getSourceRange() << clang::SourceRange(CC)); return; } } // Fall through for non-constants to give a sign conversion warning. } if ((TargetRange.NonNegative && !SourceRange.NonNegative) || (!TargetRange.NonNegative && SourceRange.NonNegative && SourceRange.Width == TargetRange.Width)) { if (S.SourceMgr.isInSystemMacro(CC)) return; unsigned DiagID = diag::warn_impcast_integer_sign; // Traditionally, gcc has warned about this under -Wsign-compare. // We also want to warn about it in -Wconversion. // So if -Wconversion is off, use a completely identical diagnostic // in the sign-compare group. // The conditional-checking code will if (ICContext) { DiagID = diag::warn_impcast_integer_sign_conditional; *ICContext = true; } return DiagnoseImpCast(S, E, T, CC, DiagID); } // Diagnose conversions between different enumeration types. // In C, we pretend that the type of an EnumConstantDecl is its enumeration // type, to give us better diagnostics. QualType SourceType = E->getType(); if (!S.getLangOpts().CPlusPlus) { if (DeclRefExpr *DRE = dyn_cast(E)) if (EnumConstantDecl *ECD = dyn_cast(DRE->getDecl())) { EnumDecl *Enum = cast(ECD->getDeclContext()); SourceType = S.Context.getTypeDeclType(Enum); Source = S.Context.getCanonicalType(SourceType).getTypePtr(); } } if (const EnumType *SourceEnum = Source->getAs()) if (const EnumType *TargetEnum = Target->getAs()) if (SourceEnum->getDecl()->hasNameForLinkage() && TargetEnum->getDecl()->hasNameForLinkage() && SourceEnum != TargetEnum) { if (S.SourceMgr.isInSystemMacro(CC)) return; return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, SourceLocation CC, QualType T); void CheckConditionalOperand(Sema &S, Expr *E, QualType T, SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); if (isa(E)) return CheckConditionalOperator(S, cast(E), CC, T); AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) return CheckImplicitConversion(S, E, T, CC, &ICContext); } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, SourceLocation CC, QualType T) { AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); bool Suspicious = false; CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); // If -Wconversion would have warned about either of the candidates // for a signedness conversion to the context type... if (!Suspicious) return; // ...but it's currently ignored... if (!S.Diags.isIgnored(diag::warn_impcast_integer_sign_conditional, CC)) return; // ...then check whether it would have warned about either of the // candidates for a signedness conversion to the condition type. if (E->getType() == T) return; Suspicious = false; CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); if (!Suspicious) CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); } /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); } /// AnalyzeImplicitConversions - Find and report any interesting /// implicit conversions in the given expression. There are a couple /// of competing diagnostics here, -Wconversion and -Wsign-compare. void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); if (E->isTypeDependent() || E->isValueDependent()) return; // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. if (isa(E)) { ConditionalOperator *CO = cast(E); CheckConditionalOperator(S, CO, CC, T); return; } // Check implicit argument conversions for function calls. if (CallExpr *Call = dyn_cast(E)) CheckImplicitArgumentConversions(S, Call, CC); // Go ahead and check any implicit conversions we might have skipped. // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. if (E->getType() != T) CheckImplicitConversion(S, E, T, CC); // Now continue drilling into this expression. if (PseudoObjectExpr *POE = dyn_cast(E)) { // The bound subexpressions in a PseudoObjectExpr are not reachable // as transitive children. // FIXME: Use a more uniform representation for this. for (auto *SE : POE->semantics()) if (auto *OVE = dyn_cast(SE)) AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC); } // Skip past explicit casts. if (isa(E)) { E = cast(E)->getSubExpr()->IgnoreParenImpCasts(); return AnalyzeImplicitConversions(S, E, CC); } if (BinaryOperator *BO = dyn_cast(E)) { // Do a somewhat different check with comparison operators. if (BO->isComparisonOp()) return AnalyzeComparison(S, BO); // And with simple assignments. if (BO->getOpcode() == BO_Assign) return AnalyzeAssignment(S, BO); } // These break the otherwise-useful invariant below. Fortunately, // we don't really need to recurse into them, because any internal // expressions should have been analyzed already when they were // built into statements. if (isa(E)) return; // Don't descend into unevaluated contexts. if (isa(E)) return; // Now just recurse over the expression's children. CC = E->getExprLoc(); BinaryOperator *BO = dyn_cast(E); bool IsLogicalAndOperator = BO && BO->getOpcode() == BO_LAnd; for (Stmt *SubStmt : E->children()) { Expr *ChildExpr = dyn_cast_or_null(SubStmt); if (!ChildExpr) continue; if (IsLogicalAndOperator && isa(ChildExpr->IgnoreParenImpCasts())) // Ignore checking string literals that are in logical and operators. // This is a common pattern for asserts. continue; AnalyzeImplicitConversions(S, ChildExpr, CC); } if (BO && BO->isLogicalOp()) { Expr *SubExpr = BO->getLHS()->IgnoreParenImpCasts(); if (!IsLogicalAndOperator || !isa(SubExpr)) ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); SubExpr = BO->getRHS()->IgnoreParenImpCasts(); if (!IsLogicalAndOperator || !isa(SubExpr)) ::CheckBoolLikeConversion(S, SubExpr, BO->getExprLoc()); } if (const UnaryOperator *U = dyn_cast(E)) if (U->getOpcode() == UO_LNot) ::CheckBoolLikeConversion(S, U->getSubExpr(), CC); } } // end anonymous namespace static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, unsigned Start, unsigned End) { bool IllegalParams = false; for (unsigned I = Start; I <= End; ++I) { QualType Ty = TheCall->getArg(I)->getType(); // Taking into account implicit conversions, // allow any integer within 32 bits range if (!Ty->isIntegerType() || S.Context.getTypeSizeInChars(Ty).getQuantity() > 4) { S.Diag(TheCall->getArg(I)->getLocStart(), diag::err_opencl_enqueue_kernel_invalid_local_size_type); IllegalParams = true; } // Potentially emit standard warnings for implicit conversions if enabled // using -Wconversion. CheckImplicitConversion(S, TheCall->getArg(I), S.Context.UnsignedIntTy, TheCall->getArg(I)->getLocStart()); } return IllegalParams; } // Helper function for Sema::DiagnoseAlwaysNonNullPointer. // Returns true when emitting a warning about taking the address of a reference. static bool CheckForReference(Sema &SemaRef, const Expr *E, const PartialDiagnostic &PD) { E = E->IgnoreParenImpCasts(); const FunctionDecl *FD = nullptr; if (const DeclRefExpr *DRE = dyn_cast(E)) { if (!DRE->getDecl()->getType()->isReferenceType()) return false; } else if (const MemberExpr *M = dyn_cast(E)) { if (!M->getMemberDecl()->getType()->isReferenceType()) return false; } else if (const CallExpr *Call = dyn_cast(E)) { if (!Call->getCallReturnType(SemaRef.Context)->isReferenceType()) return false; FD = Call->getDirectCallee(); } else { return false; } SemaRef.Diag(E->getExprLoc(), PD); // If possible, point to location of function. if (FD) { SemaRef.Diag(FD->getLocation(), diag::note_reference_is_return_value) << FD; } return true; } // Returns true if the SourceLocation is expanded from any macro body. // Returns false if the SourceLocation is invalid, is from not in a macro // expansion, or is from expanded from a top-level macro argument. static bool IsInAnyMacroBody(const SourceManager &SM, SourceLocation Loc) { if (Loc.isInvalid()) return false; while (Loc.isMacroID()) { if (SM.isMacroBodyExpansion(Loc)) return true; Loc = SM.getImmediateMacroCallerLoc(Loc); } return false; } /// \brief Diagnose pointers that are always non-null. /// \param E the expression containing the pointer /// \param NullKind NPCK_NotNull if E is a cast to bool, otherwise, E is /// compared to a null pointer /// \param IsEqual True when the comparison is equal to a null pointer /// \param Range Extra SourceRange to highlight in the diagnostic void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, Expr::NullPointerConstantKind NullKind, bool IsEqual, SourceRange Range) { if (!E) return; // Don't warn inside macros. if (E->getExprLoc().isMacroID()) { const SourceManager &SM = getSourceManager(); if (IsInAnyMacroBody(SM, E->getExprLoc()) || IsInAnyMacroBody(SM, Range.getBegin())) return; } E = E->IgnoreImpCasts(); const bool IsCompare = NullKind != Expr::NPCK_NotNull; if (isa(E)) { unsigned DiagID = IsCompare ? diag::warn_this_null_compare : diag::warn_this_bool_conversion; Diag(E->getExprLoc(), DiagID) << E->getSourceRange() << Range << IsEqual; return; } bool IsAddressOf = false; if (UnaryOperator *UO = dyn_cast(E)) { if (UO->getOpcode() != UO_AddrOf) return; IsAddressOf = true; E = UO->getSubExpr(); } if (IsAddressOf) { unsigned DiagID = IsCompare ? diag::warn_address_of_reference_null_compare : diag::warn_address_of_reference_bool_conversion; PartialDiagnostic PD = PDiag(DiagID) << E->getSourceRange() << Range << IsEqual; if (CheckForReference(*this, E, PD)) { return; } } auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) { bool IsParam = isa(NonnullAttr); std::string Str; llvm::raw_string_ostream S(Str); E->printPretty(S, nullptr, getPrintingPolicy()); unsigned DiagID = IsCompare ? diag::warn_nonnull_expr_compare : diag::warn_cast_nonnull_to_bool; Diag(E->getExprLoc(), DiagID) << IsParam << S.str() << E->getSourceRange() << Range << IsEqual; Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam; }; // If we have a CallExpr that is tagged with returns_nonnull, we can complain. if (auto *Call = dyn_cast(E->IgnoreParenImpCasts())) { if (auto *Callee = Call->getDirectCallee()) { if (const Attr *A = Callee->getAttr()) { ComplainAboutNonnullParamOrCall(A); return; } } } // Expect to find a single Decl. Skip anything more complicated. ValueDecl *D = nullptr; if (DeclRefExpr *R = dyn_cast(E)) { D = R->getDecl(); } else if (MemberExpr *M = dyn_cast(E)) { D = M->getMemberDecl(); } // Weak Decls can be null. if (!D || D->isWeak()) return; // Check for parameter decl with nonnull attribute if (const auto* PV = dyn_cast(D)) { if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV)) { if (const Attr *A = PV->getAttr()) { ComplainAboutNonnullParamOrCall(A); return; } if (const auto *FD = dyn_cast(PV->getDeclContext())) { auto ParamIter = llvm::find(FD->parameters(), PV); assert(ParamIter != FD->param_end()); unsigned ParamNo = std::distance(FD->param_begin(), ParamIter); for (const auto *NonNull : FD->specific_attrs()) { if (!NonNull->args_size()) { ComplainAboutNonnullParamOrCall(NonNull); return; } for (unsigned ArgNo : NonNull->args()) { if (ArgNo == ParamNo) { ComplainAboutNonnullParamOrCall(NonNull); return; } } } } } } QualType T = D->getType(); const bool IsArray = T->isArrayType(); const bool IsFunction = T->isFunctionType(); // Address of function is used to silence the function warning. if (IsAddressOf && IsFunction) { return; } // Found nothing. if (!IsAddressOf && !IsFunction && !IsArray) return; // Pretty print the expression for the diagnostic. std::string Str; llvm::raw_string_ostream S(Str); E->printPretty(S, nullptr, getPrintingPolicy()); unsigned DiagID = IsCompare ? diag::warn_null_pointer_compare : diag::warn_impcast_pointer_to_bool; enum { AddressOf, FunctionPointer, ArrayPointer } DiagType; if (IsAddressOf) DiagType = AddressOf; else if (IsFunction) DiagType = FunctionPointer; else if (IsArray) DiagType = ArrayPointer; else llvm_unreachable("Could not determine diagnostic."); Diag(E->getExprLoc(), DiagID) << DiagType << S.str() << E->getSourceRange() << Range << IsEqual; if (!IsFunction) return; // Suggest '&' to silence the function warning. Diag(E->getExprLoc(), diag::note_function_warning_silence) << FixItHint::CreateInsertion(E->getLocStart(), "&"); // Check to see if '()' fixit should be emitted. QualType ReturnType; UnresolvedSet<4> NonTemplateOverloads; tryExprAsCall(*E, ReturnType, NonTemplateOverloads); if (ReturnType.isNull()) return; if (IsCompare) { // There are two cases here. If there is null constant, the only suggest // for a pointer return type. If the null is 0, then suggest if the return // type is a pointer or an integer type. if (!ReturnType->isPointerType()) { if (NullKind == Expr::NPCK_ZeroExpression || NullKind == Expr::NPCK_ZeroLiteral) { if (!ReturnType->isIntegerType()) return; } else { return; } } } else { // !IsCompare // For function to bool, only suggest if the function pointer has bool // return type. if (!ReturnType->isSpecificBuiltinType(BuiltinType::Bool)) return; } Diag(E->getExprLoc(), diag::note_function_to_function_call) << FixItHint::CreateInsertion(getLocForEndOfToken(E->getLocEnd()), "()"); } /// Diagnoses "dangerous" implicit conversions within the given /// expression (which is a full expression). Implements -Wconversion /// and -Wsign-compare. /// /// \param CC the "context" location of the implicit conversion, i.e. /// the most location of the syntactic entity requiring the implicit /// conversion void Sema::CheckImplicitConversions(Expr *E, SourceLocation CC) { // Don't diagnose in unevaluated contexts. if (isUnevaluatedContext()) return; // Don't diagnose for value- or type-dependent expressions. if (E->isTypeDependent() || E->isValueDependent()) return; // Check for array bounds violations in cases where the check isn't triggered // elsewhere for other Expr types (like BinaryOperators), e.g. when an // ArraySubscriptExpr is on the RHS of a variable initialization. CheckArrayAccess(E); // This is not the right CC for (e.g.) a variable initialization. AnalyzeImplicitConversions(*this, E, CC); } /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { ::CheckBoolLikeConversion(*this, E, CC); } /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow void Sema::CheckForIntOverflow (Expr *E) { // Use a work list to deal with nested struct initializers. SmallVector Exprs(1, E); do { Expr *E = Exprs.pop_back_val(); if (isa(E->IgnoreParenCasts())) { E->IgnoreParenCasts()->EvaluateForOverflow(Context); continue; } if (auto InitList = dyn_cast(E)) Exprs.append(InitList->inits().begin(), InitList->inits().end()); } while (!Exprs.empty()); } namespace { /// \brief Visitor for expressions which looks for unsequenced operations on the /// same object. class SequenceChecker : public EvaluatedExprVisitor { typedef EvaluatedExprVisitor Base; /// \brief A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we /// finish processing an expression with sequencing, such as a comma /// expression, we fold its tree nodes into its parent, since they are /// unsequenced with respect to nodes we will visit later. class SequenceTree { struct Value { explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {} unsigned Parent : 31; unsigned Merged : 1; }; SmallVector Values; public: /// \brief A region within an expression which may be sequenced with respect /// to some other region. class Seq { explicit Seq(unsigned N) : Index(N) {} unsigned Index; friend class SequenceTree; public: Seq() : Index(0) {} }; SequenceTree() { Values.push_back(Value(0)); } Seq root() const { return Seq(0); } /// \brief Create a new sequence of operations, which is an unsequenced /// subset of \p Parent. This sequence of operations is sequenced with /// respect to other children of \p Parent. Seq allocate(Seq Parent) { Values.push_back(Value(Parent.Index)); return Seq(Values.size() - 1); } /// \brief Merge a sequence of operations into its parent. void merge(Seq S) { Values[S.Index].Merged = true; } /// \brief Determine whether two operations are unsequenced. This operation /// is asymmetric: \p Cur should be the more recent sequence, and \p Old /// should have been merged into its parent as appropriate. bool isUnsequenced(Seq Cur, Seq Old) { unsigned C = representative(Cur.Index); unsigned Target = representative(Old.Index); while (C >= Target) { if (C == Target) return true; C = Values[C].Parent; } return false; } private: /// \brief Pick a representative for a sequence. unsigned representative(unsigned K) { if (Values[K].Merged) // Perform path compression as we go. return Values[K].Parent = representative(Values[K].Parent); return K; } }; /// An object for which we can track unsequenced uses. typedef NamedDecl *Object; /// Different flavors of object usage which we track. We only track the /// least-sequenced usage of each kind. enum UsageKind { /// A read of an object. Multiple unsequenced reads are OK. UK_Use, /// A modification of an object which is sequenced before the value /// computation of the expression, such as ++n in C++. UK_ModAsValue, /// A modification of an object which is not sequenced before the value /// computation of the expression, such as n++. UK_ModAsSideEffect, UK_Count = UK_ModAsSideEffect + 1 }; struct Usage { Usage() : Use(nullptr), Seq() {} Expr *Use; SequenceTree::Seq Seq; }; struct UsageInfo { UsageInfo() : Diagnosed(false) {} Usage Uses[UK_Count]; /// Have we issued a diagnostic for this variable already? bool Diagnosed; }; typedef llvm::SmallDenseMap UsageInfoMap; Sema &SemaRef; /// Sequenced regions within the expression. SequenceTree Tree; /// Declaration modifications and references which we have seen. UsageInfoMap UsageMap; /// The region we are currently within. SequenceTree::Seq Region; /// Filled in with declarations which were modified as a side-effect /// (that is, post-increment operations). SmallVectorImpl > *ModAsSideEffect; /// Expressions to check later. We defer checking these to reduce /// stack usage. SmallVectorImpl &WorkList; /// RAII object wrapping the visitation of a sequenced subexpression of an /// expression. At the end of this process, the side-effects of the evaluation /// become sequenced with respect to the value computation of the result, so /// we downgrade any UK_ModAsSideEffect within the evaluation to /// UK_ModAsValue. struct SequencedSubexpression { SequencedSubexpression(SequenceChecker &Self) : Self(Self), OldModAsSideEffect(Self.ModAsSideEffect) { Self.ModAsSideEffect = &ModAsSideEffect; } ~SequencedSubexpression() { for (auto &M : llvm::reverse(ModAsSideEffect)) { UsageInfo &U = Self.UsageMap[M.first]; auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue); SideEffectUsage = M.second; } Self.ModAsSideEffect = OldModAsSideEffect; } SequenceChecker &Self; SmallVector, 4> ModAsSideEffect; SmallVectorImpl > *OldModAsSideEffect; }; /// RAII object wrapping the visitation of a subexpression which we might /// choose to evaluate as a constant. If any subexpression is evaluated and /// found to be non-constant, this allows us to suppress the evaluation of /// the outer expression. class EvaluationTracker { public: EvaluationTracker(SequenceChecker &Self) : Self(Self), Prev(Self.EvalTracker), EvalOK(true) { Self.EvalTracker = this; } ~EvaluationTracker() { Self.EvalTracker = Prev; if (Prev) Prev->EvalOK &= EvalOK; } bool evaluate(const Expr *E, bool &Result) { if (!EvalOK || E->isValueDependent()) return false; EvalOK = E->EvaluateAsBooleanCondition(Result, Self.SemaRef.Context); return EvalOK; } private: SequenceChecker &Self; EvaluationTracker *Prev; bool EvalOK; } *EvalTracker; /// \brief Find the object which is produced by the specified expression, /// if any. Object getObject(Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); if (UnaryOperator *UO = dyn_cast(E)) { if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec)) return getObject(UO->getSubExpr(), Mod); } else if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) return getObject(BO->getRHS(), Mod); if (Mod && BO->isAssignmentOp()) return getObject(BO->getLHS(), Mod); } else if (MemberExpr *ME = dyn_cast(E)) { // FIXME: Check for more interesting cases, like "x.n = ++x.n". if (isa(ME->getBase()->IgnoreParenCasts())) return ME->getMemberDecl(); } else if (DeclRefExpr *DRE = dyn_cast(E)) // FIXME: If this is a reference, map through to its value. return DRE->getDecl(); return nullptr; } /// \brief Note that an object was modified or used by an expression. void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { Usage &U = UI.Uses[UK]; if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { if (UK == UK_ModAsSideEffect && ModAsSideEffect) ModAsSideEffect->push_back(std::make_pair(O, U)); U.Use = Ref; U.Seq = Region; } } /// \brief Check whether a modification or use conflicts with a prior usage. void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) return; const Usage &U = UI.Uses[OtherKind]; if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) return; Expr *Mod = U.Use; Expr *ModOrUse = Ref; if (OtherKind == UK_Use) std::swap(Mod, ModOrUse); SemaRef.Diag(Mod->getExprLoc(), IsModMod ? diag::warn_unsequenced_mod_mod : diag::warn_unsequenced_mod_use) << O << SourceRange(ModOrUse->getExprLoc()); UI.Diagnosed = true; } void notePreUse(Object O, Expr *Use) { UsageInfo &U = UsageMap[O]; // Uses conflict with other modifications. checkUsage(O, U, Use, UK_ModAsValue, false); } void notePostUse(Object O, Expr *Use) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, false); addUsage(U, O, Use, UK_Use); } void notePreMod(Object O, Expr *Mod) { UsageInfo &U = UsageMap[O]; // Modifications conflict with other modifications and with uses. checkUsage(O, U, Mod, UK_ModAsValue, true); checkUsage(O, U, Mod, UK_Use, false); } void notePostMod(Object O, Expr *Use, UsageKind UK) { UsageInfo &U = UsageMap[O]; checkUsage(O, U, Use, UK_ModAsSideEffect, true); addUsage(U, O, Use, UK); } public: SequenceChecker(Sema &S, Expr *E, SmallVectorImpl &WorkList) : Base(S.Context), SemaRef(S), Region(Tree.root()), ModAsSideEffect(nullptr), WorkList(WorkList), EvalTracker(nullptr) { Visit(E); } void VisitStmt(Stmt *S) { // Skip all statements which aren't expressions for now. } void VisitExpr(Expr *E) { // By default, just recurse to evaluated subexpressions. Base::VisitStmt(E); } void VisitCastExpr(CastExpr *E) { Object O = Object(); if (E->getCastKind() == CK_LValueToRValue) O = getObject(E->getSubExpr(), false); if (O) notePreUse(O, E); VisitExpr(E); if (O) notePostUse(O, E); } void VisitBinComma(BinaryOperator *BO) { // C++11 [expr.comma]p1: // Every value computation and side effect associated with the left // expression is sequenced before every value computation and side // effect associated with the right expression. SequenceTree::Seq LHS = Tree.allocate(Region); SequenceTree::Seq RHS = Tree.allocate(Region); SequenceTree::Seq OldRegion = Region; { SequencedSubexpression SeqLHS(*this); Region = LHS; Visit(BO->getLHS()); } Region = RHS; Visit(BO->getRHS()); Region = OldRegion; // Forget that LHS and RHS are sequenced. They are both unsequenced // with respect to other stuff. Tree.merge(LHS); Tree.merge(RHS); } void VisitBinAssign(BinaryOperator *BO) { // The modification is sequenced after the value computation of the LHS // and RHS, so check it before inspecting the operands and update the // map afterwards. Object O = getObject(BO->getLHS(), true); if (!O) return VisitExpr(BO); notePreMod(O, BO); // C++11 [expr.ass]p7: // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated // only once. // // Therefore, for a compound assignment operator, O is considered used // everywhere except within the evaluation of E1 itself. if (isa(BO)) notePreUse(O, BO); Visit(BO->getLHS()); if (isa(BO)) notePostUse(O, BO); Visit(BO->getRHS()); // C++11 [expr.ass]p1: // the assignment is sequenced [...] before the value computation of the // assignment expression. // C11 6.5.16/3 has no such rule. notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue : UK_ModAsSideEffect); } void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } void VisitUnaryPreIncDec(UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); notePreMod(O, UO); Visit(UO->getSubExpr()); // C++11 [expr.pre.incr]p1: // the expression ++x is equivalent to x+=1 notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue : UK_ModAsSideEffect); } void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } void VisitUnaryPostIncDec(UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); notePreMod(O, UO); Visit(UO->getSubExpr()); notePostMod(O, UO, UK_ModAsSideEffect); } /// Don't visit the RHS of '&&' or '||' if it might not be evaluated. void VisitBinLOr(BinaryOperator *BO) { // The side-effects of the LHS of an '&&' are sequenced before the // value computation of the RHS, and hence before the value computation // of the '&&' itself, unless the LHS evaluates to zero. We treat them // as if they were unconditionally sequenced. EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); Visit(BO->getLHS()); } bool Result; if (Eval.evaluate(BO->getLHS(), Result)) { if (!Result) Visit(BO->getRHS()); } else { // Check for unsequenced operations in the RHS, treating it as an // entirely separate evaluation. // // FIXME: If there are operations in the RHS which are unsequenced // with respect to operations outside the RHS, and those operations // are unconditionally evaluated, diagnose them. WorkList.push_back(BO->getRHS()); } } void VisitBinLAnd(BinaryOperator *BO) { EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); Visit(BO->getLHS()); } bool Result; if (Eval.evaluate(BO->getLHS(), Result)) { if (Result) Visit(BO->getRHS()); } else { WorkList.push_back(BO->getRHS()); } } // Only visit the condition, unless we can be sure which subexpression will // be chosen. void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) { EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); Visit(CO->getCond()); } bool Result; if (Eval.evaluate(CO->getCond(), Result)) Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr()); else { WorkList.push_back(CO->getTrueExpr()); WorkList.push_back(CO->getFalseExpr()); } } void VisitCallExpr(CallExpr *CE) { // C++11 [intro.execution]p15: // When calling a function [...], every value computation and side effect // associated with any argument expression, or with the postfix expression // designating the called function, is sequenced before execution of every // expression or statement in the body of the function [and thus before // the value computation of its result]. SequencedSubexpression Sequenced(*this); Base::VisitCallExpr(CE); // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. } void VisitCXXConstructExpr(CXXConstructExpr *CCE) { // This is a call, so all subexpressions are sequenced before the result. SequencedSubexpression Sequenced(*this); if (!CCE->isListInitialization()) return VisitExpr(CCE); // In C++11, list initializations are sequenced. SmallVector Elts; SequenceTree::Seq Parent = Region; for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(), E = CCE->arg_end(); I != E; ++I) { Region = Tree.allocate(Parent); Elts.push_back(Region); Visit(*I); } // Forget that the initializers are sequenced. Region = Parent; for (unsigned I = 0; I < Elts.size(); ++I) Tree.merge(Elts[I]); } void VisitInitListExpr(InitListExpr *ILE) { if (!SemaRef.getLangOpts().CPlusPlus11) return VisitExpr(ILE); // In C++11, list initializations are sequenced. SmallVector Elts; SequenceTree::Seq Parent = Region; for (unsigned I = 0; I < ILE->getNumInits(); ++I) { Expr *E = ILE->getInit(I); if (!E) continue; Region = Tree.allocate(Parent); Elts.push_back(Region); Visit(E); } // Forget that the initializers are sequenced. Region = Parent; for (unsigned I = 0; I < Elts.size(); ++I) Tree.merge(Elts[I]); } }; } // end anonymous namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector WorkList; WorkList.push_back(E); while (!WorkList.empty()) { Expr *Item = WorkList.pop_back_val(); SequenceChecker(*this, Item, WorkList); } } void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, bool IsConstexpr) { CheckImplicitConversions(E, CheckLoc); if (!E->isInstantiationDependent()) CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, FieldDecl *BitField, Expr *Init) { (void) AnalyzeBitFieldAssignment(*this, BitField, Init, InitLoc); } static void diagnoseArrayStarInParamType(Sema &S, QualType PType, SourceLocation Loc) { if (!PType->isVariablyModifiedType()) return; if (const auto *PointerTy = dyn_cast(PType)) { diagnoseArrayStarInParamType(S, PointerTy->getPointeeType(), Loc); return; } if (const auto *ReferenceTy = dyn_cast(PType)) { diagnoseArrayStarInParamType(S, ReferenceTy->getPointeeType(), Loc); return; } if (const auto *ParenTy = dyn_cast(PType)) { diagnoseArrayStarInParamType(S, ParenTy->getInnerType(), Loc); return; } const ArrayType *AT = S.Context.getAsArrayType(PType); if (!AT) return; if (AT->getSizeModifier() != ArrayType::Star) { diagnoseArrayStarInParamType(S, AT->getElementType(), Loc); return; } S.Diag(Loc, diag::err_array_star_in_function_definition); } /// CheckParmsForFunctionDef - Check that the parameters of the given /// function are appropriate for the definition of a function. This /// takes care of any checks that cannot be performed on the /// declaration itself, e.g., that the types of each of the function /// parameters are complete. bool Sema::CheckParmsForFunctionDef(ArrayRef Parameters, bool CheckParameterNames) { bool HasInvalidParm = false; for (ParmVarDecl *Param : Parameters) { // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. // // This is also C++ [dcl.fct]p6. if (!Param->isInvalidDecl() && RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) { Param->setInvalidDecl(); HasInvalidParm = true; } // C99 6.9.1p5: If the declarator includes a parameter type list, the // declaration of each parameter shall include an identifier. if (CheckParameterNames && Param->getIdentifier() == nullptr && !Param->isImplicit() && !getLangOpts().CPlusPlus) Diag(Param->getLocation(), diag::err_parameter_name_omitted); // C99 6.7.5.3p12: // If the function declarator is not part of a definition of that // function, parameters may have incomplete type and may use the [*] // notation in their sequences of declarator specifiers to specify // variable length array types. QualType PType = Param->getOriginalType(); // FIXME: This diagnostic should point the '[*]' if source-location // information is added for it. diagnoseArrayStarInParamType(*this, PType, Param->getLocation()); // MSVC destroys objects passed by value in the callee. Therefore a // function definition which takes such a parameter must be able to call the // object's destructor. However, we don't perform any direct access check // on the dtor. if (getLangOpts().CPlusPlus && Context.getTargetInfo() .getCXXABI() .areArgsDestroyedLeftToRightInCallee()) { if (!Param->isInvalidDecl()) { if (const RecordType *RT = Param->getType()->getAs()) { CXXRecordDecl *ClassDecl = cast(RT->getDecl()); if (!ClassDecl->isInvalidDecl() && !ClassDecl->hasIrrelevantDestructor() && !ClassDecl->isDependentContext()) { CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl); MarkFunctionReferenced(Param->getLocation(), Destructor); DiagnoseUseOfDecl(Destructor, Param->getLocation()); } } } } // Parameters with the pass_object_size attribute only need to be marked // constant at function definitions. Because we lack information about // whether we're on a declaration or definition when we're instantiating the // attribute, we need to check for constness here. if (const auto *Attr = Param->getAttr()) if (!Param->getType().isConstQualified()) Diag(Param->getLocation(), diag::err_attribute_pointers_only) << Attr->getSpelling() << 1; } return HasInvalidParm; } /// CheckCastAlign - Implements -Wcast-align, which warns when a /// pointer cast increases the alignment requirements. void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { // This is actually a lot of work to potentially be doing on every // cast; don't do it if we're ignoring -Wcast_align (as is the default). if (getDiagnostics().isIgnored(diag::warn_cast_align, TRange.getBegin())) return; // Ignore dependent types. if (T->isDependentType() || Op->getType()->isDependentType()) return; // Require that the destination be a pointer type. const PointerType *DestPtr = T->getAs(); if (!DestPtr) return; // If the destination has alignment 1, we're done. QualType DestPointee = DestPtr->getPointeeType(); if (DestPointee->isIncompleteType()) return; CharUnits DestAlign = Context.getTypeAlignInChars(DestPointee); if (DestAlign.isOne()) return; // Require that the source be a pointer type. const PointerType *SrcPtr = Op->getType()->getAs(); if (!SrcPtr) return; QualType SrcPointee = SrcPtr->getPointeeType(); // Whitelist casts from cv void*. We already implicitly // whitelisted casts to cv void*, since they have alignment 1. // Also whitelist casts involving incomplete types, which implicitly // includes 'void'. if (SrcPointee->isIncompleteType()) return; CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); if (SrcAlign >= DestAlign) return; Diag(TRange.getBegin(), diag::warn_cast_align) << Op->getType() << T << static_cast(SrcAlign.getQuantity()) << static_cast(DestAlign.getQuantity()) << TRange << Op->getSourceRange(); } /// \brief Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are /// commonly used to emulate flexible arrays in C89 code. static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, const NamedDecl *ND) { if (Size != 1 || !ND) return false; const FieldDecl *FD = dyn_cast(ND); if (!FD) return false; // Don't consider sizes resulting from macro expansions or template argument // substitution to form C89 tail-padded arrays. TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); while (TInfo) { TypeLoc TL = TInfo->getTypeLoc(); // Look through typedefs. if (TypedefTypeLoc TTL = TL.getAs()) { const TypedefNameDecl *TDL = TTL.getTypedefNameDecl(); TInfo = TDL->getTypeSourceInfo(); continue; } if (ConstantArrayTypeLoc CTL = TL.getAs()) { const Expr *SizeExpr = dyn_cast(CTL.getSizeExpr()); if (!SizeExpr || SizeExpr->getExprLoc().isMacroID()) return false; } break; } const RecordDecl *RD = dyn_cast(FD->getDeclContext()); if (!RD) return false; if (RD->isUnion()) return false; if (const CXXRecordDecl *CRD = dyn_cast(RD)) { if (!CRD->isStandardLayout()) return false; } // See if this is the last field decl in the record. const Decl *D = FD; while ((D = D->getNextDeclInContext())) if (isa(D)) return false; return true; } void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE, bool AllowOnePastEnd, bool IndexNegated) { IndexExpr = IndexExpr->IgnoreParenImpCasts(); if (IndexExpr->isValueDependent()) return; const Type *EffectiveType = BaseExpr->getType()->getPointeeOrArrayElementType(); BaseExpr = BaseExpr->IgnoreParenCasts(); const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); if (!ArrayTy) return; llvm::APSInt index; if (!IndexExpr->EvaluateAsInt(index, Context, Expr::SE_AllowSideEffects)) return; if (IndexNegated) index = -index; const NamedDecl *ND = nullptr; if (const DeclRefExpr *DRE = dyn_cast(BaseExpr)) ND = dyn_cast(DRE->getDecl()); if (const MemberExpr *ME = dyn_cast(BaseExpr)) ND = dyn_cast(ME->getMemberDecl()); if (index.isUnsigned() || !index.isNegative()) { llvm::APInt size = ArrayTy->getSize(); if (!size.isStrictlyPositive()) return; const Type *BaseType = BaseExpr->getType()->getPointeeOrArrayElementType(); if (BaseType != EffectiveType) { // Make sure we're comparing apples to apples when comparing index to size uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); uint64_t array_typesize = Context.getTypeSize(BaseType); // Handle ptrarith_typesize being zero, such as when casting to void* if (!ptrarith_typesize) ptrarith_typesize = 1; if (ptrarith_typesize != array_typesize) { // There's a cast to a different size type involved uint64_t ratio = array_typesize / ptrarith_typesize; // TODO: Be smarter about handling cases where array_typesize is not a // multiple of ptrarith_typesize if (ptrarith_typesize * ratio == array_typesize) size *= llvm::APInt(size.getBitWidth(), ratio); } } if (size.getBitWidth() > index.getBitWidth()) index = index.zext(size.getBitWidth()); else if (size.getBitWidth() < index.getBitWidth()) size = size.zext(index.getBitWidth()); // For array subscripting the index must be less than size, but for pointer // arithmetic also allow the index (offset) to be equal to size since // computing the next address after the end of the array is legal and // commonly done e.g. in C++ iterators and range-based for loops. if (AllowOnePastEnd ? index.ule(size) : index.ult(size)) return; // Also don't warn for arrays of size 1 which are members of some // structure. These are often used to approximate flexible arrays in C89 // code. if (IsTailPaddedMemberArray(*this, size, ND)) return; // Suppress the warning if the subscript expression (as identified by the // ']' location) and the index expression are both from macro expansions // within a system header. if (ASE) { SourceLocation RBracketLoc = SourceMgr.getSpellingLoc( ASE->getRBracketLoc()); if (SourceMgr.isInSystemHeader(RBracketLoc)) { SourceLocation IndexLoc = SourceMgr.getSpellingLoc( IndexExpr->getLocStart()); if (SourceMgr.isWrittenInSameFile(RBracketLoc, IndexLoc)) return; } } unsigned DiagID = diag::warn_ptr_arith_exceeds_bounds; if (ASE) DiagID = diag::warn_array_index_exceeds_bounds; DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, PDiag(DiagID) << index.toString(10, true) << size.toString(10, true) << (unsigned)size.getLimitedValue(~0U) << IndexExpr->getSourceRange()); } else { unsigned DiagID = diag::warn_array_index_precedes_bounds; if (!ASE) { DiagID = diag::warn_ptr_arith_precedes_bounds; if (index.isNegative()) index = -index; } DiagRuntimeBehavior(BaseExpr->getLocStart(), BaseExpr, PDiag(DiagID) << index.toString(10, true) << IndexExpr->getSourceRange()); } if (!ND) { // Try harder to find a NamedDecl to point at in the note. while (const ArraySubscriptExpr *ASE = dyn_cast(BaseExpr)) BaseExpr = ASE->getBase()->IgnoreParenCasts(); if (const DeclRefExpr *DRE = dyn_cast(BaseExpr)) ND = dyn_cast(DRE->getDecl()); if (const MemberExpr *ME = dyn_cast(BaseExpr)) ND = dyn_cast(ME->getMemberDecl()); } if (ND) DiagRuntimeBehavior(ND->getLocStart(), BaseExpr, PDiag(diag::note_array_index_out_of_bounds) << ND->getDeclName()); } void Sema::CheckArrayAccess(const Expr *expr) { int AllowOnePastEnd = 0; while (expr) { expr = expr->IgnoreParenImpCasts(); switch (expr->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { const ArraySubscriptExpr *ASE = cast(expr); CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0); return; } case Stmt::OMPArraySectionExprClass: { const OMPArraySectionExpr *ASE = cast(expr); if (ASE->getLowerBound()) CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), /*ASE=*/nullptr, AllowOnePastEnd > 0); return; } case Stmt::UnaryOperatorClass: { // Only unwrap the * and & unary operators const UnaryOperator *UO = cast(expr); expr = UO->getSubExpr(); switch (UO->getOpcode()) { case UO_AddrOf: AllowOnePastEnd++; break; case UO_Deref: AllowOnePastEnd--; break; default: return; } break; } case Stmt::ConditionalOperatorClass: { const ConditionalOperator *cond = cast(expr); if (const Expr *lhs = cond->getLHS()) CheckArrayAccess(lhs); if (const Expr *rhs = cond->getRHS()) CheckArrayAccess(rhs); return; } default: return; } } } //===--- CHECK: Objective-C retain cycles ----------------------------------// namespace { struct RetainCycleOwner { RetainCycleOwner() : Variable(nullptr), Indirect(false) {} VarDecl *Variable; SourceRange Range; SourceLocation Loc; bool Indirect; void setLocsFrom(Expr *e) { Loc = e->getExprLoc(); Range = e->getSourceRange(); } }; } // end anonymous namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) { // In ARC, it's captured strongly iff the variable has __strong // lifetime. In MRR, it's captured strongly if the variable is // __block and has an appropriate type. if (var->getType().getObjCLifetime() != Qualifiers::OCL_Strong) return false; owner.Variable = var; if (ref) owner.setLocsFrom(ref); return true; } static bool findRetainCycleOwner(Sema &S, Expr *e, RetainCycleOwner &owner) { while (true) { e = e->IgnoreParens(); if (CastExpr *cast = dyn_cast(e)) { switch (cast->getCastKind()) { case CK_BitCast: case CK_LValueBitCast: case CK_LValueToRValue: case CK_ARCReclaimReturnedObject: e = cast->getSubExpr(); continue; default: return false; } } if (ObjCIvarRefExpr *ref = dyn_cast(e)) { ObjCIvarDecl *ivar = ref->getDecl(); if (ivar->getType().getObjCLifetime() != Qualifiers::OCL_Strong) return false; // Try to find a retain cycle in the base. if (!findRetainCycleOwner(S, ref->getBase(), owner)) return false; if (ref->isFreeIvar()) owner.setLocsFrom(ref); owner.Indirect = true; return true; } if (DeclRefExpr *ref = dyn_cast(e)) { VarDecl *var = dyn_cast(ref->getDecl()); if (!var) return false; return considerVariable(var, ref, owner); } if (MemberExpr *member = dyn_cast(e)) { if (member->isArrow()) return false; // Don't count this as an indirect ownership. e = member->getBase(); continue; } if (PseudoObjectExpr *pseudo = dyn_cast(e)) { // Only pay attention to pseudo-objects on property references. ObjCPropertyRefExpr *pre = dyn_cast(pseudo->getSyntacticForm() ->IgnoreParens()); if (!pre) return false; if (pre->isImplicitProperty()) return false; ObjCPropertyDecl *property = pre->getExplicitProperty(); if (!property->isRetaining() && !(property->getPropertyIvarDecl() && property->getPropertyIvarDecl()->getType() .getObjCLifetime() == Qualifiers::OCL_Strong)) return false; owner.Indirect = true; if (pre->isSuperReceiver()) { owner.Variable = S.getCurMethodDecl()->getSelfDecl(); if (!owner.Variable) return false; owner.Loc = pre->getLocation(); owner.Range = pre->getSourceRange(); return true; } e = const_cast(cast(pre->getBase()) ->getSourceExpr()); continue; } // Array ivars? return false; } } namespace { struct FindCaptureVisitor : EvaluatedExprVisitor { FindCaptureVisitor(ASTContext &Context, VarDecl *variable) : EvaluatedExprVisitor(Context), Context(Context), Variable(variable), Capturer(nullptr), VarWillBeReased(false) {} ASTContext &Context; VarDecl *Variable; Expr *Capturer; bool VarWillBeReased; void VisitDeclRefExpr(DeclRefExpr *ref) { if (ref->getDecl() == Variable && !Capturer) Capturer = ref; } void VisitObjCIvarRefExpr(ObjCIvarRefExpr *ref) { if (Capturer) return; Visit(ref->getBase()); if (Capturer && ref->isFreeIvar()) Capturer = ref; } void VisitBlockExpr(BlockExpr *block) { // Look inside nested blocks if (block->getBlockDecl()->capturesVariable(Variable)) Visit(block->getBlockDecl()->getBody()); } void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) { if (Capturer) return; if (OVE->getSourceExpr()) Visit(OVE->getSourceExpr()); } void VisitBinaryOperator(BinaryOperator *BinOp) { if (!Variable || VarWillBeReased || BinOp->getOpcode() != BO_Assign) return; Expr *LHS = BinOp->getLHS(); if (const DeclRefExpr *DRE = dyn_cast_or_null(LHS)) { if (DRE->getDecl() != Variable) return; if (Expr *RHS = BinOp->getRHS()) { RHS = RHS->IgnoreParenCasts(); llvm::APSInt Value; VarWillBeReased = (RHS && RHS->isIntegerConstantExpr(Value, Context) && Value == 0); } } } }; } // end anonymous namespace /// Check whether the given argument is a block which captures a /// variable. static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) { assert(owner.Variable && owner.Loc.isValid()); e = e->IgnoreParenCasts(); // Look through [^{...} copy] and Block_copy(^{...}). if (ObjCMessageExpr *ME = dyn_cast(e)) { Selector Cmd = ME->getSelector(); if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") { e = ME->getInstanceReceiver(); if (!e) return nullptr; e = e->IgnoreParenCasts(); } } else if (CallExpr *CE = dyn_cast(e)) { if (CE->getNumArgs() == 1) { FunctionDecl *Fn = dyn_cast_or_null(CE->getCalleeDecl()); if (Fn) { const IdentifierInfo *FnI = Fn->getIdentifier(); if (FnI && FnI->isStr("_Block_copy")) { e = CE->getArg(0)->IgnoreParenCasts(); } } } } BlockExpr *block = dyn_cast(e); if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable)) return nullptr; FindCaptureVisitor visitor(S.Context, owner.Variable); visitor.Visit(block->getBlockDecl()->getBody()); return visitor.VarWillBeReased ? nullptr : visitor.Capturer; } static void diagnoseRetainCycle(Sema &S, Expr *capturer, RetainCycleOwner &owner) { assert(capturer); assert(owner.Variable && owner.Loc.isValid()); S.Diag(capturer->getExprLoc(), diag::warn_arc_retain_cycle) << owner.Variable << capturer->getSourceRange(); S.Diag(owner.Loc, diag::note_arc_retain_cycle_owner) << owner.Indirect << owner.Range; } /// Check for a keyword selector that starts with the word 'add' or /// 'set'. static bool isSetterLikeSelector(Selector sel) { if (sel.isUnarySelector()) return false; StringRef str = sel.getNameForSlot(0); while (!str.empty() && str.front() == '_') str = str.substr(1); if (str.startswith("set")) str = str.substr(3); else if (str.startswith("add")) { // Specially whitelist 'addOperationWithBlock:'. if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock")) return false; str = str.substr(3); } else return false; if (str.empty()) return true; return !isLowercase(str.front()); } static Optional GetNSMutableArrayArgumentIndex(Sema &S, ObjCMessageExpr *Message) { bool IsMutableArray = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableArray); if (!IsMutableArray) { return None; } Selector Sel = Message->getSelector(); Optional MKOpt = S.NSAPIObj->getNSArrayMethodKind(Sel); if (!MKOpt) { return None; } NSAPI::NSArrayMethodKind MK = *MKOpt; switch (MK) { case NSAPI::NSMutableArr_addObject: case NSAPI::NSMutableArr_insertObjectAtIndex: case NSAPI::NSMutableArr_setObjectAtIndexedSubscript: return 0; case NSAPI::NSMutableArr_replaceObjectAtIndex: return 1; default: return None; } return None; } static Optional GetNSMutableDictionaryArgumentIndex(Sema &S, ObjCMessageExpr *Message) { bool IsMutableDictionary = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableDictionary); if (!IsMutableDictionary) { return None; } Selector Sel = Message->getSelector(); Optional MKOpt = S.NSAPIObj->getNSDictionaryMethodKind(Sel); if (!MKOpt) { return None; } NSAPI::NSDictionaryMethodKind MK = *MKOpt; switch (MK) { case NSAPI::NSMutableDict_setObjectForKey: case NSAPI::NSMutableDict_setValueForKey: case NSAPI::NSMutableDict_setObjectForKeyedSubscript: return 0; default: return None; } return None; } static Optional GetNSSetArgumentIndex(Sema &S, ObjCMessageExpr *Message) { bool IsMutableSet = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableSet); bool IsMutableOrderedSet = S.NSAPIObj->isSubclassOfNSClass( Message->getReceiverInterface(), NSAPI::ClassId_NSMutableOrderedSet); if (!IsMutableSet && !IsMutableOrderedSet) { return None; } Selector Sel = Message->getSelector(); Optional MKOpt = S.NSAPIObj->getNSSetMethodKind(Sel); if (!MKOpt) { return None; } NSAPI::NSSetMethodKind MK = *MKOpt; switch (MK) { case NSAPI::NSMutableSet_addObject: case NSAPI::NSOrderedSet_setObjectAtIndex: case NSAPI::NSOrderedSet_setObjectAtIndexedSubscript: case NSAPI::NSOrderedSet_insertObjectAtIndex: return 0; case NSAPI::NSOrderedSet_replaceObjectAtIndexWithObject: return 1; } return None; } void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { if (!Message->isInstanceMessage()) { return; } Optional ArgOpt; if (!(ArgOpt = GetNSMutableArrayArgumentIndex(*this, Message)) && !(ArgOpt = GetNSMutableDictionaryArgumentIndex(*this, Message)) && !(ArgOpt = GetNSSetArgumentIndex(*this, Message))) { return; } int ArgIndex = *ArgOpt; Expr *Arg = Message->getArg(ArgIndex)->IgnoreImpCasts(); if (OpaqueValueExpr *OE = dyn_cast(Arg)) { Arg = OE->getSourceExpr()->IgnoreImpCasts(); } if (Message->getReceiverKind() == ObjCMessageExpr::SuperInstance) { if (DeclRefExpr *ArgRE = dyn_cast(Arg)) { if (ArgRE->isObjCSelfExpr()) { Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) << ArgRE->getDecl()->getName() << StringRef("super"); } } } else { Expr *Receiver = Message->getInstanceReceiver()->IgnoreImpCasts(); if (OpaqueValueExpr *OE = dyn_cast(Receiver)) { Receiver = OE->getSourceExpr()->IgnoreImpCasts(); } if (DeclRefExpr *ReceiverRE = dyn_cast(Receiver)) { if (DeclRefExpr *ArgRE = dyn_cast(Arg)) { if (ReceiverRE->getDecl() == ArgRE->getDecl()) { ValueDecl *Decl = ReceiverRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) << Decl->getName() << Decl->getName(); if (!ArgRE->isObjCSelfExpr()) { Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) << Decl->getName(); } } } } else if (ObjCIvarRefExpr *IvarRE = dyn_cast(Receiver)) { if (ObjCIvarRefExpr *IvarArgRE = dyn_cast(Arg)) { if (IvarRE->getDecl() == IvarArgRE->getDecl()) { ObjCIvarDecl *Decl = IvarRE->getDecl(); Diag(Message->getSourceRange().getBegin(), diag::warn_objc_circular_container) << Decl->getName() << Decl->getName(); Diag(Decl->getLocation(), diag::note_objc_circular_container_declared_here) << Decl->getName(); } } } } } /// Check a message send to see if it's likely to cause a retain cycle. void Sema::checkRetainCycles(ObjCMessageExpr *msg) { // Only check instance methods whose selector looks like a setter. if (!msg->isInstanceMessage() || !isSetterLikeSelector(msg->getSelector())) return; // Try to find a variable that the receiver is strongly owned by. RetainCycleOwner owner; if (msg->getReceiverKind() == ObjCMessageExpr::Instance) { if (!findRetainCycleOwner(*this, msg->getInstanceReceiver(), owner)) return; } else { assert(msg->getReceiverKind() == ObjCMessageExpr::SuperInstance); owner.Variable = getCurMethodDecl()->getSelfDecl(); owner.Loc = msg->getSuperLoc(); owner.Range = msg->getSuperLoc(); } // Check whether the receiver is captured by any of the arguments. for (unsigned i = 0, e = msg->getNumArgs(); i != e; ++i) if (Expr *capturer = findCapturingExpr(*this, msg->getArg(i), owner)) return diagnoseRetainCycle(*this, capturer, owner); } /// Check a property assign to see if it's likely to cause a retain cycle. void Sema::checkRetainCycles(Expr *receiver, Expr *argument) { RetainCycleOwner owner; if (!findRetainCycleOwner(*this, receiver, owner)) return; if (Expr *capturer = findCapturingExpr(*this, argument, owner)) diagnoseRetainCycle(*this, capturer, owner); } void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) { RetainCycleOwner Owner; if (!considerVariable(Var, /*DeclRefExpr=*/nullptr, Owner)) return; // Because we don't have an expression for the variable, we have to set the // location explicitly here. Owner.Loc = Var->getLocation(); Owner.Range = Var->getSourceRange(); if (Expr *Capturer = findCapturingExpr(*this, Init, Owner)) diagnoseRetainCycle(*this, Capturer, Owner); } static bool checkUnsafeAssignLiteral(Sema &S, SourceLocation Loc, Expr *RHS, bool isProperty) { // Check if RHS is an Objective-C object literal, which also can get // immediately zapped in a weak reference. Note that we explicitly // allow ObjCStringLiterals, since those are designed to never really die. RHS = RHS->IgnoreParenImpCasts(); // This enum needs to match with the 'select' in // warn_objc_arc_literal_assign (off-by-1). Sema::ObjCLiteralKind Kind = S.CheckLiteralKind(RHS); if (Kind == Sema::LK_String || Kind == Sema::LK_None) return false; S.Diag(Loc, diag::warn_arc_literal_assign) << (unsigned) Kind << (isProperty ? 0 : 1) << RHS->getSourceRange(); return true; } static bool checkUnsafeAssignObject(Sema &S, SourceLocation Loc, Qualifiers::ObjCLifetime LT, Expr *RHS, bool isProperty) { // Strip off any implicit cast added to get to the one ARC-specific. while (ImplicitCastExpr *cast = dyn_cast(RHS)) { if (cast->getCastKind() == CK_ARCConsumeObject) { S.Diag(Loc, diag::warn_arc_retained_assign) << (LT == Qualifiers::OCL_ExplicitNone) << (isProperty ? 0 : 1) << RHS->getSourceRange(); return true; } RHS = cast->getSubExpr(); } if (LT == Qualifiers::OCL_Weak && checkUnsafeAssignLiteral(S, Loc, RHS, isProperty)) return true; return false; } bool Sema::checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS) { Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); if (LT != Qualifiers::OCL_Weak && LT != Qualifiers::OCL_ExplicitNone) return false; if (checkUnsafeAssignObject(*this, Loc, LT, RHS, false)) return true; return false; } void Sema::checkUnsafeExprAssigns(SourceLocation Loc, Expr *LHS, Expr *RHS) { QualType LHSType; // PropertyRef on LHS type need be directly obtained from // its declaration as it has a PseudoType. ObjCPropertyRefExpr *PRE = dyn_cast(LHS->IgnoreParens()); if (PRE && !PRE->isImplicitProperty()) { const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); if (PD) LHSType = PD->getType(); } if (LHSType.isNull()) LHSType = LHS->getType(); Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); if (LT == Qualifiers::OCL_Weak) { if (!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, Loc)) getCurFunction()->markSafeWeakUse(LHS); } if (checkUnsafeAssigns(Loc, LHSType, RHS)) return; // FIXME. Check for other life times. if (LT != Qualifiers::OCL_None) return; if (PRE) { if (PRE->isImplicitProperty()) return; const ObjCPropertyDecl *PD = PRE->getExplicitProperty(); if (!PD) return; unsigned Attributes = PD->getPropertyAttributes(); if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) { // when 'assign' attribute was not explicitly specified // by user, ignore it and rely on property type itself // for lifetime info. unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten(); if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) && LHSType->isObjCRetainableType()) return; while (ImplicitCastExpr *cast = dyn_cast(RHS)) { if (cast->getCastKind() == CK_ARCConsumeObject) { Diag(Loc, diag::warn_arc_retained_property_assign) << RHS->getSourceRange(); return; } RHS = cast->getSubExpr(); } } else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) { if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true)) return; } } } //===--- CHECK: Empty statement body (-Wempty-body) ---------------------===// namespace { bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, SourceLocation StmtLoc, const NullStmt *Body) { // Do not warn if the body is a macro that expands to nothing, e.g: // // #define CALL(x) // if (condition) // CALL(0); // if (Body->hasLeadingEmptyMacro()) return false; // Get line numbers of statement and body. bool StmtLineInvalid; unsigned StmtLine = SourceMgr.getPresumedLineNumber(StmtLoc, &StmtLineInvalid); if (StmtLineInvalid) return false; bool BodyLineInvalid; unsigned BodyLine = SourceMgr.getSpellingLineNumber(Body->getSemiLoc(), &BodyLineInvalid); if (BodyLineInvalid) return false; // Warn if null statement and body are on the same line. if (StmtLine != BodyLine) return false; return true; } } // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, unsigned DiagID) { // Since this is a syntactic check, don't emit diagnostic for template // instantiations, this just adds noise. if (CurrentInstantiationScope) return; // The body should be a null statement. const NullStmt *NBody = dyn_cast(Body); if (!NBody) return; // Do the usual checks. if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody)) return; Diag(NBody->getSemiLoc(), DiagID); Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line); } void Sema::DiagnoseEmptyLoopBody(const Stmt *S, const Stmt *PossibleBody) { assert(!CurrentInstantiationScope); // Ensured by caller SourceLocation StmtLoc; const Stmt *Body; unsigned DiagID; if (const ForStmt *FS = dyn_cast(S)) { StmtLoc = FS->getRParenLoc(); Body = FS->getBody(); DiagID = diag::warn_empty_for_body; } else if (const WhileStmt *WS = dyn_cast(S)) { StmtLoc = WS->getCond()->getSourceRange().getEnd(); Body = WS->getBody(); DiagID = diag::warn_empty_while_body; } else return; // Neither `for' nor `while'. // The body should be a null statement. const NullStmt *NBody = dyn_cast(Body); if (!NBody) return; // Skip expensive checks if diagnostic is disabled. if (Diags.isIgnored(DiagID, NBody->getSemiLoc())) return; // Do the usual checks. if (!ShouldDiagnoseEmptyStmtBody(SourceMgr, StmtLoc, NBody)) return; // `for(...);' and `while(...);' are popular idioms, so in order to keep // noise level low, emit diagnostics only if for/while is followed by a // CompoundStmt, e.g.: // for (int i = 0; i < n; i++); // { // a(i); // } // or if for/while is followed by a statement with more indentation // than for/while itself: // for (int i = 0; i < n; i++); // a(i); bool ProbableTypo = isa(PossibleBody); if (!ProbableTypo) { bool BodyColInvalid; unsigned BodyCol = SourceMgr.getPresumedColumnNumber( PossibleBody->getLocStart(), &BodyColInvalid); if (BodyColInvalid) return; bool StmtColInvalid; unsigned StmtCol = SourceMgr.getPresumedColumnNumber( S->getLocStart(), &StmtColInvalid); if (StmtColInvalid) return; if (BodyCol > StmtCol) ProbableTypo = true; } if (ProbableTypo) { Diag(NBody->getSemiLoc(), DiagID); Diag(NBody->getSemiLoc(), diag::note_empty_body_on_separate_line); } } //===--- CHECK: Warn on self move with std::move. -------------------------===// /// DiagnoseSelfMove - Emits a warning if a value is moved to itself. void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc) { if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) return; if (!ActiveTemplateInstantiations.empty()) return; // Strip parens and casts away. LHSExpr = LHSExpr->IgnoreParenImpCasts(); RHSExpr = RHSExpr->IgnoreParenImpCasts(); // Check for a call expression const CallExpr *CE = dyn_cast(RHSExpr); if (!CE || CE->getNumArgs() != 1) return; // Check for a call to std::move const FunctionDecl *FD = CE->getDirectCallee(); if (!FD || !FD->isInStdNamespace() || !FD->getIdentifier() || !FD->getIdentifier()->isStr("move")) return; // Get argument from std::move RHSExpr = CE->getArg(0); const DeclRefExpr *LHSDeclRef = dyn_cast(LHSExpr); const DeclRefExpr *RHSDeclRef = dyn_cast(RHSExpr); // Two DeclRefExpr's, check that the decls are the same. if (LHSDeclRef && RHSDeclRef) { if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) return; if (LHSDeclRef->getDecl()->getCanonicalDecl() != RHSDeclRef->getDecl()->getCanonicalDecl()) return; Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); return; } // Member variables require a different approach to check for self moves. // MemberExpr's are the same if every nested MemberExpr refers to the same // Decl and that the base Expr's are DeclRefExpr's with the same Decl or // the base Expr's are CXXThisExpr's. const Expr *LHSBase = LHSExpr; const Expr *RHSBase = RHSExpr; const MemberExpr *LHSME = dyn_cast(LHSExpr); const MemberExpr *RHSME = dyn_cast(RHSExpr); if (!LHSME || !RHSME) return; while (LHSME && RHSME) { if (LHSME->getMemberDecl()->getCanonicalDecl() != RHSME->getMemberDecl()->getCanonicalDecl()) return; LHSBase = LHSME->getBase(); RHSBase = RHSME->getBase(); LHSME = dyn_cast(LHSBase); RHSME = dyn_cast(RHSBase); } LHSDeclRef = dyn_cast(LHSBase); RHSDeclRef = dyn_cast(RHSBase); if (LHSDeclRef && RHSDeclRef) { if (!LHSDeclRef->getDecl() || !RHSDeclRef->getDecl()) return; if (LHSDeclRef->getDecl()->getCanonicalDecl() != RHSDeclRef->getDecl()->getCanonicalDecl()) return; Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); return; } if (isa(LHSBase) && isa(RHSBase)) Diag(OpLoc, diag::warn_self_move) << LHSExpr->getType() << LHSExpr->getSourceRange() << RHSExpr->getSourceRange(); } //===--- Layout compatibility ----------------------------------------------// namespace { bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2); /// \brief Check if two enumeration types are layout-compatible. bool isLayoutCompatible(ASTContext &C, EnumDecl *ED1, EnumDecl *ED2) { // C++11 [dcl.enum] p8: // Two enumeration types are layout-compatible if they have the same // underlying type. return ED1->isComplete() && ED2->isComplete() && C.hasSameType(ED1->getIntegerType(), ED2->getIntegerType()); } /// \brief Check if two fields are layout-compatible. bool isLayoutCompatible(ASTContext &C, FieldDecl *Field1, FieldDecl *Field2) { if (!isLayoutCompatible(C, Field1->getType(), Field2->getType())) return false; if (Field1->isBitField() != Field2->isBitField()) return false; if (Field1->isBitField()) { // Make sure that the bit-fields are the same length. unsigned Bits1 = Field1->getBitWidthValue(C); unsigned Bits2 = Field2->getBitWidthValue(C); if (Bits1 != Bits2) return false; } return true; } /// \brief Check if two standard-layout structs are layout-compatible. /// (C++11 [class.mem] p17) bool isLayoutCompatibleStruct(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { // If both records are C++ classes, check that base classes match. if (const CXXRecordDecl *D1CXX = dyn_cast(RD1)) { // If one of records is a CXXRecordDecl we are in C++ mode, // thus the other one is a CXXRecordDecl, too. const CXXRecordDecl *D2CXX = cast(RD2); // Check number of base classes. if (D1CXX->getNumBases() != D2CXX->getNumBases()) return false; // Check the base classes. for (CXXRecordDecl::base_class_const_iterator Base1 = D1CXX->bases_begin(), BaseEnd1 = D1CXX->bases_end(), Base2 = D2CXX->bases_begin(); Base1 != BaseEnd1; ++Base1, ++Base2) { if (!isLayoutCompatible(C, Base1->getType(), Base2->getType())) return false; } } else if (const CXXRecordDecl *D2CXX = dyn_cast(RD2)) { // If only RD2 is a C++ class, it should have zero base classes. if (D2CXX->getNumBases() > 0) return false; } // Check the fields. RecordDecl::field_iterator Field2 = RD2->field_begin(), Field2End = RD2->field_end(), Field1 = RD1->field_begin(), Field1End = RD1->field_end(); for ( ; Field1 != Field1End && Field2 != Field2End; ++Field1, ++Field2) { if (!isLayoutCompatible(C, *Field1, *Field2)) return false; } if (Field1 != Field1End || Field2 != Field2End) return false; return true; } /// \brief Check if two standard-layout unions are layout-compatible. /// (C++11 [class.mem] p18) bool isLayoutCompatibleUnion(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { llvm::SmallPtrSet UnmatchedFields; for (auto *Field2 : RD2->fields()) UnmatchedFields.insert(Field2); for (auto *Field1 : RD1->fields()) { llvm::SmallPtrSet::iterator I = UnmatchedFields.begin(), E = UnmatchedFields.end(); for ( ; I != E; ++I) { if (isLayoutCompatible(C, Field1, *I)) { bool Result = UnmatchedFields.erase(*I); (void) Result; assert(Result); break; } } if (I == E) return false; } return UnmatchedFields.empty(); } bool isLayoutCompatible(ASTContext &C, RecordDecl *RD1, RecordDecl *RD2) { if (RD1->isUnion() != RD2->isUnion()) return false; if (RD1->isUnion()) return isLayoutCompatibleUnion(C, RD1, RD2); else return isLayoutCompatibleStruct(C, RD1, RD2); } /// \brief Check if two types are layout-compatible in C++11 sense. bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { if (T1.isNull() || T2.isNull()) return false; // C++11 [basic.types] p11: // If two types T1 and T2 are the same type, then T1 and T2 are // layout-compatible types. if (C.hasSameType(T1, T2)) return true; T1 = T1.getCanonicalType().getUnqualifiedType(); T2 = T2.getCanonicalType().getUnqualifiedType(); const Type::TypeClass TC1 = T1->getTypeClass(); const Type::TypeClass TC2 = T2->getTypeClass(); if (TC1 != TC2) return false; if (TC1 == Type::Enum) { return isLayoutCompatible(C, cast(T1)->getDecl(), cast(T2)->getDecl()); } else if (TC1 == Type::Record) { if (!T1->isStandardLayoutType() || !T2->isStandardLayoutType()) return false; return isLayoutCompatible(C, cast(T1)->getDecl(), cast(T2)->getDecl()); } return false; } } // end anonymous namespace //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// namespace { /// \brief Given a type tag expression find the type tag itself. /// /// \param TypeExpr Type tag expression, as it appears in user's code. /// /// \param VD Declaration of an identifier that appears in a type tag. /// /// \param MagicValue Type tag magic value. bool FindTypeTagExpr(const Expr *TypeExpr, const ASTContext &Ctx, const ValueDecl **VD, uint64_t *MagicValue) { while(true) { if (!TypeExpr) return false; TypeExpr = TypeExpr->IgnoreParenImpCasts()->IgnoreParenCasts(); switch (TypeExpr->getStmtClass()) { case Stmt::UnaryOperatorClass: { const UnaryOperator *UO = cast(TypeExpr); if (UO->getOpcode() == UO_AddrOf || UO->getOpcode() == UO_Deref) { TypeExpr = UO->getSubExpr(); continue; } return false; } case Stmt::DeclRefExprClass: { const DeclRefExpr *DRE = cast(TypeExpr); *VD = DRE->getDecl(); return true; } case Stmt::IntegerLiteralClass: { const IntegerLiteral *IL = cast(TypeExpr); llvm::APInt MagicValueAPInt = IL->getValue(); if (MagicValueAPInt.getActiveBits() <= 64) { *MagicValue = MagicValueAPInt.getZExtValue(); return true; } else return false; } case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { const AbstractConditionalOperator *ACO = cast(TypeExpr); bool Result; if (ACO->getCond()->EvaluateAsBooleanCondition(Result, Ctx)) { if (Result) TypeExpr = ACO->getTrueExpr(); else TypeExpr = ACO->getFalseExpr(); continue; } return false; } case Stmt::BinaryOperatorClass: { const BinaryOperator *BO = cast(TypeExpr); if (BO->getOpcode() == BO_Comma) { TypeExpr = BO->getRHS(); continue; } return false; } default: return false; } } } /// \brief Retrieve the C type corresponding to type tag TypeExpr. /// /// \param TypeExpr Expression that specifies a type tag. /// /// \param MagicValues Registered magic values. /// /// \param FoundWrongKind Set to true if a type tag was found, but of a wrong /// kind. /// /// \param TypeInfo Information about the corresponding C type. /// /// \returns true if the corresponding C type was found. bool GetMatchingCType( const IdentifierInfo *ArgumentKind, const Expr *TypeExpr, const ASTContext &Ctx, const llvm::DenseMap *MagicValues, bool &FoundWrongKind, Sema::TypeTagData &TypeInfo) { FoundWrongKind = false; // Variable declaration that has type_tag_for_datatype attribute. const ValueDecl *VD = nullptr; uint64_t MagicValue; if (!FindTypeTagExpr(TypeExpr, Ctx, &VD, &MagicValue)) return false; if (VD) { if (TypeTagForDatatypeAttr *I = VD->getAttr()) { if (I->getArgumentKind() != ArgumentKind) { FoundWrongKind = true; return false; } TypeInfo.Type = I->getMatchingCType(); TypeInfo.LayoutCompatible = I->getLayoutCompatible(); TypeInfo.MustBeNull = I->getMustBeNull(); return true; } return false; } if (!MagicValues) return false; llvm::DenseMap::const_iterator I = MagicValues->find(std::make_pair(ArgumentKind, MagicValue)); if (I == MagicValues->end()) return false; TypeInfo = I->second; return true; } } // end anonymous namespace void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, bool LayoutCompatible, bool MustBeNull) { if (!TypeTagForDatatypeMagicValues) TypeTagForDatatypeMagicValues.reset( new llvm::DenseMap); TypeTagMagicValue Magic(ArgumentKind, MagicValue); (*TypeTagForDatatypeMagicValues)[Magic] = TypeTagData(Type, LayoutCompatible, MustBeNull); } namespace { bool IsSameCharType(QualType T1, QualType T2) { const BuiltinType *BT1 = T1->getAs(); if (!BT1) return false; const BuiltinType *BT2 = T2->getAs(); if (!BT2) return false; BuiltinType::Kind T1Kind = BT1->getKind(); BuiltinType::Kind T2Kind = BT2->getKind(); return (T1Kind == BuiltinType::SChar && T2Kind == BuiltinType::Char_S) || (T1Kind == BuiltinType::UChar && T2Kind == BuiltinType::Char_U) || (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); } } // end anonymous namespace void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs) { const IdentifierInfo *ArgumentKind = Attr->getArgumentKind(); bool IsPointerAttr = Attr->getIsPointer(); const Expr *TypeTagExpr = ExprArgs[Attr->getTypeTagIdx()]; bool FoundWrongKind; TypeTagData TypeInfo; if (!GetMatchingCType(ArgumentKind, TypeTagExpr, Context, TypeTagForDatatypeMagicValues.get(), FoundWrongKind, TypeInfo)) { if (FoundWrongKind) Diag(TypeTagExpr->getExprLoc(), diag::warn_type_tag_for_datatype_wrong_kind) << TypeTagExpr->getSourceRange(); return; } const Expr *ArgumentExpr = ExprArgs[Attr->getArgumentIdx()]; if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). if (const ImplicitCastExpr *ICE = dyn_cast(ArgumentExpr)) if (ICE->getType()->isVoidPointerType() && ICE->getCastKind() == CK_BitCast) ArgumentExpr = ICE->getSubExpr(); } QualType ArgumentType = ArgumentExpr->getType(); // Passing a `void*' pointer shouldn't trigger a warning. if (IsPointerAttr && ArgumentType->isVoidPointerType()) return; if (TypeInfo.MustBeNull) { // Type tag with matching void type requires a null pointer. if (!ArgumentExpr->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNotNull)) { Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_null_pointer_required) << ArgumentKind->getName() << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } return; } QualType RequiredType = TypeInfo.Type; if (IsPointerAttr) RequiredType = Context.getPointerType(RequiredType); bool mismatch = false; if (!TypeInfo.LayoutCompatible) { mismatch = !Context.hasSameType(ArgumentType, RequiredType); // C++11 [basic.fundamental] p1: // Plain char, signed char, and unsigned char are three distinct types. // // But we treat plain `char' as equivalent to `signed char' or `unsigned // char' depending on the current char signedness mode. if (mismatch) if ((IsPointerAttr && IsSameCharType(ArgumentType->getPointeeType(), RequiredType->getPointeeType())) || (!IsPointerAttr && IsSameCharType(ArgumentType, RequiredType))) mismatch = false; } else if (IsPointerAttr) mismatch = !isLayoutCompatible(Context, ArgumentType->getPointeeType(), RequiredType->getPointeeType()); else mismatch = !isLayoutCompatible(Context, ArgumentType, RequiredType); if (mismatch) Diag(ArgumentExpr->getExprLoc(), diag::warn_type_safety_type_mismatch) << ArgumentType << ArgumentKind << TypeInfo.LayoutCompatible << RequiredType << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 56f4019bfbb6..dfdd36752bf6 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1,7147 +1,7153 @@ //===--- SemaExprCXX.cpp - Semantic Analysis for Expressions --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Implements semantic analysis for C++ expressions. /// //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; using namespace sema; /// \brief Handle the result of the special case name lookup for inheriting /// constructor declarations. 'NS::X::X' and 'NS::X<...>::X' are treated as /// constructor names in member using declarations, even if 'X' is not the /// name of the corresponding type. ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, IdentifierInfo &Name) { NestedNameSpecifier *NNS = SS.getScopeRep(); // Convert the nested-name-specifier into a type. QualType Type; switch (NNS->getKind()) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: Type = QualType(NNS->getAsType(), 0); break; case NestedNameSpecifier::Identifier: // Strip off the last layer of the nested-name-specifier and build a // typename type for it. assert(NNS->getAsIdentifier() == &Name && "not a constructor name"); Type = Context.getDependentNameType(ETK_None, NNS->getPrefix(), NNS->getAsIdentifier()); break; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: llvm_unreachable("Nested name specifier is not a type for inheriting ctor"); } // This reference to the type is located entirely at the location of the // final identifier in the qualified-id. return CreateParsedType(Type, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } ParsedType Sema::getDestructorName(SourceLocation TildeLoc, IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. // FIXME: This area of the standard is very messy, and the current // wording is rather unclear about which scopes we search for the // destructor name; see core issues 399 and 555. Issue 399 in // particular shows where the current description of destructor name // lookup is completely out of line with existing practice, e.g., // this appears to be ill-formed: // // namespace N { // template struct S { // ~S(); // }; // } // // void f(N::S* s) { // s->N::S::~S(); // } // // See also PR6358 and PR6359. // For this reason, we're currently only doing the C++03 version of this // code; the C++0x version has to wait until we get a proper spec. QualType SearchType; DeclContext *LookupCtx = nullptr; bool isDependent = false; bool LookInScope = false; if (SS.isInvalid()) return nullptr; // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and // we know what type we're looking for. if (ObjectTypePtr) SearchType = GetTypeFromParser(ObjectTypePtr); if (SS.isSet()) { NestedNameSpecifier *NNS = SS.getScopeRep(); bool AlreadySearched = false; bool LookAtPrefix = true; // C++11 [basic.lookup.qual]p6: // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, // the type-names are looked up as types in the scope designated by the // nested-name-specifier. Similarly, in a qualified-id of the form: // // nested-name-specifier[opt] class-name :: ~ class-name // // the second class-name is looked up in the same scope as the first. // // Here, we determine whether the code below is permitted to look at the // prefix of the nested-name-specifier. DeclContext *DC = computeDeclContext(SS, EnteringContext); if (DC && DC->isFileContext()) { AlreadySearched = true; LookupCtx = DC; isDependent = false; } else if (DC && isa(DC)) { LookAtPrefix = false; LookInScope = true; } // The second case from the C++03 rules quoted further above. NestedNameSpecifier *Prefix = nullptr; if (AlreadySearched) { // Nothing left to do. } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { CXXScopeSpec PrefixSS; PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); LookupCtx = computeDeclContext(PrefixSS, EnteringContext); isDependent = isDependentScopeSpecifier(PrefixSS); } else if (ObjectTypePtr) { LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); } else { LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = LookupCtx && LookupCtx->isDependentContext(); } } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up // in the context of the entire postfix-expression. If the type T // of the object expression is of a class type C, the type-name is // also looked up in the scope of class C. At least one of the // lookups shall find a name that refers to (possibly // cv-qualified) T. LookupCtx = computeDeclContext(SearchType); isDependent = SearchType->isDependentType(); assert((isDependent || !SearchType->isIncompleteType()) && "Caller should have completed object type"); LookInScope = true; } else { // Perform lookup into the current scope (only). LookInScope = true; } TypeDecl *NonMatchingTypeDecl = nullptr; LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); for (unsigned Step = 0; Step != 2; ++Step) { // Look for the name first in the computed lookup context (if we // have one) and, if that fails to find a match, in the scope (if // we're allowed to look there). Found.clear(); if (Step == 0 && LookupCtx) LookupQualifiedName(Found, LookupCtx); else if (Step == 1 && LookInScope && S) LookupName(Found, S); else continue; // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) return nullptr; if (TypeDecl *Type = Found.getAsSingle()) { QualType T = Context.getTypeDeclType(Type); MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); if (SearchType.isNull() || SearchType->isDependentType() || Context.hasSameUnqualifiedType(T, SearchType)) { // We found our type! return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } if (!SearchType.isNull()) NonMatchingTypeDecl = Type; } // If the name that we found is a class template name, and it is // the same name as the template name in the last part of the // nested-name-specifier (if present) or the object type, then // this is the destructor for that class. // FIXME: This is a workaround until we get real drafting for core // issue 399, for which there isn't even an obvious direction. if (ClassTemplateDecl *Template = Found.getAsSingle()) { QualType MemberOfType; if (SS.isSet()) { if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { // Figure out the type of the context, if it has one. if (CXXRecordDecl *Record = dyn_cast(Ctx)) MemberOfType = Context.getTypeDeclType(Record); } } if (MemberOfType.isNull()) MemberOfType = SearchType; if (MemberOfType.isNull()) continue; // We're referring into a class template specialization. If the // class template we found is the same as the template being // specialized, we found what we are looking for. if (const RecordType *Record = MemberOfType->getAs()) { if (ClassTemplateSpecializationDecl *Spec = dyn_cast(Record->getDecl())) { if (Spec->getSpecializedTemplate()->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); } continue; } // We're referring to an unresolved class template // specialization. Determine whether we class template we found // is the same as the template being specialized or, if we don't // know which template is being specialized, that it at least // has the same name. if (const TemplateSpecializationType *SpecType = MemberOfType->getAs()) { TemplateName SpecName = SpecType->getTemplateName(); // The class template we found is the same template being // specialized. if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } // The class template we found has the same name as the // (dependent) template name being specialized. if (DependentTemplateName *DepTemplate = SpecName.getAsDependentTemplateName()) { if (DepTemplate->isIdentifier() && DepTemplate->getIdentifier() == Template->getIdentifier()) return CreateParsedType( MemberOfType, Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); continue; } } } } if (isDependent) { // We didn't find our type, but that's okay: it's dependent // anyway. // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), SS.getWithLocInContext(Context), II, NameLoc); return ParsedType::make(T); } if (NonMatchingTypeDecl) { QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); Diag(NameLoc, diag::err_destructor_expr_type_mismatch) << T << SearchType; Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) << T; } else if (ObjectTypePtr) Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) << &II; else { SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, diag::err_destructor_class_name); if (S) { const DeclContext *Ctx = S->getEntity(); if (const CXXRecordDecl *Class = dyn_cast_or_null(Ctx)) DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), Class->getNameAsString()); } } return nullptr; } ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) return nullptr; assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "only get destructor types from declspecs"); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); QualType SearchType = GetTypeFromParser(ObjectType); if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) { return ParsedType::make(T); } Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, const UnqualifiedId &Name) { assert(Name.getKind() == UnqualifiedId::IK_LiteralOperatorId); if (!SS.isValid()) return false; switch (SS.getScopeRep()->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: // Per C++11 [over.literal]p2, literal operators can only be declared at // namespace scope. Therefore, this unqualified-id cannot name anything. // Reject it early, because we have no AST representation for this in the // case where the scope is dependent. Diag(Name.getLocStart(), diag::err_literal_operator_id_outside_namespace) << SS.getScopeRep(); return true; case NestedNameSpecifier::Global: case NestedNameSpecifier::Super: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: return false; } llvm_unreachable("unknown nested name specifier kind"); } /// \brief Build a C++ typeid expression with a type operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { // C++ [expr.typeid]p4: // The top-level cv-qualifiers of the lvalue expression or the type-id // that is the operand of typeid are always ignored. // If the type of the type-id is a class type or a reference to a class // type, the class shall be completely-defined. Qualifiers Quals; QualType T = Context.getUnqualifiedArrayType(Operand->getType().getNonReferenceType(), Quals); if (T->getAs() && RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); if (T->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << T); return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), Operand, SourceRange(TypeidLoc, RParenLoc)); } /// \brief Build a C++ typeid expression with an expression operand. ExprResult Sema::BuildCXXTypeId(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { bool WasEvaluated = false; if (E && !E->isTypeDependent()) { if (E->getType()->isPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return ExprError(); E = result.get(); } QualType T = E->getType(); if (const RecordType *RecordT = T->getAs()) { CXXRecordDecl *RecordD = cast(RecordT->getDecl()); // C++ [expr.typeid]p3: // [...] If the type of the expression is a class type, the class // shall be completely-defined. if (RequireCompleteType(TypeidLoc, T, diag::err_incomplete_typeid)) return ExprError(); // C++ [expr.typeid]p3: // When typeid is applied to an expression other than an glvalue of a // polymorphic class type [...] [the] expression is an unevaluated // operand. [...] if (RecordD->isPolymorphic() && E->isGLValue()) { // The subexpression is potentially evaluated; switch the context // and recheck the subexpression. ExprResult Result = TransformToPotentiallyEvaluated(E); if (Result.isInvalid()) return ExprError(); E = Result.get(); // We require a vtable to query the type at run time. MarkVTableUsed(TypeidLoc, RecordD); WasEvaluated = true; } } // C++ [expr.typeid]p4: // [...] If the type of the type-id is a reference to a possibly // cv-qualified type, the result of the typeid expression refers to a // std::type_info object representing the cv-unqualified referenced // type. Qualifiers Quals; QualType UnqualT = Context.getUnqualifiedArrayType(T, Quals); if (!Context.hasSameType(T, UnqualT)) { T = UnqualT; E = ImpCastExprToType(E, UnqualT, CK_NoOp, E->getValueKind()).get(); } } if (E->getType()->isVariablyModifiedType()) return ExprError(Diag(TypeidLoc, diag::err_variably_modified_typeid) << E->getType()); else if (ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, WasEvaluated)) { // The expression operand for typeid is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(E->getExprLoc(), WasEvaluated ? diag::warn_side_effects_typeid : diag::warn_side_effects_unevaluated_context); } return new (Context) CXXTypeidExpr(TypeInfoType.withConst(), E, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXTypeidOfType - Parse typeid( type-id ) or typeid (expression); ExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // Find the std::type_info type. if (!getStdNamespace()) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); if (!CXXTypeInfoDecl) { IdentifierInfo *TypeInfoII = &PP.getIdentifierTable().get("type_info"); LookupResult R(*this, TypeInfoII, SourceLocation(), LookupTagName); LookupQualifiedName(R, getStdNamespace()); CXXTypeInfoDecl = R.getAsSingle(); // Microsoft's typeinfo doesn't have type_info in std but in the global // namespace if _HAS_EXCEPTIONS is defined to 0. See PR13153. if (!CXXTypeInfoDecl && LangOpts.MSVCCompat) { LookupQualifiedName(R, Context.getTranslationUnitDecl()); CXXTypeInfoDecl = R.getAsSingle(); } if (!CXXTypeInfoDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_typeid)); } if (!getLangOpts().RTTI) { return ExprError(Diag(OpLoc, diag::err_no_typeid_with_fno_rtti)); } QualType TypeInfoType = Context.getTypeDeclType(CXXTypeInfoDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXTypeId(TypeInfoType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to /// a single GUID. static void getUuidAttrOfType(Sema &SemaRef, QualType QT, llvm::SmallSetVector &UuidAttrs) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); if (QT->isPointerType() || QT->isReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); const auto *RD = Ty->getAsCXXRecordDecl(); if (!RD) return; if (const auto *Uuid = RD->getMostRecentDecl()->getAttr()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. if (const auto *CTSD = dyn_cast(RD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; if (TA.getKind() == TemplateArgument::Type) getUuidAttrOfType(SemaRef, TA.getAsType(), UuidAttrs); else if (TA.getKind() == TemplateArgument::Declaration) getUuidAttrOfType(SemaRef, TA.getAsDecl()->getType(), UuidAttrs); if (UuidForTA) UuidAttrs.insert(UuidForTA); } } } /// \brief Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { StringRef UuidStr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// \brief Build a Microsoft __uuidof expression with an expression operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { StringRef UuidStr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { UuidStr = "00000000-0000-0000-0000-000000000000"; } else { llvm::SmallSetVector UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); UuidStr = UuidAttrs.back()->getGuid(); } } return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { // If MSVCGuidDecl has not been cached, do the lookup. if (!MSVCGuidDecl) { IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); LookupQualifiedName(R, Context.getTranslationUnitDecl()); MSVCGuidDecl = R.getAsSingle(); if (!MSVCGuidDecl) return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); } QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); if (isType) { // The operand is a type; handle it as such. TypeSourceInfo *TInfo = nullptr; QualType T = GetTypeFromParser(ParsedType::getFromOpaquePtr(TyOrExpr), &TInfo); if (T.isNull()) return ExprError(); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); return BuildCXXUuidof(GuidType, OpLoc, TInfo, RParenLoc); } // The operand is an expression. return BuildCXXUuidof(GuidType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } /// ActOnCXXBoolLiteral - Parse {true,false} literals. ExprResult Sema::ActOnCXXBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw_true || Kind == tok::kw_false) && "Unknown C++ Boolean value!"); return new (Context) CXXBoolLiteralExpr(Kind == tok::kw_true, Context.BoolTy, OpLoc); } /// ActOnCXXNullPtrLiteral - Parse 'nullptr'. ExprResult Sema::ActOnCXXNullPtrLiteral(SourceLocation Loc) { return new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc); } /// ActOnCXXThrow - Parse throw expressions. ExprResult Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { bool IsThrownVarInScope = false; if (Ex) { // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or catch- // clause parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object if (DeclRefExpr *DRE = dyn_cast(Ex->IgnoreParens())) if (VarDecl *Var = dyn_cast(DRE->getDecl())) { if (Var->hasLocalStorage() && !Var->getType().isVolatileQualified()) { for( ; S; S = S->getParent()) { if (S->isDeclScope(Var)) { IsThrownVarInScope = true; break; } if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | Scope::TryScope)) break; } } } } return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); } ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc)) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; if (Ex && !Ex->isTypeDependent()) { QualType ExceptionObjectTy = Context.getExceptionObjectType(Ex->getType()); if (CheckCXXThrowOperand(OpLoc, ExceptionObjectTy, Ex)) return ExprError(); // Initialize the exception result. This implicitly weeds out // abstract types or types with inaccessible copy constructors. // C++0x [class.copymove]p31: // When certain criteria are met, an implementation is allowed to omit the // copy/move construction of a class object [...] // // - in a throw-expression, when the operand is the name of a // non-volatile automatic object (other than a function or // catch-clause // parameter) whose scope does not extend beyond the end of the // innermost enclosing try-block (if there is one), the copy/move // operation from the operand to the exception object (15.1) can be // omitted by constructing the automatic object directly into the // exception object const VarDecl *NRVOVariable = nullptr; if (IsThrownVarInScope) NRVOVariable = getCopyElisionCandidate(QualType(), Ex, false); InitializedEntity Entity = InitializedEntity::InitializeException( OpLoc, ExceptionObjectTy, /*NRVO=*/NRVOVariable != nullptr); ExprResult Res = PerformMoveOrCopyInitialization( Entity, NRVOVariable, QualType(), Ex, IsThrownVarInScope); if (Res.isInvalid()) return ExprError(); Ex = Res.get(); } return new (Context) CXXThrowExpr(Ex, Context.VoidTy, OpLoc, IsThrownVarInScope); } static void collectPublicBases(CXXRecordDecl *RD, llvm::DenseMap &SubobjectsSeen, llvm::SmallPtrSetImpl &VBases, llvm::SetVector &PublicSubobjectsSeen, bool ParentIsPublic) { for (const CXXBaseSpecifier &BS : RD->bases()) { CXXRecordDecl *BaseDecl = BS.getType()->getAsCXXRecordDecl(); bool NewSubobject; // Virtual bases constitute the same subobject. Non-virtual bases are // always distinct subobjects. if (BS.isVirtual()) NewSubobject = VBases.insert(BaseDecl).second; else NewSubobject = true; if (NewSubobject) ++SubobjectsSeen[BaseDecl]; // Only add subobjects which have public access throughout the entire chain. bool PublicPath = ParentIsPublic && BS.getAccessSpecifier() == AS_public; if (PublicPath) PublicSubobjectsSeen.insert(BaseDecl); // Recurse on to each base subobject. collectPublicBases(BaseDecl, SubobjectsSeen, VBases, PublicSubobjectsSeen, PublicPath); } } static void getUnambiguousPublicSubobjects( CXXRecordDecl *RD, llvm::SmallVectorImpl &Objects) { llvm::DenseMap SubobjectsSeen; llvm::SmallSet VBases; llvm::SetVector PublicSubobjectsSeen; SubobjectsSeen[RD] = 1; PublicSubobjectsSeen.insert(RD); collectPublicBases(RD, SubobjectsSeen, VBases, PublicSubobjectsSeen, /*ParentIsPublic=*/true); for (CXXRecordDecl *PublicSubobject : PublicSubobjectsSeen) { // Skip ambiguous objects. if (SubobjectsSeen[PublicSubobject] > 1) continue; Objects.push_back(PublicSubobject); } } /// CheckCXXThrowOperand - Validate the operand of a throw. bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, QualType ExceptionObjectTy, Expr *E) { // If the type of the exception would be an incomplete type or a pointer // to an incomplete type other than (cv) void the program is ill-formed. QualType Ty = ExceptionObjectTy; bool isPointer = false; if (const PointerType* Ptr = Ty->getAs()) { Ty = Ptr->getPointeeType(); isPointer = true; } if (!isPointer || !Ty->isVoidType()) { if (RequireCompleteType(ThrowLoc, Ty, isPointer ? diag::err_throw_incomplete_ptr : diag::err_throw_incomplete, E->getSourceRange())) return true; if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return true; } // If the exception has class type, we need additional handling. CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); if (!RD) return false; // If we are throwing a polymorphic class type or pointer thereof, // exception handling will make use of the vtable. MarkVTableUsed(ThrowLoc, RD); // If a pointer is thrown, the referenced object will not be destroyed. if (isPointer) return false; // If the class has a destructor, we must be able to call it. if (!RD->hasIrrelevantDestructor()) { if (CXXDestructorDecl *Destructor = LookupDestructor(RD)) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_exception) << Ty); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return true; } } // The MSVC ABI creates a list of all types which can catch the exception // object. This list also references the appropriate copy constructor to call // if the object is caught by value and has a non-trivial copy constructor. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { // We are only interested in the public, unambiguous bases contained within // the exception object. Bases which are ambiguous or otherwise // inaccessible are not catchable types. llvm::SmallVector UnambiguousPublicSubobjects; getUnambiguousPublicSubobjects(RD, UnambiguousPublicSubobjects); for (CXXRecordDecl *Subobject : UnambiguousPublicSubobjects) { // Attempt to lookup the copy constructor. Various pieces of machinery // will spring into action, like template instantiation, which means this // cannot be a simple walk of the class's decls. Instead, we must perform // lookup and overload resolution. CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); if (!CD) continue; // Mark the constructor referenced as it is used by this throw expression. MarkFunctionReferenced(E->getExprLoc(), CD); // Skip this copy constructor if it is trivial, we don't need to record it // in the catchable type data. if (CD->isTrivial()) continue; // The copy constructor is non-trivial, create a mapping from this class // type to this constructor. // N.B. The selection of copy constructor is not sensitive to this // particular throw-site. Lookup will be performed at the catch-site to // ensure that the copy constructor is, in fact, accessible (via // friendship or any other means). Context.addCopyConstructorForExceptionObject(Subobject, CD); // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { // Skip any default arguments that we've already instantiated. if (Context.getDefaultArgExprForConstructor(CD, I)) continue; Expr *DefaultArg = BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get(); Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); } } } return false; } static QualType adjustCVQualifiersForCXXThisWithinLambda( ArrayRef FunctionScopes, QualType ThisTy, DeclContext *CurSemaContext, ASTContext &ASTCtx) { QualType ClassType = ThisTy->getPointeeType(); LambdaScopeInfo *CurLSI = nullptr; DeclContext *CurDC = CurSemaContext; // Iterate through the stack of lambdas starting from the innermost lambda to // the outermost lambda, checking if '*this' is ever captured by copy - since // that could change the cv-qualifiers of the '*this' object. // The object referred to by '*this' starts out with the cv-qualifiers of its // member function. We then start with the innermost lambda and iterate // outward checking to see if any lambda performs a by-copy capture of '*this' // - and if so, any nested lambda must respect the 'constness' of that // capturing lamdbda's call operator. // // The issue is that we cannot rely entirely on the FunctionScopeInfo stack // since ScopeInfos are pushed on during parsing and treetransforming. But // since a generic lambda's call operator can be instantiated anywhere (even // end of the TU) we need to be able to examine its enclosing lambdas and so // we use the DeclContext to get a hold of the closure-class and query it for // capture information. The reason we don't just resort to always using the // DeclContext chain is that it is only mature for lambda expressions // enclosing generic lambda's call operators that are being instantiated. for (int I = FunctionScopes.size(); I-- && isa(FunctionScopes[I]); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast(FunctionScopes[I]); if (!CurLSI->isCXXThisCaptured()) continue; auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (CurLSI->CallOperator->isConst()) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } } // We've run out of ScopeInfos but check if CurDC is a lambda (which can // happen during instantiation of generic lambdas) if (isLambdaCallOperator(CurDC)) { assert(CurLSI); assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator)); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); auto IsThisCaptured = [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { IsConst = false; IsByCopy = false; for (auto &&C : Closure->captures()) { if (C.capturesThis()) { if (C.getCaptureKind() == LCK_StarThis) IsByCopy = true; if (Closure->getLambdaCallOperator()->isConst()) IsConst = true; return true; } } return false; }; bool IsByCopyCapture = false; bool IsConstCapture = false; CXXRecordDecl *Closure = cast(CurDC->getParent()); while (Closure && IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) { if (IsByCopyCapture) { ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); if (IsConstCapture) ClassType.addConst(); return ASTCtx.getPointerType(ClassType); } Closure = isLambdaCallOperator(Closure->getParent()) ? cast(Closure->getParent()->getParent()) : nullptr; } } return ASTCtx.getPointerType(ClassType); } QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); QualType ThisTy = CXXThisTypeOverride; if (CXXMethodDecl *method = dyn_cast(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(Context); } if (ThisTy.isNull() && isLambdaCallOperator(CurContext) && !ActiveTemplateInstantiations.empty()) { assert(isa(DC) && "Trying to get 'this' type from static method?"); // This is a lambda call operator that is being instantiated as a default // initializer. DC must point to the enclosing class type, so we can recover // the 'this' type from it. QualType ClassTy = Context.getTypeDeclType(cast(DC)); // There are no cv-qualifiers for 'this' within default initializers, // per [expr.prim.general]p4. ThisTy = Context.getPointerType(ClassTy); } // If we are within a lambda's call operator, the cv-qualifiers of 'this' // might need to be adjusted if the lambda or any of its enclosing lambda's // captures '*this' by copy. if (!ThisTy.isNull() && isLambdaCallOperator(CurContext)) return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy, CurContext, Context); return ThisTy; } Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, bool Enabled) : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) { if (!Enabled || !ContextDecl) return; CXXRecordDecl *Record = nullptr; if (ClassTemplateDecl *Template = dyn_cast(ContextDecl)) Record = Template->getTemplatedDecl(); else Record = cast(ContextDecl); // We care only for CVR qualifiers here, so cut everything else. CXXThisTypeQuals &= Qualifiers::FastMask; S.CXXThisTypeOverride = S.Context.getPointerType( S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); this->Enabled = true; } Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { if (Enabled) { S.CXXThisTypeOverride = OldCXXThisTypeOverride; } } static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, QualType ThisTy, SourceLocation Loc, const bool ByCopy) { QualType AdjustedThisTy = ThisTy; // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). QualType CaptureThisFieldTy = ThisTy; if (ByCopy) { // If we are capturing the object referred to by '*this' by copy, ignore any // cv qualifiers inherited from the type of the member function for the type // of the closure-type's corresponding data member and any use of 'this'. CaptureThisFieldTy = ThisTy->getPointeeType(); CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask); AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy); } FieldDecl *Field = FieldDecl::Create( Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy, Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false, ICIS_NoInit); Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); Expr *This = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/ true); if (ByCopy) { Expr *StarThis = S.CreateBuiltinUnaryOp(Loc, UO_Deref, This).get(); InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture( nullptr, CaptureThisFieldTy, Loc); InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); InitializationSequence Init(S, Entity, InitKind, StarThis); ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis); if (ER.isInvalid()) return nullptr; return ER.get(); } return This; } bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; // Check that we can capture the *enclosing object* (referred to by '*this') // by the capturing-entity/closure (lambda/block/etc) at // MaxFunctionScopesIndex-deep on the FunctionScopes stack. // Note: The *enclosing object* can only be captured by-value by a // closure that is a lambda, using the explicit notation: // [*this] { ... }. // Every other capture of the *enclosing object* results in its by-reference // capture. // For a closure 'L' (at MaxFunctionScopesIndex in the FunctionScopes // stack), we can capture the *enclosing object* only if: // - 'L' has an explicit byref or byval capture of the *enclosing object* // - or, 'L' has an implicit capture. // AND // -- there is no enclosing closure // -- or, there is some enclosing closure 'E' that has already captured the // *enclosing object*, and every intervening closure (if any) between 'E' // and 'L' can implicitly capture the *enclosing object*. // -- or, every enclosing closure can implicitly capture the // *enclosing object* unsigned NumCapturingClosures = 0; for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { if (CapturingScopeInfo *CSI = dyn_cast(FunctionScopes[idx])) { if (CSI->CXXThisCaptureIndex != 0) { // 'this' is already being captured; there isn't anything more to do. break; } LambdaScopeInfo *LSI = dyn_cast(CSI); if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) { // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || (Explicit && idx == MaxFunctionScopesIndex)) { // Regarding (Explicit && idx == MaxFunctionScopesIndex): only the first // iteration through can be an explicit capture, all enclosing closures, // if any, must perform implicit captures. // This closure can capture 'this'; continue looking upwards. NumCapturingClosures++; continue; } // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) Diag(Loc, diag::err_this_capture) << (Explicit && idx == MaxFunctionScopesIndex); return true; } break; } if (!BuildAndDiagnose) return false; // If we got here, then the closure at MaxFunctionScopesIndex on the // FunctionScopes stack, can capture the *enclosing object*, so capture it // (including implicit by-reference captures in any enclosing closures). // In the loop below, respect the ByCopy flag only for the closure requesting // the capture (i.e. first iteration through the loop below). Ignore it for // all enclosing closure's upto NumCapturingClosures (since they must be // implicitly capturing the *enclosing object* by reference (see loop // above)). assert((!ByCopy || dyn_cast(FunctionScopes[MaxFunctionScopesIndex])) && "Only a lambda can capture the enclosing object (referred to by " "*this) by copy"); // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. QualType ThisTy = getCurrentThisType(); for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast(FunctionScopes[idx]); Expr *ThisExpr = nullptr; if (LambdaScopeInfo *LSI = dyn_cast(CSI)) { // For lambda expressions, build a field and an initializing expression, // and capture the *enclosing object* by copy only if this is the first // iteration. ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc, ByCopy && idx == MaxFunctionScopesIndex); } else if (CapturedRegionScopeInfo *RSI = dyn_cast(FunctionScopes[idx])) ThisExpr = captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc, false/*ByCopy*/); bool isNested = NumCapturingClosures > 1; CSI->addThisCapture(isNested, Loc, ThisExpr, ByCopy); } return false; } ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { /// C++ 9.3.2: In the body of a non-static member function, the keyword this /// is a non-lvalue expression whose value is the address of the object for /// which the function is called. QualType ThisTy = getCurrentThisType(); if (ThisTy.isNull()) return Diag(Loc, diag::err_invalid_this_use); CheckCXXThisCapture(Loc); return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/false); } bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { // If we're outside the body of a member function, then we'll have a specified // type for 'this'. if (CXXThisTypeOverride.isNull()) return false; // Determine whether we're looking into a class that's currently being // defined. CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); return Class && Class->isBeingDefined(); } ExprResult Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, SourceLocation LParenLoc, MultiExprArg exprs, SourceLocation RParenLoc) { if (!TypeRep) return ExprError(); TypeSourceInfo *TInfo; QualType Ty = GetTypeFromParser(TypeRep, &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without // checking for embedded typos. if (!Result.isInvalid() && Result.get()->isInstantiationDependent() && !Result.get()->isTypeDependent()) Result = CorrectDelayedTyposInExpr(Result.get()); return Result; } /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. /// Can be interpreted either as function-style casting ("int(x)") /// or class type construction ("ClassType(x,y,z)") /// or creation of a value-initialized type ("int()"). ExprResult Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, SourceLocation LParenLoc, MultiExprArg Exprs, SourceLocation RParenLoc) { QualType Ty = TInfo->getType(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(Exprs)) { return CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, Exprs, RParenLoc); } bool ListInitialization = LParenLoc.isInvalid(); assert((!ListInitialization || (Exprs.size() == 1 && isa(Exprs[0]))) && "List initialization must have initializer list as expression."); SourceRange FullRange = SourceRange(TyBeginLoc, ListInitialization ? Exprs[0]->getSourceRange().getEnd() : RParenLoc); // C++ [expr.type.conv]p1: // If the expression list is a single expression, the type conversion // expression is equivalent (in definedness, and if defined in meaning) to the // corresponding cast expression. if (Exprs.size() == 1 && !ListInitialization) { Expr *Arg = Exprs[0]; return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } // C++14 [expr.type.conv]p2: The expression T(), where T is a // simple-type-specifier or typename-specifier for a non-array complete // object type or the (possibly cv-qualified) void type, creates a prvalue // of the specified type, whose value is that produced by value-initializing // an object of type T. QualType ElemTy = Ty; if (Ty->isArrayType()) { if (!ListInitialization) return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_array_type) << FullRange); ElemTy = Context.getBaseElementType(Ty); } if (!ListInitialization && Ty->isFunctionType()) return ExprError(Diag(TyBeginLoc, diag::err_value_init_for_function_type) << FullRange); if (!Ty->isVoidType() && RequireCompleteType(TyBeginLoc, ElemTy, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); if (RequireNonAbstractType(TyBeginLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization ? InitializationKind::CreateDirectList(TyBeginLoc) : InitializationKind::CreateDirect(TyBeginLoc, LParenLoc, RParenLoc) : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, Exprs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Exprs); if (Result.isInvalid() || !ListInitialization) return Result; Expr *Inner = Result.get(); if (CXXBindTemporaryExpr *BTE = dyn_cast_or_null(Inner)) Inner = BTE->getSubExpr(); if (!isa(Inner)) { // If we created a CXXTemporaryObjectExpr, that node also represents the // functional cast. Otherwise, create an explicit cast to represent // the syntactic form of a functional-style cast that was used here. // // FIXME: Creating a CXXFunctionalCastExpr around a CXXConstructExpr // would give a more consistent AST representation than using a // CXXTemporaryObjectExpr. It's also weird that the functional cast // is sometimes handled by initialization and sometimes not. QualType ResultType = Result.get()->getType(); Result = CXXFunctionalCastExpr::Create( Context, ResultType, Expr::getValueKindForType(TInfo->getType()), TInfo, CK_NoOp, Result.get(), /*Path=*/nullptr, LParenLoc, RParenLoc); } return Result; } /// doesUsualArrayDeleteWantSize - Answers whether the usual /// operator delete[] for the given type has a size_t parameter. static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, QualType allocType) { const RecordType *record = allocType->getBaseElementTypeUnsafe()->getAs(); if (!record) return false; // Try to find an operator delete[] in class scope. DeclarationName deleteName = S.Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete); LookupResult ops(S, deleteName, loc, Sema::LookupOrdinaryName); S.LookupQualifiedName(ops, record->getDecl()); // We're just doing this for information. ops.suppressDiagnostics(); // Very likely: there's no operator delete[]. if (ops.empty()) return false; // If it's ambiguous, it should be illegal to call operator delete[] // on this thing, so it doesn't matter if we allocate extra space or not. if (ops.isAmbiguous()) return false; LookupResult::Filter filter = ops.makeFilter(); while (filter.hasNext()) { NamedDecl *del = filter.next()->getUnderlyingDecl(); // C++0x [basic.stc.dynamic.deallocation]p2: // A template instance is never a usual deallocation function, // regardless of its signature. if (isa(del)) { filter.erase(); continue; } // C++0x [basic.stc.dynamic.deallocation]p2: // If class T does not declare [an operator delete[] with one // parameter] but does declare a member deallocation function // named operator delete[] with exactly two parameters, the // second of which has type std::size_t, then this function // is a usual deallocation function. if (!cast(del)->isUsualDeallocationFunction()) { filter.erase(); continue; } } filter.done(); if (!ops.isSingleResult()) return false; const FunctionDecl *del = cast(ops.getFoundDecl()); return (del->getNumParams() == 2); } /// \brief Parsed a C++ 'new' expression (C++ 5.3.4). /// /// E.g.: /// @code new (memory) int[size][4] @endcode /// or /// @code ::new Foo(23, "hello") @endcode /// /// \param StartLoc The first location of the expression. /// \param UseGlobal True if 'new' was prefixed with '::'. /// \param PlacementLParen Opening paren of the placement arguments. /// \param PlacementArgs Placement new arguments. /// \param PlacementRParen Closing paren of the placement arguments. /// \param TypeIdParens If the type is in parens, the source range. /// \param D The type to be allocated, as well as array dimensions. /// \param Initializer The initializing expression or initializer-list, or null /// if there is none. ExprResult Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, Declarator &D, Expr *Initializer) { bool TypeContainsAuto = D.getDeclSpec().containsPlaceholderType(); Expr *ArraySize = nullptr; // If the specified type is an array, unwrap it and save the expression. if (D.getNumTypeObjects() > 0 && D.getTypeObject(0).Kind == DeclaratorChunk::Array) { DeclaratorChunk &Chunk = D.getTypeObject(0); if (TypeContainsAuto) return ExprError(Diag(Chunk.Loc, diag::err_new_array_of_auto) << D.getSourceRange()); if (Chunk.Arr.hasStatic) return ExprError(Diag(Chunk.Loc, diag::err_static_illegal_in_new) << D.getSourceRange()); if (!Chunk.Arr.NumElts) return ExprError(Diag(Chunk.Loc, diag::err_array_new_needs_size) << D.getSourceRange()); ArraySize = static_cast(Chunk.Arr.NumElts); D.DropFirstTypeObject(); } // Every dimension shall be of constant size. if (ArraySize) { for (unsigned I = 0, N = D.getNumTypeObjects(); I < N; ++I) { if (D.getTypeObject(I).Kind != DeclaratorChunk::Array) break; DeclaratorChunk::ArrayTypeInfo &Array = D.getTypeObject(I).Arr; if (Expr *NumElts = (Expr *)Array.NumElts) { if (!NumElts->isTypeDependent() && !NumElts->isValueDependent()) { if (getLangOpts().CPlusPlus14) { // C++1y [expr.new]p6: Every constant-expression in a noptr-new-declarator // shall be a converted constant expression (5.19) of type std::size_t // and shall evaluate to a strictly positive value. unsigned IntWidth = Context.getTargetInfo().getIntWidth(); assert(IntWidth && "Builtin type of size 0?"); llvm::APSInt Value(IntWidth); Array.NumElts = CheckConvertedConstantExpression(NumElts, Context.getSizeType(), Value, CCEK_NewExpr) .get(); } else { Array.NumElts = VerifyIntegerConstantExpression(NumElts, nullptr, diag::err_new_array_nonconst) .get(); } if (!Array.NumElts) return ExprError(); } } } } TypeSourceInfo *TInfo = GetTypeForDeclarator(D, /*Scope=*/nullptr); QualType AllocType = TInfo->getType(); if (D.isInvalidType()) return ExprError(); SourceRange DirectInitRange; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) DirectInitRange = List->getSourceRange(); return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, PlacementLParen, PlacementArgs, PlacementRParen, TypeIdParens, AllocType, TInfo, ArraySize, DirectInitRange, Initializer, TypeContainsAuto); } static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, Expr *Init) { if (!Init) return true; if (ParenListExpr *PLE = dyn_cast(Init)) return PLE->getNumExprs() == 0; if (isa(Init)) return true; else if (CXXConstructExpr *CCE = dyn_cast(Init)) return !CCE->isListInitialization() && CCE->getConstructor()->isDefaultConstructor(); else if (Style == CXXNewExpr::ListInit) { assert(isa(Init) && "Shouldn't create list CXXConstructExprs for arrays."); return true; } return false; } ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, SourceRange TypeIdParens, QualType AllocType, TypeSourceInfo *AllocTypeInfo, Expr *ArraySize, SourceRange DirectInitRange, Expr *Initializer, bool TypeMayContainAuto) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); SourceLocation StartLoc = Range.getBegin(); CXXNewExpr::InitializationStyle initStyle; if (DirectInitRange.isValid()) { assert(Initializer && "Have parens but no initializer."); initStyle = CXXNewExpr::CallInit; } else if (Initializer && isa(Initializer)) initStyle = CXXNewExpr::ListInit; else { assert((!Initializer || isa(Initializer) || isa(Initializer)) && "Initializer expression that cannot have been implicitly created."); initStyle = CXXNewExpr::NoInit; } Expr **Inits = &Initializer; unsigned NumInits = Initializer ? 1 : 0; if (ParenListExpr *List = dyn_cast_or_null(Initializer)) { assert(initStyle == CXXNewExpr::CallInit && "paren init for non-call init"); Inits = List->getExprs(); NumInits = List->getNumExprs(); } // C++11 [dcl.spec.auto]p6. Deduce the type which 'auto' stands in for. if (TypeMayContainAuto && AllocType->isUndeducedType()) { if (initStyle == CXXNewExpr::NoInit || NumInits == 0) return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg) << AllocType << TypeRange); if (initStyle == CXXNewExpr::ListInit || (NumInits == 1 && isa(Inits[0]))) return ExprError(Diag(Inits[0]->getLocStart(), diag::err_auto_new_list_init) << AllocType << TypeRange); if (NumInits > 1) { Expr *FirstBad = Inits[1]; return ExprError(Diag(FirstBad->getLocStart(), diag::err_auto_new_ctor_multiple_expressions) << AllocType << TypeRange); } Expr *Deduce = Inits[0]; QualType DeducedType; if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) == DAR_Failed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); if (DeducedType.isNull()) return ExprError(); AllocType = DeducedType; } // Per C++0x [expr.new]p5, the type being constructed may be a // typedef of an array type. if (!ArraySize) { if (const ConstantArrayType *Array = Context.getAsConstantArrayType(AllocType)) { ArraySize = IntegerLiteral::Create(Context, Array->getSize(), Context.getSizeType(), TypeRange.getEnd()); AllocType = Array->getElementType(); } } if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange)) return ExprError(); if (initStyle == CXXNewExpr::ListInit && isStdInitializerList(AllocType, nullptr)) { Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(), diag::warn_dangling_std_initializer_list) << /*at end of FE*/0 << Inits[0]->getSourceRange(); } // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && AllocType->isObjCLifetimeType()) { AllocType = Context.getLifetimeQualifiedType(AllocType, AllocType->getObjCARCImplicitLifetime()); } QualType ResultType = Context.getPointerType(AllocType); if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(ArraySize); if (result.isInvalid()) return ExprError(); ArraySize = result.get(); } // C++98 5.3.4p6: "The expression in a direct-new-declarator shall have // integral or enumeration type with a non-negative value." // C++11 [expr.new]p6: The expression [...] shall be of integral or unscoped // enumeration type, or a class type for which a single non-explicit // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { assert(Context.getTargetInfo().getIntWidth() && "Builtin type of size 0?"); ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), AA_Converting); if (!ConvertedSize.isInvalid() && ArraySize->getType()->getAs()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) << ArraySize->getType() << 0 << "'size_t'"; } else { class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: Expr *ArraySize; public: SizeConvertDiagnoser(Expr *ArraySize) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), ArraySize(ArraySize) {} SemaDiagnosticBuilder diagnoseNotInt(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_not_integral) << S.getLangOpts().CPlusPlus11 << T; } SemaDiagnosticBuilder diagnoseIncomplete( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_incomplete_type) << T << ArraySize->getSourceRange(); } SemaDiagnosticBuilder diagnoseExplicitConv( Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_array_size_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous( Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_array_size_ambiguous_conversion) << T; } SemaDiagnosticBuilder noteAmbiguous( Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_array_size_conversion) << ConvTy->isEnumeralType() << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, S.getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_array_size_conversion : diag::ext_array_size_conversion) << T << ConvTy->isEnumeralType() << ConvTy; } } SizeDiagnoser(ArraySize); ConvertedSize = PerformContextualImplicitConversion(StartLoc, ArraySize, SizeDiagnoser); } if (ConvertedSize.isInvalid()) return ExprError(); ArraySize = ConvertedSize.get(); QualType SizeType = ArraySize->getType(); if (!SizeType->isIntegralOrUnscopedEnumerationType()) return ExprError(); // C++98 [expr.new]p7: // The expression in a direct-new-declarator shall have integral type // with a non-negative value. // // Let's see if this is a constant < 0. If so, we reject it out of // hand. Otherwise, if it's not a constant, we must have an unparenthesized // array type. // // Note: such a construct has well-defined semantics in C++11: it throws // std::bad_array_new_length. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. if (ArraySize->isIntegerConstantExpr(Value, Context)) { if (Value < llvm::APSInt( llvm::APInt::getNullValue(Value.getBitWidth()), Value.isUnsigned())) { if (getLangOpts().CPlusPlus11) Diag(ArraySize->getLocStart(), diag::warn_typecheck_negative_array_new_size) << ArraySize->getSourceRange(); else return ExprError(Diag(ArraySize->getLocStart(), diag::err_typecheck_negative_array_size) << ArraySize->getSourceRange()); } else if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { if (getLangOpts().CPlusPlus11) Diag(ArraySize->getLocStart(), diag::warn_array_new_too_large) << Value.toString(10) << ArraySize->getSourceRange(); else return ExprError(Diag(ArraySize->getLocStart(), diag::err_array_too_large) << Value.toString(10) << ArraySize->getSourceRange()); } } } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst) << ArraySize->getSourceRange() << FixItHint::CreateRemoval(TypeIdParens.getBegin()) << FixItHint::CreateRemoval(TypeIdParens.getEnd()); TypeIdParens = SourceRange(); } } // Note that we do *not* convert the argument in any way. It can // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), UseGlobal, AllocType, ArraySize, PlacementArgs, OperatorNew, OperatorDelete)) return ExprError(); // If this is an array allocation, compute whether the usual array // deallocation function for the type has a size_t parameter. bool UsualArrayDeleteWantsSize = false; if (ArraySize && !AllocType->isDependentType()) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); SmallVector AllPlaceArgs; if (OperatorNew) { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; // We've already converted the placement args, just fill in any default // arguments. Skip the first parameter because we don't have a corresponding // argument. if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1, PlacementArgs, AllPlaceArgs, CallType)) return ExprError(); if (!AllPlaceArgs.empty()) PlacementArgs = AllPlaceArgs; // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); // FIXME: Missing call to CheckFunctionCall or equivalent } // Warn if the type is over-aligned and is being allocated by global operator // new. if (PlacementArgs.empty() && OperatorNew && (OperatorNew->isImplicit() || (OperatorNew->getLocStart().isValid() && getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){ unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign(); if (Align > SuitableAlign) Diag(StartLoc, diag::warn_overaligned_type) << AllocType << unsigned(Align / Context.getCharWidth()) << unsigned(SuitableAlign / Context.getCharWidth()); } } QualType InitType = AllocType; // Array 'new' can't have any initializers except empty parentheses. // Initializer lists are also allowed, in C++11. Rely on the parser for the // dialect distinction. if (ResultType->isArrayType() || ArraySize) { if (!isLegalArrayNewInitializer(initStyle, Initializer)) { SourceRange InitRange(Inits[0]->getLocStart(), Inits[NumInits - 1]->getLocEnd()); Diag(StartLoc, diag::err_new_array_init_args) << InitRange; return ExprError(); } if (InitListExpr *ILE = dyn_cast_or_null(Initializer)) { // We do the initialization typechecking against the array type // corresponding to the number of initializers + 1 (to also check // default-initialization). unsigned NumElements = ILE->getNumInits() + 1; InitType = Context.getConstantArrayType(AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements), ArrayType::Normal, 0); } } // If we can perform the initialization, and we've not already done so, // do it now. if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments( llvm::makeArrayRef(Inits, NumInits))) { // C++11 [expr.new]p15: // A new-expression that creates an object of type T initializes that // object as follows: InitializationKind Kind // - If the new-initializer is omitted, the object is default- // initialized (8.5); if no initialization is performed, // the object has indeterminate value = initStyle == CXXNewExpr::NoInit ? InitializationKind::CreateDefault(TypeRange.getBegin()) // - Otherwise, the new-initializer is interpreted according to the // initialization rules of 8.5 for direct-initialization. : initStyle == CXXNewExpr::ListInit ? InitializationKind::CreateDirectList(TypeRange.getBegin()) : InitializationKind::CreateDirect(TypeRange.getBegin(), DirectInitRange.getBegin(), DirectInitRange.getEnd()); InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) return ExprError(); // FullInit is our initializer; strip off CXXBindTemporaryExprs, because // we don't want the initialized object to be destructed. if (CXXBindTemporaryExpr *Binder = dyn_cast_or_null(FullInit.get())) FullInit = Binder->getSubExpr(); Initializer = FullInit.get(); } // Mark the new and delete operators as referenced. if (OperatorNew) { if (DiagnoseUseOfDecl(OperatorNew, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorNew); } if (OperatorDelete) { if (DiagnoseUseOfDecl(OperatorDelete, StartLoc)) return ExprError(); MarkFunctionReferenced(StartLoc, OperatorDelete); } // C++0x [expr.new]p17: // If the new expression creates an array of objects of class type, // access and ambiguity control are done for the destructor. QualType BaseAllocType = Context.getBaseElementType(AllocType); if (ArraySize && !BaseAllocType->isDependentType()) { if (const RecordType *BaseRecordType = BaseAllocType->getAs()) { if (CXXDestructorDecl *dtor = LookupDestructor( cast(BaseRecordType->getDecl()))) { MarkFunctionReferenced(StartLoc, dtor); CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); if (DiagnoseUseOfDecl(dtor, StartLoc)) return ExprError(); } } } return new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange); } /// \brief Checks that a type is suitable as the allocated type /// in a new-expression. bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, SourceRange R) { // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an // abstract class type or array thereof. if (AllocType->isFunctionType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 0 << R; else if (AllocType->isReferenceType()) return Diag(Loc, diag::err_bad_new_type) << AllocType << 1 << R; else if (!AllocType->isDependentType() && RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) return true; else if (AllocType->isVariablyModifiedType()) return Diag(Loc, diag::err_variably_modified_new_type) << AllocType; else if (unsigned AddressSpace = AllocType.getAddressSpace()) return Diag(Loc, diag::err_address_space_qualified_new) << AllocType.getUnqualifiedType() << AddressSpace; else if (getLangOpts().ObjCAutoRefCount) { if (const ArrayType *AT = Context.getAsArrayType(AllocType)) { QualType BaseAllocType = Context.getBaseElementType(AT); if (BaseAllocType.getObjCLifetime() == Qualifiers::OCL_None && BaseAllocType->isObjCLifetimeType()) return Diag(Loc, diag::err_arc_new_array_without_ownership) << BaseAllocType; } } return false; } /// \brief Determine whether the given function is a non-placement /// deallocation function. static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { if (FD->isInvalidDecl()) return false; if (CXXMethodDecl *Method = dyn_cast(FD)) return Method->isUsualDeallocationFunction(); if (FD->getOverloadedOperator() != OO_Delete && FD->getOverloadedOperator() != OO_Array_Delete) return false; if (FD->getNumParams() == 1) return true; return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 && S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(), S.Context.getSizeType()); } /// FindAllocationFunctions - Finds the overloads of operator new and delete /// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool UseGlobal, QualType AllocType, bool IsArray, MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete) { // --- Choosing an allocation function --- // C++ 5.3.4p8 - 14 & 18 // 1) If UseGlobal is true, only look in the global scope. Else, also look // in the scope of the allocated class. // 2) If an array size is given, look for operator new[], else look for // operator new. // 3) The first argument is always size_t. Append the arguments from the // placement form. SmallVector AllocArgs(1 + PlaceArgs.size()); // We don't care about the actual value of this argument. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? IntegerLiteral Size(Context, llvm::APInt::getNullValue( Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); AllocArgs[0] = &Size; std::copy(PlaceArgs.begin(), PlaceArgs.end(), AllocArgs.begin() + 1); // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation // function's name is operator new and the deallocation function's // name is operator delete. If the allocated type is an array // type, the allocation function's name is operator new[] and the // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_New : OO_New); DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( IsArray ? OO_Array_Delete : OO_Delete); QualType AllocElemType = Context.getBaseElementType(AllocType); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *Record = cast(AllocElemType->getAs()->getDecl()); if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, Record, /*AllowMissing=*/true, OperatorNew)) return true; } if (!OperatorNew) { // Didn't find a member overload. Look for a global one. DeclareGlobalNewDelete(); DeclContext *TUDecl = Context.getTranslationUnitDecl(); bool FallbackEnabled = IsArray && Context.getLangOpts().MSVCCompat; if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, /*AllowMissing=*/FallbackEnabled, OperatorNew, /*Diagnose=*/!FallbackEnabled)) { if (!FallbackEnabled) return true; // MSVC will fall back on trying to find a matching global operator new // if operator new[] cannot be found. Also, MSVC will leak by not // generating a call to operator delete or operator delete[], but we // will not replicate that bug. NewName = Context.DeclarationNames.getCXXOperatorName(OO_New); DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, /*AllowMissing=*/false, OperatorNew)) return true; } } // We don't need an operator delete if we're running under // -fno-exceptions. if (!getLangOpts().Exceptions) { OperatorDelete = nullptr; return false; } // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the // deallocation function's name is looked up in the global // scope. Otherwise, if the allocated type is a class type T or an // array thereof, the deallocation function's name is looked up in // the scope of T. If this lookup fails to find the name, or if // the allocated type is not a class type or array thereof, the // deallocation function's name is looked up in the global scope. LookupResult FoundDelete(*this, DeleteName, StartLoc, LookupOrdinaryName); if (AllocElemType->isRecordType() && !UseGlobal) { CXXRecordDecl *RD = cast(AllocElemType->getAs()->getDecl()); LookupQualifiedName(FoundDelete, RD); } if (FoundDelete.isAmbiguous()) return true; // FIXME: clean up expressions? if (FoundDelete.empty()) { DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); } FoundDelete.suppressDiagnostics(); SmallVector, 2> Matches; // Whether we're looking for a placement operator delete is dictated // by whether we selected a placement operator new, not by whether // we had explicit placement arguments. This matters for things like // struct A { void *operator new(size_t, int = 0); ... }; // A *a = new A() bool isPlacementNew = (!PlaceArgs.empty() || OperatorNew->param_size() != 1); if (isPlacementNew) { // C++ [expr.new]p20: // A declaration of a placement deallocation function matches the // declaration of a placement allocation function if it has the // same number of parameters and, after parameter transformations // (8.3.5), all parameter types except the first are // identical. [...] // // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. // // FIXME: this comparison should ignore CC and the like. QualType ExpectedFunctionType; { const FunctionProtoType *Proto = OperatorNew->getType()->getAs(); SmallVector ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); for (unsigned I = 1, N = Proto->getNumParams(); I < N; ++I) ArgTypes.push_back(Proto->getParamType(I)); FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = Proto->isVariadic(); ExpectedFunctionType = Context.getFunctionType(Context.VoidTy, ArgTypes, EPI); } for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; if (FunctionTemplateDecl *FnTmpl = dyn_cast((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn, Info)) continue; } else Fn = cast((*D)->getUnderlyingDecl()); if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } } else { // C++ [expr.new]p20: // [...] Any non-placement deallocation function matches a // non-placement allocation function. [...] for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast((*D)->getUnderlyingDecl())) if (isNonPlacementDeallocationFunction(*this, Fn)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } // C++1y [expr.new]p22: // For a non-placement allocation function, the normal deallocation // function lookup is used // C++1y [expr.delete]p?: // If [...] deallocation function lookup finds both a usual deallocation // function with only a pointer parameter and a usual deallocation // function with both a pointer parameter and a size parameter, then the // selected deallocation function shall be the one with two parameters. // Otherwise, the selected deallocation function shall be the function // with one parameter. if (getLangOpts().SizedDeallocation && Matches.size() == 2) { if (Matches[0].second->getNumParams() == 1) Matches.erase(Matches.begin()); else Matches.erase(Matches.begin() + 1); assert(Matches[0].second->getNumParams() == 2 && "found an unexpected usual deallocation function"); } } // C++ [expr.new]p20: // [...] If the lookup finds a single matching deallocation // function, that function will be called; otherwise, no // deallocation function will be called. if (Matches.size() == 1) { OperatorDelete = Matches[0].second; // C++0x [expr.new]p20: // If the lookup finds the two-parameter form of a usual // deallocation function (3.7.4.2) and that function, considered // as a placement deallocation function, would have been // selected as a match for the allocation function, the program // is ill-formed. if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 && isNonPlacementDeallocationFunction(*this, OperatorDelete)) { Diag(StartLoc, diag::err_placement_new_non_placement_delete) << SourceRange(PlaceArgs.front()->getLocStart(), PlaceArgs.back()->getLocEnd()); if (!OperatorDelete->isImplicit()) Diag(OperatorDelete->getLocation(), diag::note_previous_decl) << DeleteName; } else { CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), Matches[0].first); } } return false; } /// \brief Find an fitting overload for the allocation function /// in the specified scope. /// /// \param StartLoc The location of the 'new' token. /// \param Range The range of the placement arguments. /// \param Name The name of the function ('operator new' or 'operator new[]'). /// \param Args The placement arguments specified. /// \param Ctx The scope in which we should search; either a class scope or the /// translation unit. /// \param AllowMissing If \c true, report an error if we can't find any /// allocation functions. Otherwise, succeed but don't fill in \p /// Operator. /// \param Operator Filled in with the found allocation function. Unchanged if /// no allocation function was found. /// \param Diagnose If \c true, issue errors if the allocation function is not /// usable. bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, DeclarationName Name, MultiExprArg Args, DeclContext *Ctx, bool AllowMissing, FunctionDecl *&Operator, bool Diagnose) { LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(R, Ctx); if (R.empty()) { if (AllowMissing || !Diagnose) return false; return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; } if (R.isAmbiguous()) return true; R.suppressDiagnostics(); OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal); for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Even member operator new/delete are implicitly treated as // static, so don't use AddMemberCandidate. NamedDecl *D = (*Alloc)->getUnderlyingDecl(); if (FunctionTemplateDecl *FnTemplate = dyn_cast(D)) { AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), /*ExplicitTemplateArgs=*/nullptr, Args, Candidates, /*SuppressUserConversions=*/false); continue; } FunctionDecl *Fn = cast(D); AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, /*SuppressUserConversions=*/false); } // Do the resolution. OverloadCandidateSet::iterator Best; switch (Candidates.BestViableFunction(*this, StartLoc, Best)) { case OR_Success: { // Got one! FunctionDecl *FnDecl = Best->Function; if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), Best->FoundDecl, Diagnose) == AR_inaccessible) return true; Operator = FnDecl; return false; } case OR_No_Viable_Function: if (Diagnose) { Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) << Name << Range; Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); } return true; case OR_Ambiguous: if (Diagnose) { Diag(StartLoc, diag::err_ovl_ambiguous_call) << Name << Range; Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args); } return true; case OR_Deleted: { if (Diagnose) { Diag(StartLoc, diag::err_ovl_deleted_call) << Best->Function->isDeleted() << Name << getDeletedOrUnavailableSuffix(Best->Function) << Range; Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); } return true; } } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code /// // C++03: /// void* operator new(std::size_t) throw(std::bad_alloc); /// void* operator new[](std::size_t) throw(std::bad_alloc); /// void operator delete(void *) throw(); /// void operator delete[](void *) throw(); /// // C++11: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// // C++1y: /// void* operator new(std::size_t); /// void* operator new[](std::size_t); /// void operator delete(void *) noexcept; /// void operator delete[](void *) noexcept; /// void operator delete(void *, std::size_t) noexcept; /// void operator delete[](void *, std::size_t) noexcept; /// @endcode /// Note that the placement and nothrow forms of new are *not* implicitly /// declared. Their use requires including \. void Sema::DeclareGlobalNewDelete() { if (GlobalNewDeleteDeclared) return; // C++ [basic.std.dynamic]p2: // [...] The following allocation and deallocation functions (18.4) are // implicitly declared in global scope in each translation unit of a // program // // C++03: // void* operator new(std::size_t) throw(std::bad_alloc); // void* operator new[](std::size_t) throw(std::bad_alloc); // void operator delete(void*) throw(); // void operator delete[](void*) throw(); // C++11: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // C++1y: // void* operator new(std::size_t); // void* operator new[](std::size_t); // void operator delete(void*) noexcept; // void operator delete[](void*) noexcept; // void operator delete(void*, std::size_t) noexcept; // void operator delete[](void*, std::size_t) noexcept; // // These implicit declarations introduce only the function names operator // new, operator new[], operator delete, operator delete[]. // // Here, we need to refer to std::bad_alloc, so we will implicitly declare // "std" or "bad_alloc" as necessary to form the exception specification. // However, we do not make these implicit declarations visible to name // lookup. if (!StdBadAlloc && !getLangOpts().CPlusPlus11) { // The "std::bad_alloc" class has not yet been declared, so build it // implicitly. StdBadAlloc = CXXRecordDecl::Create(Context, TTK_Class, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), &PP.getIdentifierTable().get("bad_alloc"), nullptr); getStdBadAlloc()->setImplicit(true); } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_New), VoidPtr, SizeT, QualType()); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Array_New), VoidPtr, SizeT, QualType()); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Delete), Context.VoidTy, VoidPtr); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), Context.VoidTy, VoidPtr); if (getLangOpts().SizedDeallocation) { DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Delete), Context.VoidTy, VoidPtr, Context.getSizeType()); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), Context.VoidTy, VoidPtr, Context.getSizeType()); } } /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, QualType Param1, QualType Param2) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); unsigned NumParams = Param2.isNull() ? 1 : 2; // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); for (DeclContext::lookup_iterator Alloc = R.begin(), AllocEnd = R.end(); Alloc != AllocEnd; ++Alloc) { // Only look at non-template functions, as it is the predefined, // non-templated allocation function we are trying to declare here. if (FunctionDecl *Func = dyn_cast(*Alloc)) { if (Func->getNumParams() == NumParams) { QualType InitialParam1Type = Context.getCanonicalType(Func->getParamDecl(0) ->getType().getUnqualifiedType()); QualType InitialParam2Type = NumParams == 2 ? Context.getCanonicalType(Func->getParamDecl(1) ->getType().getUnqualifiedType()) : QualType(); // FIXME: Do we need to check for default arguments here? if (InitialParam1Type == Param1 && (NumParams == 1 || InitialParam2Type == Param2)) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. Func->setHidden(false); return; } } } } FunctionProtoType::ExtProtoInfo EPI; QualType BadAllocType; bool HasBadAllocExceptionSpec = (Name.getCXXOverloadedOperator() == OO_New || Name.getCXXOverloadedOperator() == OO_Array_New); if (HasBadAllocExceptionSpec) { if (!getLangOpts().CPlusPlus11) { BadAllocType = Context.getTypeDeclType(getStdBadAlloc()); assert(StdBadAlloc && "Must have std::bad_alloc declared"); EPI.ExceptionSpec.Type = EST_Dynamic; EPI.ExceptionSpec.Exceptions = llvm::makeArrayRef(BadAllocType); } } else { EPI.ExceptionSpec = getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } QualType Params[] = { Param1, Param2 }; QualType FnType = Context.getFunctionType( Return, llvm::makeArrayRef(Params, NumParams), EPI); FunctionDecl *Alloc = FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, FnType, /*TInfo=*/nullptr, SC_None, false, true); Alloc->setImplicit(); // Implicit sized deallocation functions always have default visibility. Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, VisibilityAttr::Default)); ParmVarDecl *ParamDecls[2]; for (unsigned I = 0; I != NumParams; ++I) { ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), SourceLocation(), nullptr, Params[I], /*TInfo=*/nullptr, SC_None, nullptr); ParamDecls[I]->setImplicit(); } Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams)); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); } FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, DeclarationName Name) { DeclareGlobalNewDelete(); LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); // C++ [expr.new]p20: // [...] Any non-placement deallocation function matches a // non-placement allocation function. [...] llvm::SmallVector Matches; for (LookupResult::iterator D = FoundDelete.begin(), DEnd = FoundDelete.end(); D != DEnd; ++D) { if (FunctionDecl *Fn = dyn_cast(*D)) if (isNonPlacementDeallocationFunction(*this, Fn)) Matches.push_back(Fn); } // C++1y [expr.delete]p?: // If the type is complete and deallocation function lookup finds both a // usual deallocation function with only a pointer parameter and a usual // deallocation function with both a pointer parameter and a size // parameter, then the selected deallocation function shall be the one // with two parameters. Otherwise, the selected deallocation function // shall be the function with one parameter. if (getLangOpts().SizedDeallocation && Matches.size() == 2) { unsigned NumArgs = CanProvideSize ? 2 : 1; if (Matches[0]->getNumParams() != NumArgs) Matches.erase(Matches.begin()); else Matches.erase(Matches.begin() + 1); assert(Matches[0]->getNumParams() == NumArgs && "found an unexpected usual deallocation function"); } if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast(CurContext), Matches); assert(Matches.size() == 1 && "unexpectedly have multiple usual deallocation functions"); return Matches.front(); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, FunctionDecl* &Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); if (Found.isAmbiguous()) return true; Found.suppressDiagnostics(); SmallVector Matches; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) { NamedDecl *ND = (*F)->getUnderlyingDecl(); // Ignore template operator delete members from the check for a usual // deallocation function. if (isa(ND)) continue; if (cast(ND)->isUsualDeallocationFunction()) Matches.push_back(F.getPair()); } if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast(CurContext), Matches); // There's exactly one suitable operator; pick it. if (Matches.size() == 1) { Operator = cast(Matches[0]->getUnderlyingDecl()); if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); NoteDeletedFunction(Operator); } return true; } if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), Matches[0], Diagnose) == AR_inaccessible) return true; return false; // We found multiple suitable operators; complain about the ambiguity. } else if (!Matches.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; for (SmallVectorImpl::iterator F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; } // We did find operator delete/operator delete[] declarations, but // none of them were suitable. if (!Found.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); F != FEnd; ++F) Diag((*F)->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; } Operator = nullptr; return false; } namespace { /// \brief Checks whether delete-expression, and new-expression used for /// initializing deletee have the same array form. class MismatchingNewDeleteDetector { public: enum MismatchResult { /// Indicates that there is no mismatch or a mismatch cannot be proven. NoMismatch, /// Indicates that variable is initialized with mismatching form of \a new. VarInitMismatches, /// Indicates that member is initialized with mismatching form of \a new. MemberInitMismatches, /// Indicates that 1 or more constructors' definitions could not been /// analyzed, and they will be checked again at the end of translation unit. AnalyzeLater }; /// \param EndOfTU True, if this is the final analysis at the end of /// translation unit. False, if this is the initial analysis at the point /// delete-expression was encountered. explicit MismatchingNewDeleteDetector(bool EndOfTU) : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} /// \brief Checks whether pointee of a delete-expression is initialized with /// matching form of new-expression. /// /// If return value is \c VarInitMismatches or \c MemberInitMismatches at the /// point where delete-expression is encountered, then a warning will be /// issued immediately. If return value is \c AnalyzeLater at the point where /// delete-expression is seen, then member will be analyzed at the end of /// translation unit. \c AnalyzeLater is returned iff at least one constructor /// couldn't be analyzed. If at least one constructor initializes the member /// with matching type of new, the return value is \c NoMismatch. MismatchResult analyzeDeleteExpr(const CXXDeleteExpr *DE); /// \brief Analyzes a class member. /// \param Field Class member to analyze. /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); /// List of mismatching new-expressions used for initialization of the pointee llvm::SmallVector NewExprs; /// Indicates whether delete-expression was in array form. bool IsArrayForm; FieldDecl *Field; private: const bool EndOfTU; /// \brief Indicates that there is at least one constructor without body. bool HasUndefinedConstructors; /// \brief Returns \c CXXNewExpr from given initialization expression. /// \param E Expression used for initializing pointee in delete-expression. /// E can be a single-element \c InitListExpr consisting of new-expression. const CXXNewExpr *getNewExprFromInitListOrExpr(const Expr *E); /// \brief Returns whether member is initialized with mismatching form of /// \c new either by the member initializer or in-class initialization. /// /// If bodies of all constructors are not visible at the end of translation /// unit or at least one constructor initializes member with the matching /// form of \c new, mismatch cannot be proven, and this function will return /// \c NoMismatch. MismatchResult analyzeMemberExpr(const MemberExpr *ME); /// \brief Returns whether variable is initialized with mismatching form of /// \c new. /// /// If variable is initialized with matching form of \c new or variable is not /// initialized with a \c new expression, this function will return true. /// If variable is initialized with mismatching form of \c new, returns false. /// \param D Variable to analyze. bool hasMatchingVarInit(const DeclRefExpr *D); /// \brief Checks whether the constructor initializes pointee with mismatching /// form of \c new. /// /// Returns true, if member is initialized with matching form of \c new in /// member initializer list. Returns false, if member is initialized with the /// matching form of \c new in this constructor's initializer or given /// constructor isn't defined at the point where delete-expression is seen, or /// member isn't initialized by the constructor. bool hasMatchingNewInCtor(const CXXConstructorDecl *CD); /// \brief Checks whether member is initialized with matching form of /// \c new in member initializer list. bool hasMatchingNewInCtorInit(const CXXCtorInitializer *CI); /// Checks whether member is initialized with mismatching form of \c new by /// in-class initializer. MismatchResult analyzeInClassInitializer(); }; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeDeleteExpr(const CXXDeleteExpr *DE) { NewExprs.clear(); assert(DE && "Expected delete-expression"); IsArrayForm = DE->isArrayForm(); const Expr *E = DE->getArgument()->IgnoreParenImpCasts(); if (const MemberExpr *ME = dyn_cast(E)) { return analyzeMemberExpr(ME); } else if (const DeclRefExpr *D = dyn_cast(E)) { if (!hasMatchingVarInit(D)) return VarInitMismatches; } return NoMismatch; } const CXXNewExpr * MismatchingNewDeleteDetector::getNewExprFromInitListOrExpr(const Expr *E) { assert(E != nullptr && "Expected a valid initializer expression"); E = E->IgnoreParenImpCasts(); if (const InitListExpr *ILE = dyn_cast(E)) { if (ILE->getNumInits() == 1) E = dyn_cast(ILE->getInit(0)->IgnoreParenImpCasts()); } return dyn_cast_or_null(E); } bool MismatchingNewDeleteDetector::hasMatchingNewInCtorInit( const CXXCtorInitializer *CI) { const CXXNewExpr *NE = nullptr; if (Field == CI->getMember() && (NE = getNewExprFromInitListOrExpr(CI->getInit()))) { if (NE->isArray() == IsArrayForm) return true; else NewExprs.push_back(NE); } return false; } bool MismatchingNewDeleteDetector::hasMatchingNewInCtor( const CXXConstructorDecl *CD) { if (CD->isImplicit()) return false; const FunctionDecl *Definition = CD; if (!CD->isThisDeclarationADefinition() && !CD->isDefined(Definition)) { HasUndefinedConstructors = true; return EndOfTU; } for (const auto *CI : cast(Definition)->inits()) { if (hasMatchingNewInCtorInit(CI)) return true; } return false; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeInClassInitializer() { assert(Field != nullptr && "This should be called only for members"); const Expr *InitExpr = Field->getInClassInitializer(); if (!InitExpr) return EndOfTU ? NoMismatch : AnalyzeLater; if (const CXXNewExpr *NE = getNewExprFromInitListOrExpr(InitExpr)) { if (NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); return MemberInitMismatches; } } return NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeField(FieldDecl *Field, bool DeleteWasArrayForm) { assert(Field != nullptr && "Analysis requires a valid class member."); this->Field = Field; IsArrayForm = DeleteWasArrayForm; const CXXRecordDecl *RD = cast(Field->getParent()); for (const auto *CD : RD->ctors()) { if (hasMatchingNewInCtor(CD)) return NoMismatch; } if (HasUndefinedConstructors) return EndOfTU ? NoMismatch : AnalyzeLater; if (!NewExprs.empty()) return MemberInitMismatches; return Field->hasInClassInitializer() ? analyzeInClassInitializer() : NoMismatch; } MismatchingNewDeleteDetector::MismatchResult MismatchingNewDeleteDetector::analyzeMemberExpr(const MemberExpr *ME) { assert(ME != nullptr && "Expected a member expression"); if (FieldDecl *F = dyn_cast(ME->getMemberDecl())) return analyzeField(F, IsArrayForm); return NoMismatch; } bool MismatchingNewDeleteDetector::hasMatchingVarInit(const DeclRefExpr *D) { const CXXNewExpr *NE = nullptr; if (const VarDecl *VD = dyn_cast(D->getDecl())) { if (VD->hasInit() && (NE = getNewExprFromInitListOrExpr(VD->getInit())) && NE->isArray() != IsArrayForm) { NewExprs.push_back(NE); } } return NewExprs.empty(); } static void DiagnoseMismatchedNewDelete(Sema &SemaRef, SourceLocation DeleteLoc, const MismatchingNewDeleteDetector &Detector) { SourceLocation EndOfDelete = SemaRef.getLocForEndOfToken(DeleteLoc); FixItHint H; if (!Detector.IsArrayForm) H = FixItHint::CreateInsertion(EndOfDelete, "[]"); else { SourceLocation RSquare = Lexer::findLocationAfterToken( DeleteLoc, tok::l_square, SemaRef.getSourceManager(), SemaRef.getLangOpts(), true); if (RSquare.isValid()) H = FixItHint::CreateRemoval(SourceRange(EndOfDelete, RSquare)); } SemaRef.Diag(DeleteLoc, diag::warn_mismatched_delete_new) << Detector.IsArrayForm << H; for (const auto *NE : Detector.NewExprs) SemaRef.Diag(NE->getExprLoc(), diag::note_allocated_here) << Detector.IsArrayForm; } void Sema::AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE) { if (Diags.isIgnored(diag::warn_mismatched_delete_new, SourceLocation())) return; MismatchingNewDeleteDetector Detector(/*EndOfTU=*/false); switch (Detector.analyzeDeleteExpr(DE)) { case MismatchingNewDeleteDetector::VarInitMismatches: case MismatchingNewDeleteDetector::MemberInitMismatches: { DiagnoseMismatchedNewDelete(*this, DE->getLocStart(), Detector); break; } case MismatchingNewDeleteDetector::AnalyzeLater: { DeleteExprs[Detector.Field].push_back( std::make_pair(DE->getLocStart(), DE->isArrayForm())); break; } case MismatchingNewDeleteDetector::NoMismatch: break; } } void Sema::AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, bool DeleteWasArrayForm) { MismatchingNewDeleteDetector Detector(/*EndOfTU=*/true); switch (Detector.analyzeField(Field, DeleteWasArrayForm)) { case MismatchingNewDeleteDetector::VarInitMismatches: llvm_unreachable("This analysis should have been done for class members."); case MismatchingNewDeleteDetector::AnalyzeLater: llvm_unreachable("Analysis cannot be postponed any point beyond end of " "translation unit."); case MismatchingNewDeleteDetector::MemberInitMismatches: DiagnoseMismatchedNewDelete(*this, DeleteLoc, Detector); break; case MismatchingNewDeleteDetector::NoMismatch: break; } } /// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in: /// @code ::delete ptr; @endcode /// or /// @code delete [] ptr; @endcode ExprResult Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, bool ArrayForm, Expr *ExE) { // C++ [expr.delete]p1: // The operand shall have a pointer type, or a class type having a single // non-explicit conversion function to a pointer type. The result has type // void. // // DR599 amends "pointer type" to "pointer to object type" in both cases. ExprResult Ex = ExE; FunctionDecl *OperatorDelete = nullptr; bool ArrayFormAsWritten = ArrayForm; bool UsualArrayDeleteWantsSize = false; if (!Ex.get()->isTypeDependent()) { // Perform lvalue-to-rvalue cast, if needed. Ex = DefaultLvalueConversion(Ex.get()); if (Ex.isInvalid()) return ExprError(); QualType Type = Ex.get()->getType(); class DeleteConverter : public ContextualImplicitConverter { public: DeleteConverter() : ContextualImplicitConverter(false, true) {} bool match(QualType ConvType) override { // FIXME: If we have an operator T* and an operator void*, we must pick // the operator T*. if (const PointerType *ConvPtrType = ConvType->getAs()) if (ConvPtrType->getPointeeType()->isIncompleteOrObjectType()) return true; return false; } SemaDiagnosticBuilder diagnoseNoMatch(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_operand) << T; } SemaDiagnosticBuilder diagnoseIncomplete(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_delete_incomplete_class_type) << T; } SemaDiagnosticBuilder diagnoseExplicitConv(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { return S.Diag(Loc, diag::err_delete_explicit_conversion) << T << ConvTy; } SemaDiagnosticBuilder noteExplicitConv(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseAmbiguous(Sema &S, SourceLocation Loc, QualType T) override { return S.Diag(Loc, diag::err_ambiguous_delete_operand) << T; } SemaDiagnosticBuilder noteAmbiguous(Sema &S, CXXConversionDecl *Conv, QualType ConvTy) override { return S.Diag(Conv->getLocation(), diag::note_delete_conversion) << ConvTy; } SemaDiagnosticBuilder diagnoseConversion(Sema &S, SourceLocation Loc, QualType T, QualType ConvTy) override { llvm_unreachable("conversion functions are permitted"); } } Converter; Ex = PerformContextualImplicitConversion(StartLoc, Ex.get(), Converter); if (Ex.isInvalid()) return ExprError(); Type = Ex.get()->getType(); if (!Converter.match(Type)) // FIXME: PerformContextualImplicitConversion should return ExprError // itself in this case. return ExprError(); QualType Pointee = Type->getAs()->getPointeeType(); QualType PointeeElem = Context.getBaseElementType(Pointee); if (unsigned AddressSpace = Pointee.getAddressSpace()) return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() << AddressSpace; CXXRecordDecl *PointeeRD = nullptr; if (Pointee->isVoidType() && !isSFINAEContext()) { // The C++ standard bans deleting a pointer to a non-object type, which // effectively bans deletion of "void*". However, most compilers support // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { // FIXME: This can result in errors if the definition was imported from a // module but is hidden. if (!RequireCompleteType(StartLoc, Pointee, diag::warn_delete_incomplete, Ex.get())) { if (const RecordType *RT = PointeeElem->getAs()) PointeeRD = cast(RT->getDecl()); } } if (Pointee->isArrayType() && !ArrayForm) { Diag(StartLoc, diag::warn_delete_array_type) << Type << Ex.get()->getSourceRange() << FixItHint::CreateInsertion(getLocForEndOfToken(StartLoc), "[]"); ArrayForm = true; } DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( ArrayForm ? OO_Array_Delete : OO_Delete); if (PointeeRD) { if (!UseGlobal && FindDeallocationFunction(StartLoc, PointeeRD, DeleteName, OperatorDelete)) return ExprError(); // If we're allocating an array of records, check whether the // usual operator delete[] has a size_t parameter. if (ArrayForm) { // If the user specifically asked to use the global allocator, // we'll need to do the lookup into the class. if (UseGlobal) UsualArrayDeleteWantsSize = doesUsualArrayDeleteWantSize(*this, StartLoc, PointeeElem); // Otherwise, the usual operator delete[] should be the // function we just found. else if (OperatorDelete && isa(OperatorDelete)) UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); } if (!PointeeRD->hasIrrelevantDestructor()) if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { MarkFunctionReferenced(StartLoc, const_cast(Dtor)); if (DiagnoseUseOfDecl(Dtor, StartLoc)) return ExprError(); } CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc, /*IsDelete=*/true, /*CallCanBeVirtual=*/true, /*WarnOnNonAbstractTypes=*/!ArrayForm, SourceLocation()); } if (!OperatorDelete) // Look for a global declaration. OperatorDelete = FindUsualDeallocationFunction( StartLoc, isCompleteType(StartLoc, Pointee) && (!ArrayForm || UsualArrayDeleteWantsSize || Pointee.isDestructedType()), DeleteName); MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } } } CXXDeleteExpr *Result = new (Context) CXXDeleteExpr( Context.VoidTy, UseGlobal, ArrayForm, ArrayFormAsWritten, UsualArrayDeleteWantsSize, OperatorDelete, Ex.get(), StartLoc); AnalyzeDeleteExprMismatch(Result); return Result; } void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { if (!dtor || dtor->isVirtual() || !CallCanBeVirtual) return; // C++ [expr.delete]p3: // In the first alternative (delete object), if the static type of the // object to be deleted is different from its dynamic type, the static // type shall be a base class of the dynamic type of the object to be // deleted and the static type shall have a virtual destructor or the // behavior is undefined. // const CXXRecordDecl *PointeeRD = dtor->getParent(); // Note: a final class cannot be derived from, no issue there if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr()) return; QualType ClassType = dtor->getThisType(Context)->getPointeeType(); if (PointeeRD->isAbstract()) { // If the class is abstract, we warn by default, because we're // sure the code has undefined behavior. Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } else if (WarnOnNonAbstractTypes) { // Otherwise, if this is not an array delete, it's a bit suspect, // but not necessarily wrong. Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1) << ClassType; } if (!IsDelete) { std::string TypeStr; ClassType.getAsStringInternal(TypeStr, getPrintingPolicy()); Diag(DtorLoc, diag::note_delete_non_virtual) << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::"); } } Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { ExprResult E = CheckConditionVariable(cast(ConditionVar), StmtLoc, CK); if (E.isInvalid()) return ConditionError(); return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc), CK == ConditionKind::ConstexprIf); } /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, ConditionKind CK) { if (ConditionVar->isInvalidDecl()) return ExprError(); QualType T = ConditionVar->getType(); // C++ [stmt.select]p2: // The declarator shall not specify a function or an array. if (T->isFunctionType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_function_type) << ConditionVar->getSourceRange()); else if (T->isArrayType()) return ExprError(Diag(ConditionVar->getLocation(), diag::err_invalid_use_of_array_type) << ConditionVar->getSourceRange()); ExprResult Condition = DeclRefExpr::Create( Context, NestedNameSpecifierLoc(), SourceLocation(), ConditionVar, /*enclosing*/ false, ConditionVar->getLocation(), ConditionVar->getType().getNonReferenceType(), VK_LValue); MarkDeclRefReferenced(cast(Condition.get())); switch (CK) { case ConditionKind::Boolean: return CheckBooleanCondition(StmtLoc, Condition.get()); case ConditionKind::ConstexprIf: return CheckBooleanCondition(StmtLoc, Condition.get(), true); case ConditionKind::Switch: return CheckSwitchCondition(StmtLoc, Condition.get()); } llvm_unreachable("unexpected condition kind"); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) { // C++ 6.4p4: // The value of a condition that is an initialized declaration in a statement // other than a switch statement is the value of the declared variable // implicitly converted to type bool. If that conversion is ill-formed, the // program is ill-formed. // The value of a condition that is an expression is the value of the // expression, implicitly converted to bool. // // FIXME: Return this value to the caller so they don't need to recompute it. llvm::APSInt Value(/*BitWidth*/1); return (IsConstexpr && !CondExpr->isValueDependent()) ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, CCEK_ConstexprIf) : PerformContextuallyConvertToBool(CondExpr); } /// Helper function to determine whether this is the (deprecated) C++ /// conversion from a string literal to a pointer to non-const char or /// non-const wchar_t (for narrow and wide string literals, /// respectively). bool Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { // Look inside the implicit cast, if it exists. if (ImplicitCastExpr *Cast = dyn_cast(From)) From = Cast->getSubExpr(); // A string literal (2.13.4) that is not a wide string literal can // be converted to an rvalue of type "pointer to char"; a wide // string literal can be converted to an rvalue of type "pointer // to wchar_t" (C++ 4.2p2). if (StringLiteral *StrLit = dyn_cast(From->IgnoreParens())) if (const PointerType *ToPtrType = ToType->getAs()) if (const BuiltinType *ToPointeeType = ToPtrType->getPointeeType()->getAs()) { // This conversion is considered only when there is an // explicit appropriate pointer target type (C++ 4.2p2). if (!ToPtrType->getPointeeType().hasQualifiers()) { switch (StrLit->getKind()) { case StringLiteral::UTF8: case StringLiteral::UTF16: case StringLiteral::UTF32: // We don't allow UTF literals to be implicitly converted break; case StringLiteral::Ascii: return (ToPointeeType->getKind() == BuiltinType::Char_U || ToPointeeType->getKind() == BuiltinType::Char_S); case StringLiteral::Wide: return Context.typesAreCompatible(Context.getWideCharType(), QualType(ToPointeeType, 0)); } } } return false; } static ExprResult BuildCXXCastArgument(Sema &S, SourceLocation CastLoc, QualType Ty, CastKind Kind, CXXMethodDecl *Method, DeclAccessPair FoundDecl, bool HadMultipleCandidates, Expr *From) { switch (Kind) { default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { CXXConstructorDecl *Constructor = cast(Method); SmallVector ConstructorArgs; if (S.RequireNonAbstractType(CastLoc, Ty, diag::err_allocation_of_abstract_type)) return ExprError(); if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) return ExprError(); S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl, InitializedEntity::InitializeTemporary(Ty)); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); ExprResult Result = S.BuildCXXConstructExpr( CastLoc, Ty, FoundDecl, cast(Method), ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) return ExprError(); return S.MaybeBindToTemporary(Result.getAs()); } case CK_UserDefinedConversion: { assert(!From->getType()->isPointerType() && "Arg can't have pointer type!"); S.CheckMemberOperatorAccess(CastLoc, From, /*arg*/ nullptr, FoundDecl); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); // Create an implicit call expr that calls it. CXXConversionDecl *Conv = cast(Method); ExprResult Result = S.BuildCXXMemberCallExpr(From, FoundDecl, Conv, HadMultipleCandidates); if (Result.isInvalid()) return ExprError(); // Record usage of conversion in an implicit cast. Result = ImplicitCastExpr::Create(S.Context, Result.get()->getType(), CK_UserDefinedConversion, Result.get(), nullptr, Result.get()->getValueKind()); return S.MaybeBindToTemporary(Result.get()); } } } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType using the pre-computed implicit /// conversion sequence ICS. Returns the converted /// expression. Action is the kind of conversion we're performing, /// used in the error message. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, AssignmentAction Action, CheckedConversionKind CCK) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { ExprResult Res = PerformImplicitConversion(From, ToType, ICS.Standard, Action, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); break; } case ImplicitConversionSequence::UserDefinedConversion: { FunctionDecl *FD = ICS.UserDefined.ConversionFunction; CastKind CastKind; QualType BeforeToType; assert(FD && "no conversion function for user-defined conversion seq"); if (const CXXConversionDecl *Conv = dyn_cast(FD)) { CastKind = CK_UserDefinedConversion; // If the user-defined conversion is specified by a conversion function, // the initial standard conversion sequence converts the source type to // the implicit object parameter of the conversion function. BeforeToType = Context.getTagDeclType(Conv->getParent()); } else { const CXXConstructorDecl *Ctor = cast(FD); CastKind = CK_ConstructorConversion; // Do no conversion if dealing with ... for the first conversion. if (!ICS.UserDefined.EllipsisConversion) { // If the user-defined conversion is specified by a constructor, the // initial standard conversion sequence converts the source type to // the type required by the argument of the constructor BeforeToType = Ctor->getParamDecl(0)->getType().getNonReferenceType(); } } // Watch out for ellipsis conversion. if (!ICS.UserDefined.EllipsisConversion) { ExprResult Res = PerformImplicitConversion(From, BeforeToType, ICS.UserDefined.Before, AA_Converting, CCK); if (Res.isInvalid()) return ExprError(); From = Res.get(); } ExprResult CastArg = BuildCXXCastArgument(*this, From->getLocStart(), ToType.getNonReferenceType(), CastKind, cast(FD), ICS.UserDefined.FoundConversionFunction, ICS.UserDefined.HadMultipleCandidates, From); if (CastArg.isInvalid()) return ExprError(); From = CastArg.get(); return PerformImplicitConversion(From, ToType, ICS.UserDefined.After, AA_Converting, CCK); } case ImplicitConversionSequence::AmbiguousConversion: ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: return ExprError(); } // Everything went well. return From; } /// PerformImplicitConversion - Perform an implicit conversion of the /// expression From to the type ToType by following the standard /// conversion sequence SCS. Returns the converted /// expression. Flavor is the context in which we're performing this /// conversion, for use in error messages. ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, AssignmentAction Action, CheckedConversionKind CCK) { bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); if (SCS.Second == ICK_Derived_To_Base) { SmallVector ConstructorArgs; if (CompleteConstructorCall(cast(SCS.CopyConstructor), From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, ConstructorArgs, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } return BuildCXXConstructExpr( /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.FoundCopyConstructor, SCS.CopyConstructor, From, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } // Resolve overloaded function references. if (Context.hasSameType(FromType, Context.OverloadTy)) { DeclAccessPair Found; FunctionDecl *Fn = ResolveAddressOfOverloadedFunction(From, ToType, true, Found); if (!Fn) return ExprError(); if (DiagnoseUseOfDecl(Fn, From->getLocStart())) return ExprError(); From = FixOverloadedFunctionReference(From, Found, Fn); FromType = From->getType(); } // If we're converting to an atomic type, first convert to the corresponding // non-atomic type. QualType ToAtomicType; if (const AtomicType *ToAtomic = ToType->getAs()) { ToAtomicType = ToType; ToType = ToAtomic->getValueType(); } QualType InitialFromType = FromType; // Perform the first implicit conversion. switch (SCS.First) { case ICK_Identity: if (const AtomicType *FromAtomic = FromType->getAs()) { FromType = FromAtomic->getValueType().getUnqualifiedType(); From = ImplicitCastExpr::Create(Context, FromType, CK_AtomicToNonAtomic, From, /*BasePath=*/nullptr, VK_RValue); } break; case ICK_Lvalue_To_Rvalue: { assert(From->getObjectKind() != OK_ObjCProperty); ExprResult FromRes = DefaultLvalueConversion(From); assert(!FromRes.isInvalid() && "Can't perform deduced conversion?!"); From = FromRes.get(); FromType = From->getType(); break; } case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; default: llvm_unreachable("Improper first standard conversion"); } // Perform the second implicit conversion switch (SCS.Second) { case ICK_Identity: // C++ [except.spec]p5: // [For] assignment to and initialization of pointers to functions, // pointers to member functions, and references to functions: the // target entity shall allow at least the exceptions allowed by the // source value in the assignment or initialization. switch (Action) { case AA_Assigning: case AA_Initializing: // Note, function argument passing and returning are initialization. case AA_Passing: case AA_Returning: case AA_Sending: case AA_Passing_CFAudited: if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); break; case AA_Casting: case AA_Converting: // Casts and implicit conversions are not initialization, so are not // checked for exception specification mismatches. break; } // Nothing else to do. break; case ICK_NoReturn_Adjustment: // If both sides are functions (or pointers/references to them), there could // be incompatible exception declarations. if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { assert(FromType->castAs()->getDecl()->isFixed() && SCS.Second == ICK_Integral_Promotion && "only enums with fixed underlying type can promote to bool"); From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { From = ImpCastExprToType(From, ToType, CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } break; case ICK_Floating_Promotion: case ICK_Floating_Conversion: From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Complex_Promotion: case ICK_Complex_Conversion: { QualType FromEl = From->getType()->getAs()->getElementType(); QualType ToEl = ToType->getAs()->getElementType(); CastKind CK; if (FromEl->isRealFloatingType()) { if (ToEl->isRealFloatingType()) CK = CK_FloatingComplexCast; else CK = CK_FloatingComplexToIntegralComplex; } else if (ToEl->isRealFloatingType()) { CK = CK_IntegralComplexToFloatingComplex; } else { CK = CK_IntegralComplexCast; } From = ImpCastExprToType(From, ToType, CK, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); else From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Compatible_Conversion: From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Writeback_Conversion: case ICK_Pointer_Conversion: { if (SCS.IncompatibleObjC && Action != AA_Casting) { // Diagnose incompatible Objective-C conversions if (Action == AA_Initializing || Action == AA_Assigning) Diag(From->getLocStart(), diag::ext_typecheck_convert_incompatible_pointer) << ToType << From->getType() << Action << From->getSourceRange() << 0; else Diag(From->getLocStart(), diag::ext_typecheck_convert_incompatible_pointer) << From->getType() << ToType << Action << From->getSourceRange() << 0; if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); } else if (getLangOpts().ObjCAutoRefCount && !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { if (Action == AA_Initializing) Diag(From->getLocStart(), diag::err_arc_weak_unavailable_assign); else Diag(From->getLocStart(), diag::err_arc_convesion_of_weak_unavailable) << (Action == AA_Casting) << From->getType() << ToType << From->getSourceRange(); } CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); // Make sure we extend blocks if necessary. // FIXME: doing this here is really ugly. if (Kind == CK_BlockPointerToObjCPointerCast) { ExprResult E = From; (void) PrepareCastToObjCObjectPointer(E); From = E.get(); } if (getLangOpts().ObjCAutoRefCount) CheckObjCARCConversion(SourceRange(), ToType, From, CCK); From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Pointer_Member: { CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckMemberPointerConversion(From, ToType, Kind, BasePath, CStyle)) return ExprError(); if (CheckExceptionSpecCompatibility(From, ToType)) return ExprError(); // We may not have been able to figure out what this member pointer resolved // to up until this exact point. Attempt to lock-in it's inheritance model. if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)isCompleteType(From->getExprLoc(), From->getType()); (void)isCompleteType(From->getExprLoc(), ToType); } From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } case ICK_Boolean_Conversion: // Perform half-to-boolean conversion via float. if (From->getType()->isHalfType()) { From = ImpCastExprToType(From, Context.FloatTy, CK_FloatingCast).get(); FromType = Context.FloatTy; } From = ImpCastExprToType(From, Context.BoolTy, ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Derived_To_Base: { CXXCastPath BasePath; if (CheckDerivedToBaseConversion(From->getType(), ToType.getNonReferenceType(), From->getLocStart(), From->getSourceRange(), &BasePath, CStyle)) return ExprError(); From = ImpCastExprToType(From, ToType.getNonReferenceType(), CK_DerivedToBase, From->getValueKind(), &BasePath, CCK).get(); break; } case ICK_Vector_Conversion: From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Vector_Splat: { // Vector splat from any arithmetic type to a vector. Expr *Elem = prepareVectorSplat(ToType, From).get(); From = ImpCastExprToType(Elem, ToType, CK_VectorSplat, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Complex_Real: // Case 1. x -> _Complex y if (const ComplexType *ToComplex = ToType->getAs()) { QualType ElType = ToComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // x -> y if (Context.hasSameUnqualifiedType(ElType, From->getType())) { // do nothing } else if (From->getType()->isRealFloatingType()) { From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingCast : CK_FloatingToIntegral).get(); } else { assert(From->getType()->isIntegerType()); From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_IntegralToFloating : CK_IntegralCast).get(); } // y -> _Complex y From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingRealToComplex : CK_IntegralRealToComplex).get(); // Case 2. _Complex x -> y } else { const ComplexType *FromComplex = From->getType()->getAs(); assert(FromComplex); QualType ElType = FromComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal : CK_IntegralComplexToReal, VK_RValue, /*BasePath=*/nullptr, CCK).get(); // x -> y if (Context.hasSameUnqualifiedType(ElType, ToType)) { // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } } break; case ICK_Block_Pointer_Conversion: { From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_TransparentUnionConversion: { ExprResult FromRes = From; Sema::AssignConvertType ConvTy = CheckTransparentUnionArgumentConstraints(ToType, FromRes); if (FromRes.isInvalid()) return ExprError(); From = FromRes.get(); assert ((ConvTy == Sema::Compatible) && "Improper transparent union conversion"); (void)ConvTy; break; } case ICK_Zero_Event_Conversion: From = ImpCastExprToType(From, ToType, CK_ZeroToOCLEvent, From->getValueKind()).get(); break; case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: llvm_unreachable("Improper second standard conversion"); } switch (SCS.Third) { case ICK_Identity: // Nothing to do. break; case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. ExprValueKind VK = ToType->isReferenceType() ? From->getValueKind() : VK_RValue; From = ImpCastExprToType(From, ToType.getNonLValueExprType(Context), CK_NoOp, VK, /*BasePath=*/nullptr, CCK).get(); if (SCS.DeprecatedStringLiteralToCharPtr && !getLangOpts().WritableStrings) { Diag(From->getLocStart(), getLangOpts().CPlusPlus11 ? diag::ext_deprecated_string_literal_conversion : diag::warn_deprecated_string_literal_conversion) << ToType.getNonReferenceType(); } break; } default: llvm_unreachable("Improper third standard conversion"); } // If this conversion sequence involved a scalar -> atomic conversion, perform // that conversion now. if (!ToAtomicType.isNull()) { assert(Context.hasSameType( ToAtomicType->castAs()->getValueType(), From->getType())); From = ImpCastExprToType(From, ToAtomicType, CK_NonAtomicToAtomic, VK_RValue, nullptr, CCK).get(); } // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. if (CCK == CCK_ImplicitConversion) diagnoseNullableToNonnullConversion(ToType, InitialFromType, From->getLocStart()); return From; } /// \brief Check the completeness of a type in a unary type trait. /// /// If the particular type trait requires a complete type, tries to complete /// it. If completing the type fails, a diagnostic is emitted and false /// returned. If completing the type succeeds or no completion was required, /// returns true. static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, SourceLocation Loc, QualType ArgTy) { // C++0x [meta.unary.prop]p3: // For all of the class templates X declared in this Clause, instantiating // that template with a template argument that is a class template // specialization may result in the implicit instantiation of the template // argument if and only if the semantics of X require that the argument // must be a complete type. // We apply this rule to all the type trait expressions used to implement // these class templates. We also try to follow any GCC documented behavior // in these expressions to ensure portability of standard libraries. switch (UTT) { default: llvm_unreachable("not a UTT"); // is_complete_type somewhat obviously cannot require a complete type. case UTT_IsCompleteType: // Fall-through // These traits are modeled on the type predicates in C++0x // [meta.unary.cat] and [meta.unary.comp]. They are not specified as // requiring a complete type, as whether or not they return true cannot be // impacted by the completeness of the type. case UTT_IsVoid: case UTT_IsIntegral: case UTT_IsFloatingPoint: case UTT_IsArray: case UTT_IsPointer: case UTT_IsLvalueReference: case UTT_IsRvalueReference: case UTT_IsMemberFunctionPointer: case UTT_IsMemberObjectPointer: case UTT_IsEnum: case UTT_IsUnion: case UTT_IsClass: case UTT_IsFunction: case UTT_IsReference: case UTT_IsArithmetic: case UTT_IsFundamental: case UTT_IsObject: case UTT_IsScalar: case UTT_IsCompound: case UTT_IsMemberPointer: // Fall-through // These traits are modeled on type predicates in C++0x [meta.unary.prop] // which requires some of its traits to have the complete type. However, // the completeness of the type cannot impact these traits' semantics, and // so they don't require it. This matches the comments on these traits in // Table 49. case UTT_IsConst: case UTT_IsVolatile: case UTT_IsSigned: case UTT_IsUnsigned: // This type trait always returns false, checking the type is moot. case UTT_IsInterfaceClass: return true; // C++14 [meta.unary.prop]: // If T is a non-union class type, T shall be a complete type. case UTT_IsEmpty: case UTT_IsPolymorphic: case UTT_IsAbstract: if (const auto *RD = ArgTy->getAsCXXRecordDecl()) if (!RD->isUnion()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++14 [meta.unary.prop]: // If T is a class type, T shall be a complete type. case UTT_IsFinal: case UTT_IsSealed: if (ArgTy->getAsCXXRecordDecl()) return !S.RequireCompleteType( Loc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr); return true; // C++0x [meta.unary.prop] Table 49 requires the following traits to be // applied to a complete type. case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: case UTT_IsPOD: case UTT_IsLiteral: case UTT_IsDestructible: case UTT_IsNothrowDestructible: // Fall-through // These trait expressions are designed to help implement predicates in // [meta.unary.prop] despite not being named the same. They are specified // by both GCC and the Embarcadero C++ compiler, and require the complete // type due to the overarching C++0x type predicates being implemented // requiring the complete type. case UTT_HasNothrowAssign: case UTT_HasNothrowMoveAssign: case UTT_HasNothrowConstructor: case UTT_HasNothrowCopy: case UTT_HasTrivialAssign: case UTT_HasTrivialMoveAssign: case UTT_HasTrivialDefaultConstructor: case UTT_HasTrivialMoveConstructor: case UTT_HasTrivialCopy: case UTT_HasTrivialDestructor: case UTT_HasVirtualDestructor: // Arrays of unknown bound are expressly allowed. QualType ElTy = ArgTy; if (ArgTy->isIncompleteArrayType()) ElTy = S.Context.getAsArrayType(ArgTy)->getElementType(); // The void type is expressly allowed. if (ElTy->isVoidType()) return true; return !S.RequireCompleteType( Loc, ElTy, diag::err_incomplete_type_used_in_type_trait_expr); } } static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, bool (CXXRecordDecl::*HasTrivial)() const, bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { CXXRecordDecl *RD = cast(RT->getDecl()); if ((RD->*HasTrivial)() && !(RD->*HasNonTrivial)()) return true; DeclarationName Name = C.DeclarationNames.getCXXOperatorName(Op); DeclarationNameInfo NameInfo(Name, KeyLoc); LookupResult Res(Self, NameInfo, Sema::LookupOrdinaryName); if (Self.LookupQualifiedName(Res, RD)) { bool FoundOperator = false; Res.suppressDiagnostics(); for (LookupResult::iterator Op = Res.begin(), OpEnd = Res.end(); Op != OpEnd; ++Op) { if (isa(*Op)) continue; CXXMethodDecl *Operator = cast(*Op); if((Operator->*IsDesiredOp)()) { FoundOperator = true; const FunctionProtoType *CPT = Operator->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow(C)) return false; } } return FoundOperator; } return false; } static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, SourceLocation KeyLoc, QualType T) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); ASTContext &C = Self.Context; switch(UTT) { default: llvm_unreachable("not a UTT"); // Type trait expressions corresponding to the primary type category // predicates in C++0x [meta.unary.cat]. case UTT_IsVoid: return T->isVoidType(); case UTT_IsIntegral: return T->isIntegralType(C); case UTT_IsFloatingPoint: return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); case UTT_IsPointer: return T->isPointerType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: return T->isRValueReferenceType(); case UTT_IsMemberFunctionPointer: return T->isMemberFunctionPointerType(); case UTT_IsMemberObjectPointer: return T->isMemberDataPointerType(); case UTT_IsEnum: return T->isEnumeralType(); case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: return T->isClassType() || T->isStructureType() || T->isInterfaceType(); case UTT_IsFunction: return T->isFunctionType(); // Type trait expressions which correspond to the convenient composition // predicates in C++0x [meta.unary.comp]. case UTT_IsReference: return T->isReferenceType(); case UTT_IsArithmetic: return T->isArithmeticType() && !T->isEnumeralType(); case UTT_IsFundamental: return T->isFundamentalType(); case UTT_IsObject: return T->isObjectType(); case UTT_IsScalar: // Note: semantic analysis depends on Objective-C lifetime types to be // considered scalar types. However, such types do not actually behave // like scalar types at run time (since they may require retain/release // operations), so we report them as non-scalar. if (T->isObjCLifetimeType()) { switch (T.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: return true; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return false; } } return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); case UTT_IsMemberPointer: return T->isMemberPointerType(); // Type trait expressions which correspond to the type property predicates // in C++0x [meta.unary.prop]. case UTT_IsConst: return T.isConstQualified(); case UTT_IsVolatile: return T.isVolatileQualified(); case UTT_IsTrivial: return T.isTrivialType(C); case UTT_IsTriviallyCopyable: return T.isTriviallyCopyableType(C); case UTT_IsStandardLayout: return T->isStandardLayoutType(); case UTT_IsPOD: return T.isPODType(C); case UTT_IsLiteral: return T->isLiteralType(C); case UTT_IsEmpty: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isEmpty(); return false; case UTT_IsPolymorphic: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isPolymorphic(); return false; case UTT_IsAbstract: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isAbstract(); return false; // __is_interface_class only returns true when CL is invoked in /CLR mode and // even then only when it is used with the 'interface struct ...' syntax // Clang doesn't support /CLR which makes this type trait moot. case UTT_IsInterfaceClass: return false; case UTT_IsFinal: case UTT_IsSealed: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasAttr(); return false; case UTT_IsSigned: return T->isSignedIntegerType(); case UTT_IsUnsigned: return T->isUnsignedIntegerType(); // Type trait expressions which query classes regarding their construction, // destruction, and copying. Rather than being based directly on the // related type predicates in the standard, they are specified by both // GCC[1] and the Embarcadero C++ compiler[2], and Clang implements those // specifications. // // 1: http://gcc.gnu/.org/onlinedocs/gcc/Type-Traits.html // 2: http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index // // Note that these builtins do not behave as documented in g++: if a class // has both a trivial and a non-trivial special member of a particular kind, // they return false! For now, we emulate this behavior. // FIXME: This appears to be a g++ bug: more complex cases reveal that it // does not correctly compute triviality in the presence of multiple special // members of the same kind. Revisit this once the g++ bug is fixed. case UTT_HasTrivialDefaultConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is // a cv class or union type (or array thereof) with a trivial default // constructor ([class.ctor]) then the trait is true, else it is false. if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor(); return false; case UTT_HasTrivialMoveConstructor: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_trivially_move_constructible (20.9.4.3). if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveConstructor() && !RD->hasNonTrivialMoveConstructor(); return false; case UTT_HasTrivialCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true or type is a reference type then // the trait is true, else if type is a cv class or union type // with a trivial copy constructor ([class.copy]) then the trait // is true, else it is false. if (T.isPODType(C) || T->isReferenceType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor(); return false; case UTT_HasTrivialMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically it is used as the logic // behind std::is_trivially_move_assignable (20.9.4.3) if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialMoveAssignment() && !RD->hasNonTrivialMoveAssignment(); return false; case UTT_HasTrivialAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __is_pod (type) is true then the // trait is true, else if type is a cv class or union type with // a trivial copy assignment ([class.copy]) then the trait is // true, else it is false. // Note: the const and reference restrictions are interesting, // given that const and reference members don't prevent a class // from having a trivial copy assignment operator (but do cause // errors if the copy assignment operator is actually used, q.v. // [class.copy]p12). if (T.isConstQualified()) return false; if (T.isPODType(C)) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasTrivialCopyAssignment() && !RD->hasNonTrivialCopyAssignment(); return false; case UTT_IsDestructible: case UTT_IsNothrowDestructible: // C++14 [meta.unary.prop]: // For reference types, is_destructible::value is true. if (T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; // C++14 [meta.unary.prop]: // For incomplete types and function types, is_destructible::value is // false. if (T->isIncompleteType() || T->isFunctionType()) return false; // C++14 [meta.unary.prop]: // For object types and given U equal to remove_all_extents_t, if the // expression std::declval().~U() is well-formed when treated as an // unevaluated operand (Clause 5), then is_destructible::value is true if (auto *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { CXXDestructorDecl *Destructor = Self.LookupDestructor(RD); if (!Destructor) return false; // C++14 [dcl.fct.def.delete]p2: // A program that refers to a deleted function implicitly or // explicitly, other than to declare it, is ill-formed. if (Destructor->isDeleted()) return false; if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) return false; if (UTT == UTT_IsNothrowDestructible) { const FunctionProtoType *CPT = Destructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow(C)) return false; } } return true; case UTT_HasTrivialDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __is_pod (type) is true or type is a reference type // then the trait is true, else if type is a cv class or union // type (or array thereof) with a trivial destructor // ([class.dtor]) then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType()) return true; // Objective-C++ ARC: autorelease types don't require destruction. if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDestructor(); return false; // TODO: Propagate nothrowness for implicitly declared special members. case UTT_HasNothrowAssign: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is const qualified or is a reference type then the // trait is false. Otherwise if __has_trivial_assign (type) // is true then the trait is true, else if type is a cv class // or union type with copy assignment operators that are known // not to throw an exception then the trait is true, else it is // false. if (C.getBaseElementType(T).isConstQualified()) return false; if (T->isReferenceType()) return false; if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (const RecordType *RT = T->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialCopyAssignment, &CXXRecordDecl::hasNonTrivialCopyAssignment, &CXXMethodDecl::isCopyAssignmentOperator); return false; case UTT_HasNothrowMoveAssign: // This trait is implemented by MSVC 2012 and needed to parse the // standard library headers. Specifically this is used as the logic // behind std::is_nothrow_move_assignable (20.9.4.3). if (T.isPODType(C)) return true; if (const RecordType *RT = C.getBaseElementType(T)->getAs()) return HasNoThrowOperator(RT, OO_Equal, Self, KeyLoc, C, &CXXRecordDecl::hasTrivialMoveAssignment, &CXXRecordDecl::hasNonTrivialMoveAssignment, &CXXMethodDecl::isMoveAssignmentOperator); return false; case UTT_HasNothrowCopy: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __has_trivial_copy (type) is true then the trait is true, else // if type is a cv class or union type with copy constructors that are // known not to throw an exception then the trait is true, else it is // false. if (T.isPODType(C) || T->isReferenceType() || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) { if (RD->hasTrivialCopyConstructor() && !RD->hasNonTrivialCopyConstructor()) return true; bool FoundConstructor = false; unsigned FoundTQs; for (const auto *ND : Self.LookupConstructors(RD)) { // A template constructor is never a copy constructor. // FIXME: However, it may actually be selected at the actual overload // resolution point. - if (isa(ND)) + if (isa(ND->getUnderlyingDecl())) continue; - const CXXConstructorDecl *Constructor = cast(ND); + // UsingDecl itself is not a constructor + if (isa(ND)) + continue; + auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // TODO: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow(C) || CPT->getNumParams() > 1) return false; } } return FoundConstructor; } return false; case UTT_HasNothrowConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html // If __has_trivial_constructor (type) is true then the trait is // true, else if type is a cv class or union type (or array // thereof) with a default constructor that is known not to // throw an exception then the trait is true, else it is false. if (T.isPODType(C) || T->isObjCLifetimeType()) return true; if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) { if (RD->hasTrivialDefaultConstructor() && !RD->hasNonTrivialDefaultConstructor()) return true; bool FoundConstructor = false; for (const auto *ND : Self.LookupConstructors(RD)) { // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa(ND)) + if (isa(ND->getUnderlyingDecl())) + continue; + // UsingDecl itself is not a constructor + if (isa(ND)) continue; - const CXXConstructorDecl *Constructor = cast(ND); + auto *Constructor = cast(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; const FunctionProtoType *CPT = Constructor->getType()->getAs(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; // FIXME: check whether evaluating default arguments can throw. // For now, we'll be conservative and assume that they can throw. if (!CPT->isNothrow(C) || CPT->getNumParams() > 0) return false; } } return FoundConstructor; } return false; case UTT_HasVirtualDestructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If type is a class type with a virtual destructor ([class.dtor]) // then the trait is true, else it is false. if (CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *Destructor = Self.LookupDestructor(RD)) return Destructor->isVirtual(); return false; // These type trait expressions are modeled on the specifications for the // Embarcadero C++0x type trait functions: // http://docwiki.embarcadero.com/RADStudio/XE/en/Type_Trait_Functions_(C%2B%2B0x)_Index case UTT_IsCompleteType: // http://docwiki.embarcadero.com/RADStudio/XE/en/Is_complete_type_(typename_T_): // Returns True if and only if T is a complete type at the point of the // function call. return !T->isIncompleteType(); } } /// \brief Determine whether T has a non-trivial Objective-C lifetime in /// ARC mode. static bool hasNontrivialObjCLifetime(QualType T) { switch (T.getObjCLifetime()) { case Qualifiers::OCL_ExplicitNone: return false; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: case Qualifiers::OCL_Autoreleasing: return true; case Qualifiers::OCL_None: return T->isObjCLifetimeType(); } llvm_unreachable("Unknown ObjC lifetime qualifier"); } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc); static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { if (Kind <= UTT_Last) return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); if (Kind <= BTT_Last) return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), Args[1]->getType(), RParenLoc); switch (Kind) { case clang::TT_IsConstructible: case clang::TT_IsNothrowConstructible: case clang::TT_IsTriviallyConstructible: { // C++11 [meta.unary.prop]: // is_trivially_constructible is defined as: // // is_constructible::value is true and the variable // definition for is_constructible, as defined below, is known to call // no operation that is not trivial. // // The predicate condition for a template specialization // is_constructible shall be satisfied if and only if the // following variable definition would be well-formed for some invented // variable t: // // T t(create()...); assert(!Args.empty()); // Precondition: T and all types in the parameter pack Args shall be // complete types, (possibly cv-qualified) void, or arrays of // unknown bound. for (const auto *TSI : Args) { QualType ArgTy = TSI->getType(); if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; if (S.RequireCompleteType(KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } // Make sure the first argument is not incomplete nor a function type. QualType T = Args[0]->getType(); if (T->isIncompleteType() || T->isFunctionType()) return false; // Make sure the first argument is not an abstract type. CXXRecordDecl *RD = T->getAsCXXRecordDecl(); if (RD && RD->isAbstract()) return false; SmallVector OpaqueArgExprs; SmallVector ArgExprs; ArgExprs.reserve(Args.size() - 1); for (unsigned I = 1, N = Args.size(); I != N; ++I) { QualType ArgTy = Args[I]->getType(); if (ArgTy->isObjectType() || ArgTy->isFunctionType()) ArgTy = S.Context.getRValueReferenceType(ArgTy); OpaqueArgExprs.push_back( OpaqueValueExpr(Args[I]->getTypeLoc().getLocStart(), ArgTy.getNonLValueExprType(S.Context), Expr::getValueKindForType(ArgTy))); } for (Expr &E : OpaqueArgExprs) ArgExprs.push_back(&E); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(S, S.Context.getTranslationUnitDecl()); InitializedEntity To(InitializedEntity::InitializeTemporary(Args[0])); InitializationKind InitKind(InitializationKind::CreateDirect(KWLoc, KWLoc, RParenLoc)); InitializationSequence Init(S, To, InitKind, ArgExprs); if (Init.Failed()) return false; ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; if (Kind == clang::TT_IsConstructible) return true; if (Kind == clang::TT_IsNothrowConstructible) return S.canThrow(Result.get()) == CT_Cannot; if (Kind == clang::TT_IsTriviallyConstructible) { // Under Objective-C ARC, if the destination has non-trivial Objective-C // lifetime, this is a non-trivial construction. if (S.getLangOpts().ObjCAutoRefCount && hasNontrivialObjCLifetime(T.getNonReferenceType())) return false; // The initialization succeeded; now make sure there are no non-trivial // calls. return !Result.get()->hasNonTrivialCall(S.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a TT"); } return false; } ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { QualType ResultType = Context.getLogicalOperationType(); if (Kind <= UTT_Last && !CheckUnaryTypeTraitTypeCompleteness( *this, Kind, KWLoc, Args[0]->getType())) return ExprError(); bool Dependent = false; for (unsigned I = 0, N = Args.size(); I != N; ++I) { if (Args[I]->getType()->isDependentType()) { Dependent = true; break; } } bool Result = false; if (!Dependent) Result = evaluateTypeTrait(*this, Kind, KWLoc, Args, RParenLoc); return TypeTraitExpr::Create(Context, ResultType, KWLoc, Kind, Args, RParenLoc, Result); } ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, ArrayRef Args, SourceLocation RParenLoc) { SmallVector ConvertedArgs; ConvertedArgs.reserve(Args.size()); for (unsigned I = 0, N = Args.size(); I != N; ++I) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(Args[I], &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); ConvertedArgs.push_back(TInfo); } return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); } static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, QualType RhsT, SourceLocation KeyLoc) { assert(!LhsT->isDependentType() && !RhsT->isDependentType() && "Cannot evaluate traits of dependent types"); switch(BTT) { case BTT_IsBaseOf: { // C++0x [meta.rel]p2 // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. const RecordType *lhsRecord = LhsT->getAs(); if (!lhsRecord) return false; const RecordType *rhsRecord = RhsT->getAs(); if (!rhsRecord) return false; assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) == (lhsRecord == rhsRecord)); if (lhsRecord == rhsRecord) return !lhsRecord->getDecl()->isUnion(); // C++0x [meta.rel]p2: // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. if (Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; return cast(rhsRecord->getDecl()) ->isDerivedFrom(cast(lhsRecord->getDecl())); } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); case BTT_TypeCompatible: return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), RhsT.getUnqualifiedType()); case BTT_IsConvertible: case BTT_IsConvertibleTo: { // C++0x [meta.rel]p4: // Given the following function prototype: // // template // typename add_rvalue_reference::type create(); // // the predicate condition for a template specialization // is_convertible shall be satisfied if and only if // the return expression in the following code would be // well-formed, including any implicit conversions to the return // type of the function: // // To test() { // return create(); // } // // Access checking is performed as if in a context unrelated to To and // From. Only the validity of the immediate context of the expression // of the return-statement (including conversions to the return type) // is considered. // // We model the initialization as a copy-initialization of a temporary // of the appropriate type, which for this expression is identical to the // return statement (since NRVO doesn't apply). // Functions aren't allowed to return function or array types. if (RhsT->isFunctionType() || RhsT->isArrayType()) return false; // A return statement in a void function must have void type. if (RhsT->isVoidType()) return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) return false; // Compute the result of add_rvalue_reference. if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); // Build a fake source and destination for initialization. InitializedEntity To(InitializedEntity::InitializeTemporary(RhsT)); OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); InitializationSequence Init(Self, To, Kind, FromPtr); if (Init.Failed()) return false; ExprResult Result = Init.Perform(Self, To, Kind, FromPtr); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } case BTT_IsAssignable: case BTT_IsNothrowAssignable: case BTT_IsTriviallyAssignable: { // C++11 [meta.unary.prop]p3: // is_trivially_assignable is defined as: // is_assignable::value is true and the assignment, as defined by // is_assignable, is known to call no operation that is not trivial // // is_assignable is defined as: // The expression declval() = declval() is well-formed when // treated as an unevaluated operand (Clause 5). // // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. if (LhsT->isVoidType() || RhsT->isVoidType()) return false; // Build expressions that emulate the effect of declval() and // declval(). if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); if (RhsT->isObjectType() || RhsT->isFunctionType()) RhsT = Self.Context.getRValueReferenceType(RhsT); OpaqueValueExpr Lhs(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(RhsT)); // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); Sema::ContextRAII TUContext(Self, Self.Context.getTranslationUnitDecl()); ExprResult Result = Self.BuildBinOp(/*S=*/nullptr, KeyLoc, BO_Assign, &Lhs, &Rhs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; if (BTT == BTT_IsAssignable) return true; if (BTT == BTT_IsNothrowAssignable) return Self.canThrow(Result.get()) == CT_Cannot; if (BTT == BTT_IsTriviallyAssignable) { // Under Objective-C ARC, if the destination has non-trivial Objective-C // lifetime, this is a non-trivial assignment. if (Self.getLangOpts().ObjCAutoRefCount && hasNontrivialObjCLifetime(LhsT.getNonReferenceType())) return false; return !Result.get()->hasNonTrivialCall(Self.Context); } llvm_unreachable("unhandled type trait"); return false; } default: llvm_unreachable("not a BTT"); } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::ActOnArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, ParsedType Ty, Expr* DimExpr, SourceLocation RParen) { TypeSourceInfo *TSInfo; QualType T = GetTypeFromParser(Ty, &TSInfo); if (!TSInfo) TSInfo = Context.getTrivialTypeSourceInfo(T); return BuildArrayTypeTrait(ATT, KWLoc, TSInfo, DimExpr, RParen); } static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, QualType T, Expr *DimExpr, SourceLocation KeyLoc) { assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); switch(ATT) { case ATT_ArrayRank: if (T->isArrayType()) { unsigned Dim = 0; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { ++Dim; T = AT->getElementType(); } return Dim; } return 0; case ATT_ArrayExtent: { llvm::APSInt Value; uint64_t Dim; if (Self.VerifyIntegerConstantExpression(DimExpr, &Value, diag::err_dimension_expr_not_constant_integer, false).isInvalid()) return 0; if (Value.isSigned() && Value.isNegative()) { Self.Diag(KeyLoc, diag::err_dimension_expr_not_constant_integer) << DimExpr->getSourceRange(); return 0; } Dim = Value.getLimitedValue(); if (T->isArrayType()) { unsigned D = 0; bool Matched = false; while (const ArrayType *AT = Self.Context.getAsArrayType(T)) { if (Dim == D) { Matched = true; break; } ++D; T = AT->getElementType(); } if (Matched && T->isArrayType()) { if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T)) return CAT->getSize().getLimitedValue(); } } return 0; } } llvm_unreachable("Unknown type trait or not implemented"); } ExprResult Sema::BuildArrayTypeTrait(ArrayTypeTrait ATT, SourceLocation KWLoc, TypeSourceInfo *TSInfo, Expr* DimExpr, SourceLocation RParen) { QualType T = TSInfo->getType(); // FIXME: This should likely be tracked as an APInt to remove any host // assumptions about the width of size_t on the target. uint64_t Value = 0; if (!T->isDependentType()) Value = EvaluateArrayTypeTrait(*this, ATT, T, DimExpr, KWLoc); // While the specification for these traits from the Embarcadero C++ // compiler's documentation says the return type is 'unsigned int', Clang // returns 'size_t'. On Windows, the primary platform for the Embarcadero // compiler, there is no difference. On several other platforms this is an // important distinction. return new (Context) ArrayTypeTraitExpr(KWLoc, ATT, TSInfo, Value, DimExpr, RParen, Context.getSizeType()); } ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { // If error parsing the expression, ignore. if (!Queried) return ExprError(); ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen); return Result; } static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { switch (ET) { case ET_IsLValueExpr: return E->isLValue(); case ET_IsRValueExpr: return E->isRValue(); } llvm_unreachable("Expression trait not covered by switch"); } ExprResult Sema::BuildExpressionTrait(ExpressionTrait ET, SourceLocation KWLoc, Expr *Queried, SourceLocation RParen) { if (Queried->isTypeDependent()) { // Delay type-checking for type-dependent expressions. } else if (Queried->getType()->isPlaceholderType()) { ExprResult PE = CheckPlaceholderExpr(Queried); if (PE.isInvalid()) return ExprError(); return BuildExpressionTrait(ET, KWLoc, PE.get(), RParen); } bool Value = EvaluateExpressionTrait(ET, Queried); return new (Context) ExpressionTraitExpr(KWLoc, ET, Queried, Value, RParen, Context.BoolTy); } QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, SourceLocation Loc, bool isIndirect) { assert(!LHS.get()->getType()->isPlaceholderType() && !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); // The LHS undergoes lvalue conversions if this is ->*. if (isIndirect) { LHS = DefaultLvalueConversion(LHS.get()); if (LHS.isInvalid()) return QualType(); } // The RHS always undergoes lvalue conversions. RHS = DefaultLvalueConversion(RHS.get()); if (RHS.isInvalid()) return QualType(); const char *OpSpelling = isIndirect ? "->*" : ".*"; // C++ 5.5p2 // The binary operator .* [p3: ->*] binds its second operand, which shall // be of type "pointer to member of T" (where T is a completely-defined // class type) [...] QualType RHSType = RHS.get()->getType(); const MemberPointerType *MemPtr = RHSType->getAs(); if (!MemPtr) { Diag(Loc, diag::err_bad_memptr_rhs) << OpSpelling << RHSType << RHS.get()->getSourceRange(); return QualType(); } QualType Class(MemPtr->getClass(), 0); // Note: C++ [expr.mptr.oper]p2-3 says that the class type into which the // member pointer points must be completely-defined. However, there is no // reason for this semantic distinction, and the rule is not enforced by // other compilers. Therefore, we do not check this property, as it is // likely to be considered a defect. // C++ 5.5p2 // [...] to its first operand, which shall be of class T or of a class of // which T is an unambiguous and accessible base class. [p3: a pointer to // such a class] QualType LHSType = LHS.get()->getType(); if (isIndirect) { if (const PointerType *Ptr = LHSType->getAs()) LHSType = Ptr->getPointeeType(); else { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << 1 << LHSType << FixItHint::CreateReplacement(SourceRange(Loc), ".*"); return QualType(); } } if (!Context.hasSameUnqualifiedType(Class, LHSType)) { // If we want to check the hierarchy, we need a complete type. if (RequireCompleteType(Loc, LHSType, diag::err_bad_memptr_lhs, OpSpelling, (int)isIndirect)) { return QualType(); } if (!IsDerivedFrom(Loc, LHSType, Class)) { Diag(Loc, diag::err_bad_memptr_lhs) << OpSpelling << (int)isIndirect << LHS.get()->getType(); return QualType(); } CXXCastPath BasePath; if (CheckDerivedToBaseConversion(LHSType, Class, Loc, SourceRange(LHS.get()->getLocStart(), RHS.get()->getLocEnd()), &BasePath)) return QualType(); // Cast LHS to type of use. QualType UseType = isIndirect ? Context.getPointerType(Class) : Class; ExprValueKind VK = isIndirect ? VK_RValue : LHS.get()->getValueKind(); LHS = ImpCastExprToType(LHS.get(), UseType, CK_DerivedToBase, VK, &BasePath); } if (isa(RHS.get()->IgnoreParens())) { // Diagnose use of pointer-to-member type which when used as // the functional cast in a pointer-to-member expression. Diag(Loc, diag::err_pointer_to_member_type) << isIndirect; return QualType(); } // C++ 5.5p2 // The result is an object or a function of the type specified by the // second operand. // The cv qualifiers are the union of those in the pointer and the left side, // in accordance with 5.5p5 and 5.2.5. QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); // C++0x [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is // ill-formed if the second operand is a pointer to member function with // ref-qualifier &. In a ->* expression or in a .* expression whose object // expression is an lvalue, the program is ill-formed if the second operand // is a pointer to member function with ref-qualifier &&. if (const FunctionProtoType *Proto = Result->getAs()) { switch (Proto->getRefQualifier()) { case RQ_None: // Do nothing break; case RQ_LValue: if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 1 << LHS.get()->getSourceRange(); break; case RQ_RValue: if (isIndirect || !LHS.get()->Classify(Context).isRValue()) Diag(Loc, diag::err_pointer_to_member_oper_value_classify) << RHSType << 0 << LHS.get()->getSourceRange(); break; } } // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its // first operand. The result of a .* expression whose second // operand is a pointer to a member function is a prvalue. The // result of an ->* expression is an lvalue if its second operand // is a pointer to data member and a prvalue otherwise. if (Result->isFunctionType()) { VK = VK_RValue; return Context.BoundMemberTy; } else if (isIndirect) { VK = VK_LValue; } else { VK = LHS.get()->getValueKind(); } return Result; } /// \brief Try to convert a type to another according to C++11 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be /// converted to each other. This function does the conversion in one direction. /// It returns true if the program is ill-formed and has already been diagnosed /// as such. static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, SourceLocation QuestionLoc, bool &HaveConversion, QualType &ToType) { HaveConversion = false; ToType = To->getType(); InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); // C++11 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: // -- If E2 is an lvalue: E1 can be converted to match E2 if E1 can be // implicitly converted to type "lvalue reference to T2", subject to the // constraint that in the conversion the reference must bind directly to // an lvalue. // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be // implicitly conveted to the type "rvalue reference to R2", subject to // the constraint that the reference must bind directly. if (To->isLValue() || To->isXValue()) { QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) : Self.Context.getRValueReferenceType(ToType); InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq.isDirectReferenceBinding()) { ToType = T; HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } // -- If E2 is an rvalue, or if the conversion above cannot be done: // -- if E1 and E2 have class type, and the underlying class types are // the same or one is a base class of the other: QualType FTy = From->getType(); QualType TTy = To->getType(); const RecordType *FRec = FTy->getAs(); const RecordType *TRec = TTy->getAs(); bool FDerivedFromT = FRec && TRec && FRec != TRec && Self.IsDerivedFrom(QuestionLoc, FTy, TTy); if (FRec && TRec && (FRec == TRec || FDerivedFromT || Self.IsDerivedFrom(QuestionLoc, TTy, FTy))) { // E1 can be converted to match E2 if the class of T2 is the // same type as, or a base class of, the class of T1, and // [cv2 > cv1]. if (FRec == TRec || FDerivedFromT) { if (TTy.isAtLeastAsQualifiedAs(FTy)) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); if (InitSeq) { HaveConversion = true; return false; } if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); } } return false; } // -- Otherwise: E1 can be converted to match E2 if E1 can be // implicitly converted to the type that expression E2 would have // if E2 were converted to an rvalue (or the type it has, if E2 is // an rvalue). // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. if (!TTy->getAs()) TTy = TTy.getUnqualifiedType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); HaveConversion = !InitSeq.Failed(); ToType = TTy; if (InitSeq.isAmbiguous()) return InitSeq.Diagnose(Self, Entity, Kind, From); return false; } /// \brief Try to find a common type for two according to C++0x 5.16p5. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, overload resolution is used to find a /// conversion to a common type. static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS, SourceLocation QuestionLoc) { Expr *Args[2] = { LHS.get(), RHS.get() }; OverloadCandidateSet CandidateSet(QuestionLoc, OverloadCandidateSet::CSK_Operator); Self.AddBuiltinOperatorCandidates(OO_Conditional, QuestionLoc, Args, CandidateSet); OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) { case OR_Success: { // We found a match. Perform the conversions on the arguments and move on. ExprResult LHSRes = Self.PerformImplicitConversion(LHS.get(), Best->BuiltinTypes.ParamTypes[0], Best->Conversions[0], Sema::AA_Converting); if (LHSRes.isInvalid()) break; LHS = LHSRes; ExprResult RHSRes = Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1], Best->Conversions[1], Sema::AA_Converting); if (RHSRes.isInvalid()) break; RHS = RHSRes; if (Best->Function) Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; } case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is a pointer type. In this case, the user most // likely forgot to take the address of the other expression. if (Self.DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return true; Self.Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return true; case OR_Ambiguous: Self.Diag(QuestionLoc, diag::err_conditional_ambiguous_ovl) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); // FIXME: Print the possible common types by printing the return types of // the viable candidates. break; case OR_Deleted: llvm_unreachable("Conditional operator has only built-in overloads"); } return true; } /// \brief Perform an "extended" implicit conversion as returned by /// TryClassUnification. static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationKind Kind = InitializationKind::CreateCopy(E.get()->getLocStart(), SourceLocation()); Expr *Arg = E.get(); InitializationSequence InitSeq(Self, Entity, Kind, Arg); ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; E = Result; return false; } /// \brief Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. if (!Cond.get()->isTypeDependent()) { ExprResult CondRes = CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) return QualType(); Cond = CondRes; } // Assume r-value. VK = VK_RValue; OK = OK_Ordinary; // Either of the arguments dependent? if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent()) return Context.DependentTy; // C++11 [expr.cond]p2 // If either the second or the third operand has type (cv) void, ... QualType LTy = LHS.get()->getType(); QualType RTy = RHS.get()->getType(); bool LVoid = LTy->isVoidType(); bool RVoid = RTy->isVoidType(); if (LVoid || RVoid) { // ... one of the following shall hold: // -- The second or the third operand (but not both) is a (possibly // parenthesized) throw-expression; the result is of the type // and value category of the other. bool LThrow = isa(LHS.get()->IgnoreParenImpCasts()); bool RThrow = isa(RHS.get()->IgnoreParenImpCasts()); if (LThrow != RThrow) { Expr *NonThrow = LThrow ? RHS.get() : LHS.get(); VK = NonThrow->getValueKind(); // DR (no number yet): the result is a bit-field if the // non-throw-expression operand is a bit-field. OK = NonThrow->getObjectKind(); return NonThrow->getType(); } // -- Both the second and third operands have type void; the result is of // type void and is a prvalue. if (LVoid && RVoid) return Context.VoidTy; // Neither holds, error. Diag(QuestionLoc, diag::err_conditional_void_nonvoid) << (LVoid ? RTy : LTy) << (LVoid ? 0 : 1) << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // Neither is void. // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and // either has (cv) class type [...] an attempt is made to convert each of // those operands to the type of the other. if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { // These return true if a single direction is already ambiguous. QualType L2RType, R2LType; bool HaveL2R, HaveR2L; if (TryClassUnification(*this, LHS.get(), RHS.get(), QuestionLoc, HaveL2R, L2RType)) return QualType(); if (TryClassUnification(*this, RHS.get(), LHS.get(), QuestionLoc, HaveR2L, R2LType)) return QualType(); // If both can be converted, [...] the program is ill-formed. if (HaveL2R && HaveR2L) { Diag(QuestionLoc, diag::err_conditional_ambiguous) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } // If exactly one conversion is possible, that conversion is applied to // the chosen operand and the converted operands are used in place of the // original operands for the remainder of this section. if (HaveL2R) { if (ConvertForConditional(*this, LHS, L2RType) || LHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); } else if (HaveR2L) { if (ConvertForConditional(*this, RHS, R2LType) || RHS.isInvalid()) return QualType(); RTy = RHS.get()->getType(); } } // C++11 [expr.cond]p3 // if both are glvalues of the same value category and the same type except // for cv-qualification, an attempt is made to convert each of those // operands to the type of the other. ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && Context.hasSameUnqualifiedType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { // Since the unqualified types are reference-related and we require the // result to be as if a reference bound directly, the only conversion // we can perform is to add cv-qualifiers. Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers()); Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers()); if (RCVR.isStrictSupersetOf(LCVR)) { LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); LTy = LHS.get()->getType(); } else if (LCVR.isStrictSupersetOf(RCVR)) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); } } // C++11 [expr.cond]p4 // If the second and third operands are glvalues of the same value // category and have the same type, the result is of that type and // value category and it is a bit-field if the second or the third // operand is a bit-field, or if both are bit-fields. // We only extend this to bitfields, not to the crazy other kinds of // l-values. bool Same = Context.hasSameType(LTy, RTy); if (Same && LVK == RVK && LVK != VK_RValue && LHS.get()->isOrdinaryOrBitFieldObject() && RHS.get()->isOrdinaryOrBitFieldObject()) { VK = LHS.get()->getValueKind(); if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; return LTy; } // C++11 [expr.cond]p5 // Otherwise, the result is a prvalue. If the second and third operands // do not have the same type, and either has (cv) class type, ... if (!Same && (LTy->isRecordType() || RTy->isRecordType())) { // ... overload resolution is used to determine the conversions (if any) // to be applied to the operands. If the overload resolution fails, the // program is ill-formed. if (FindConditionalOverload(*this, LHS, RHS, QuestionLoc)) return QualType(); } // C++11 [expr.cond]p6 // Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); LTy = LHS.get()->getType(); RTy = RHS.get()->getType(); // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result // is of that type. If the operands have class type, the result // is a prvalue temporary of the result type, which is // copy-initialized from either the second operand or the third // operand depending on the value of the first operand. if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. if (RequireNonAbstractType(QuestionLoc, LTy, diag::err_allocation_of_abstract_type)) return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), LHS); if (LHSCopy.isInvalid()) return QualType(); ExprResult RHSCopy = PerformCopyInitialization(Entity, SourceLocation(), RHS); if (RHSCopy.isInvalid()) return QualType(); LHS = LHSCopy; RHS = RHSCopy; } return LTy; } // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) return CheckVectorOperands(LHS, RHS, QuestionLoc, /*isCompAssign*/false, /*AllowBothBool*/true, /*AllowBoolConversions*/false); // -- The second and third operands have arithmetic or enumeration type; // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (ResTy.isNull()) { Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LTy << RTy << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); return ResTy; } // -- The second and third operands have pointer type, or one has pointer // type and the other is a null pointer constant, or both are null // pointer constants, at least one of which is non-integral; pointer // conversions and qualification conversions are performed to bring them // to their composite pointer type. The result is of the composite // pointer type. // -- The second and third operands have pointer to member type, or one has // pointer to member type and the other is a null pointer constant; // pointer to member conversions and qualification conversions are // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. bool NonStandardCompositeType = false; QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS, isSFINAEContext() ? nullptr : &NonStandardCompositeType); if (!Composite.isNull()) { if (NonStandardCompositeType) Diag(QuestionLoc, diag::ext_typecheck_cond_incompatible_operands_nonstandard) << LTy << RTy << Composite << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return Composite; } // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); if (!Composite.isNull()) return Composite; // Check if we are using a null with a non-pointer type. if (DiagnoseConditionalForNull(LHS.get(), RHS.get(), QuestionLoc)) return QualType(); Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands) << LHS.get()->getType() << RHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } /// \brief Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 /// and @p E2 according to C++11 5.9p2. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. /// /// If \p NonStandardCompositeType is non-NULL, then we are permitted to find /// a non-standard (but still sane) composite type to which both expressions /// can be converted. When such a type is chosen, \c *NonStandardCompositeType /// will be set true. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, bool *NonStandardCompositeType) { if (NonStandardCompositeType) *NonStandardCompositeType = false; assert(getLangOpts().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); // C++11 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If // one operand is a null pointer constant, the composite pointer type is // std::nullptr_t if the other operand is also a null pointer constant or, // if the other operand is a pointer, the type of the other operand. if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && !T2->isAnyPointerType() && !T2->isMemberPointerType()) { if (T1->isNullPtrType() && E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); return T1; } if (T2->isNullPtrType() && E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); return T2; } return QualType(); } if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T2->isMemberPointerType()) E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).get(); else E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); return T2; } if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T1->isMemberPointerType()) E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).get(); else E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); return T1; } // Now both have to be pointers or member pointers. if ((!T1->isPointerType() && !T1->isMemberPointerType()) || (!T2->isPointerType() && !T2->isMemberPointerType())) return QualType(); // Otherwise, of one of the operands has type "pointer to cv1 void," then // the other has type "pointer to cv2 T" and the composite pointer type is // "pointer to cv12 void," where cv12 is the union of cv1 and cv2. // Otherwise, the composite pointer type is a pointer type similar to the // type of one of the operands, with a cv-qualification signature that is // the union of the cv-qualification signatures of the operand types. // In practice, the first part here is redundant; it's subsumed by the second. // What we do here is, we build the two possible composite types, and try the // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. // FIXME: extended qualifiers? typedef SmallVector QualifierVector; QualifierVector QualifierUnion; typedef SmallVector, 4> ContainingClassVector; ContainingClassVector MemberOfClass; QualType Composite1 = Context.getCanonicalType(T1), Composite2 = Context.getCanonicalType(T2); unsigned NeedConstBefore = 0; do { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs()) && (Ptr2 = Composite2->getAs())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(nullptr, nullptr)); continue; } const MemberPointerType *MemPtr1, *MemPtr2; if ((MemPtr1 = Composite1->getAs()) && (MemPtr2 = Composite2->getAs())) { Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. if (NonStandardCompositeType && Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), MemPtr2->getClass())); continue; } // FIXME: block pointer types? // Cannot unwrap any more types. break; } while (true); if (NeedConstBefore && NonStandardCompositeType) { // Extension: Add 'const' to qualifiers that come before the first qualifier // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. for (unsigned I = 0; I != NeedConstBefore; ++I) { if ((QualifierUnion[I] & Qualifiers::Const) == 0) { QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; *NonStandardCompositeType = true; } } } // Rewrap the composites as pointers or member pointers with the union CVRs. ContainingClassVector::reverse_iterator MOC = MemberOfClass.rbegin(); for (QualifierVector::reverse_iterator I = QualifierUnion.rbegin(), E = QualifierUnion.rend(); I != E; (void)++I, ++MOC) { Qualifiers Quals = Qualifiers::fromCVRMask(*I); if (MOC->first && MOC->second) { // Rebuild member pointer type Composite1 = Context.getMemberPointerType( Context.getQualifiedType(Composite1, Quals), MOC->first); Composite2 = Context.getMemberPointerType( Context.getQualifiedType(Composite2, Quals), MOC->second); } else { // Rebuild pointer type Composite1 = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); Composite2 = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); } } // Try to convert to the first composite pointer type. InitializedEntity Entity1 = InitializedEntity::InitializeTemporary(Composite1); InitializationKind Kind = InitializationKind::CreateCopy(Loc, SourceLocation()); InitializationSequence E1ToC1(*this, Entity1, Kind, E1); InitializationSequence E2ToC1(*this, Entity1, Kind, E2); if (E1ToC1 && E2ToC1) { // Conversion to Composite1 is viable. if (!Context.hasSameType(Composite1, Composite2)) { // Composite2 is a different type from Composite1. Check whether // Composite2 is also viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); InitializationSequence E1ToC2(*this, Entity2, Kind, E1); InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (E1ToC2 && E2ToC2) { // Both Composite1 and Composite2 are viable and are different; // this is an ambiguity. return QualType(); } } // Convert E1 to Composite1 ExprResult E1Result = E1ToC1.Perform(*this, Entity1, Kind, E1); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.getAs(); // Convert E2 to Composite1 ExprResult E2Result = E2ToC1.Perform(*this, Entity1, Kind, E2); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.getAs(); return Composite1; } // Check whether Composite2 is viable. InitializedEntity Entity2 = InitializedEntity::InitializeTemporary(Composite2); InitializationSequence E1ToC2(*this, Entity2, Kind, E1); InitializationSequence E2ToC2(*this, Entity2, Kind, E2); if (!E1ToC2 || !E2ToC2) return QualType(); // Convert E1 to Composite2 ExprResult E1Result = E1ToC2.Perform(*this, Entity2, Kind, E1); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.getAs(); // Convert E2 to Composite2 ExprResult E2Result = E2ToC2.Perform(*this, Entity2, Kind, E2); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.getAs(); return Composite2; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!E) return ExprError(); assert(!isa(E) && "Double-bound temporary?"); // If the result is a glvalue, we shouldn't bind it. if (!E->isRValue()) return E; // In ARC, calls that return a retainable type can return retained, // in which case we have to insert a consuming cast. if (getLangOpts().ObjCAutoRefCount && E->getType()->isObjCRetainableType()) { bool ReturnsRetained; // For actual calls, we compute this by examining the type of the // called value. if (CallExpr *Call = dyn_cast(E)) { Expr *Callee = Call->getCallee()->IgnoreParens(); QualType T = Callee->getType(); if (T == Context.BoundMemberTy) { // Handle pointer-to-members. if (BinaryOperator *BinOp = dyn_cast(Callee)) T = BinOp->getRHS()->getType(); else if (MemberExpr *Mem = dyn_cast(Callee)) T = Mem->getMemberDecl()->getType(); } if (const PointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const BlockPointerType *Ptr = T->getAs()) T = Ptr->getPointeeType(); else if (const MemberPointerType *MemPtr = T->getAs()) T = MemPtr->getPointeeType(); const FunctionType *FTy = T->getAs(); assert(FTy && "call to value not of function type?"); ReturnsRetained = FTy->getExtInfo().getProducesResult(); // ActOnStmtExpr arranges things so that StmtExprs of retainable // type always produce a +1 object. } else if (isa(E)) { ReturnsRetained = true; // We hit this case with the lambda conversion-to-block optimization; // we don't want any extra casts here. } else if (isa(E) && isa(cast(E)->getSubExpr())) { return E; // For message sends and property references, we try to find an // actual method. FIXME: we should infer retention by selector in // cases where we don't have an actual method. } else { ObjCMethodDecl *D = nullptr; if (ObjCMessageExpr *Send = dyn_cast(E)) { D = Send->getMethodDecl(); } else if (ObjCBoxedExpr *BoxedExpr = dyn_cast(E)) { D = BoxedExpr->getBoxingMethod(); } else if (ObjCArrayLiteral *ArrayLit = dyn_cast(E)) { D = ArrayLit->getArrayWithObjectsMethod(); } else if (ObjCDictionaryLiteral *DictLit = dyn_cast(E)) { D = DictLit->getDictWithObjectsMethod(); } ReturnsRetained = (D && D->hasAttr()); // Don't do reclaims on performSelector calls; despite their // return type, the invoked method doesn't necessarily actually // return an object. if (!ReturnsRetained && D && D->getMethodFamily() == OMF_performSelector) return E; } // Don't reclaim an object of Class type. if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType()) return E; Cleanup.setExprNeedsCleanups(true); CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject : CK_ARCReclaimReturnedObject); return ImplicitCastExpr::Create(Context, E->getType(), ck, E, nullptr, VK_RValue); } if (!getLangOpts().CPlusPlus) return E; // Search for the base element type (cf. ASTContext::getBaseElementType) with // a fast path for the common case that the type is directly a RecordType. const Type *T = Context.getCanonicalType(E->getType().getTypePtr()); const RecordType *RT = nullptr; while (!RT) { switch (T->getTypeClass()) { case Type::Record: RT = cast(T); break; case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: case Type::DependentSizedArray: T = cast(T)->getElementType().getTypePtr(); break; default: return E; } } // That should be enough to guarantee that this type is complete, if we're // not processing a decltype expression. CXXRecordDecl *RD = cast(RT->getDecl()); if (RD->isInvalidDecl() || RD->isDependentContext()) return E; bool IsDecltype = ExprEvalContexts.back().IsDecltype; CXXDestructorDecl *Destructor = IsDecltype ? nullptr : LookupDestructor(RD); if (Destructor) { MarkFunctionReferenced(E->getExprLoc(), Destructor); CheckDestructorAccess(E->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << E->getType()); if (DiagnoseUseOfDecl(Destructor, E->getExprLoc())) return ExprError(); // If destructor is trivial, we can avoid the extra copy. if (Destructor->isTrivial()) return E; // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); CXXBindTemporaryExpr *Bind = CXXBindTemporaryExpr::Create(Context, Temp, E); if (IsDecltype) ExprEvalContexts.back().DelayedDecltypeBinds.push_back(Bind); return Bind; } ExprResult Sema::MaybeCreateExprWithCleanups(ExprResult SubExpr) { if (SubExpr.isInvalid()) return ExprError(); return MaybeCreateExprWithCleanups(SubExpr.get()); } Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { assert(SubExpr && "subexpression can't be null!"); CleanupVarDeclMarking(); unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects; assert(ExprCleanupObjects.size() >= FirstCleanup); assert(Cleanup.exprNeedsCleanups() || ExprCleanupObjects.size() == FirstCleanup); if (!Cleanup.exprNeedsCleanups()) return SubExpr; auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, ExprCleanupObjects.size() - FirstCleanup); auto *E = ExprWithCleanups::Create( Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups); DiscardCleanupsInEvaluationContext(); return E; } Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { assert(SubStmt && "sub-statement can't be null!"); CleanupVarDeclMarking(); if (!Cleanup.exprNeedsCleanups()) return SubStmt; // FIXME: In order to attach the temporaries, wrap the statement into // a StmtExpr; currently this is only used for asm statements. // This is hacky, either create a new CXXStmtWithTemporaries statement or // a new AsmStmtWithTemporaries. CompoundStmt *CompStmt = new (Context) CompoundStmt(Context, SubStmt, SourceLocation(), SourceLocation()); Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation()); return MaybeCreateExprWithCleanups(E); } /// Process the expression contained within a decltype. For such expressions, /// certain semantic checks on temporaries are delayed until this point, and /// are omitted for the 'topmost' call in the decltype expression. If the /// topmost call bound a temporary, strip that temporary off the expression. ExprResult Sema::ActOnDecltypeExpression(Expr *E) { assert(ExprEvalContexts.back().IsDecltype && "not in a decltype expression"); // C++11 [expr.call]p11: // If a function call is a prvalue of object type, // -- if the function call is either // -- the operand of a decltype-specifier, or // -- the right operand of a comma operator that is the operand of a // decltype-specifier, // a temporary object is not introduced for the prvalue. // Recursively rebuild ParenExprs and comma expressions to strip out the // outermost CXXBindTemporaryExpr, if any. if (ParenExpr *PE = dyn_cast(E)) { ExprResult SubExpr = ActOnDecltypeExpression(PE->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); if (SubExpr.get() == PE->getSubExpr()) return E; return ActOnParenExpr(PE->getLParen(), PE->getRParen(), SubExpr.get()); } if (BinaryOperator *BO = dyn_cast(E)) { if (BO->getOpcode() == BO_Comma) { ExprResult RHS = ActOnDecltypeExpression(BO->getRHS()); if (RHS.isInvalid()) return ExprError(); if (RHS.get() == BO->getRHS()) return E; return new (Context) BinaryOperator( BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), BO->getObjectKind(), BO->getOperatorLoc(), BO->isFPContractable()); } } CXXBindTemporaryExpr *TopBind = dyn_cast(E); CallExpr *TopCall = TopBind ? dyn_cast(TopBind->getSubExpr()) : nullptr; if (TopCall) E = TopCall; else TopBind = nullptr; // Disable the special decltype handling now. ExprEvalContexts.back().IsDecltype = false; // In MS mode, don't perform any extra checking of call return types within a // decltype expression. if (getLangOpts().MSVCCompat) return E; // Perform the semantic checks we delayed until this point. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeCalls.size(); I != N; ++I) { CallExpr *Call = ExprEvalContexts.back().DelayedDecltypeCalls[I]; if (Call == TopCall) continue; if (CheckCallReturnType(Call->getCallReturnType(Context), Call->getLocStart(), Call, Call->getDirectCallee())) return ExprError(); } // Now all relevant types are complete, check the destructors are accessible // and non-deleted, and annotate them on the temporaries. for (unsigned I = 0, N = ExprEvalContexts.back().DelayedDecltypeBinds.size(); I != N; ++I) { CXXBindTemporaryExpr *Bind = ExprEvalContexts.back().DelayedDecltypeBinds[I]; if (Bind == TopBind) continue; CXXTemporary *Temp = Bind->getTemporary(); CXXRecordDecl *RD = Bind->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); CXXDestructorDecl *Destructor = LookupDestructor(RD); Temp->setDestructor(Destructor); MarkFunctionReferenced(Bind->getExprLoc(), Destructor); CheckDestructorAccess(Bind->getExprLoc(), Destructor, PDiag(diag::err_access_dtor_temp) << Bind->getType()); if (DiagnoseUseOfDecl(Destructor, Bind->getExprLoc())) return ExprError(); // We need a cleanup, but we don't need to remember the temporary. Cleanup.setExprNeedsCleanups(true); } // Possibly strip off the top CXXBindTemporaryExpr. return E; } /// Note a set of 'operator->' functions that were used for a member access. static void noteOperatorArrows(Sema &S, ArrayRef OperatorArrows) { unsigned SkipStart = OperatorArrows.size(), SkipCount = 0; // FIXME: Make this configurable? unsigned Limit = 9; if (OperatorArrows.size() > Limit) { // Produce Limit-1 normal notes and one 'skipping' note. SkipStart = (Limit - 1) / 2 + (Limit - 1) % 2; SkipCount = OperatorArrows.size() - (Limit - 1); } for (unsigned I = 0; I < OperatorArrows.size(); /**/) { if (I == SkipStart) { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrows_suppressed) << SkipCount; I += SkipCount; } else { S.Diag(OperatorArrows[I]->getLocation(), diag::note_operator_arrow_here) << OperatorArrows[I]->getCallResultType(); ++I; } } } ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, ParsedType &ObjectType, bool &MayBePseudoDestructor) { // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); Result = CheckPlaceholderExpr(Base); if (Result.isInvalid()) return ExprError(); Base = Result.get(); QualType BaseType = Base->getType(); MayBePseudoDestructor = false; if (BaseType->isDependentType()) { // If we have a pointer to a dependent type and are using the -> operator, // the object type is the type that the pointer points to. We might still // have enough information about that type to do something useful. if (OpKind == tok::arrow) if (const PointerType *Ptr = BaseType->getAs()) BaseType = Ptr->getPointeeType(); ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } // C++ [over.match.oper]p8: // [...] When operator->returns, the operator-> is applied to the value // returned, with the original second operand. if (OpKind == tok::arrow) { QualType StartingType = BaseType; bool NoArrowOperatorFound = false; bool FirstIteration = true; FunctionDecl *CurFD = dyn_cast(CurContext); // The set of types we've considered so far. llvm::SmallPtrSet CTypes; SmallVector OperatorArrows; CTypes.insert(Context.getCanonicalType(BaseType)); while (BaseType->isRecordType()) { if (OperatorArrows.size() >= getLangOpts().ArrowDepth) { Diag(OpLoc, diag::err_operator_arrow_depth_exceeded) << StartingType << getLangOpts().ArrowDepth << Base->getSourceRange(); noteOperatorArrows(*this, OperatorArrows); Diag(OpLoc, diag::note_operator_arrow_depth) << getLangOpts().ArrowDepth; return ExprError(); } Result = BuildOverloadedArrowExpr( S, Base, OpLoc, // When in a template specialization and on the first loop iteration, // potentially give the default diagnostic (with the fixit in a // separate note) instead of having the error reported back to here // and giving a diagnostic with a fixit attached to the error itself. (FirstIteration && CurFD && CurFD->isFunctionTemplateSpecialization()) ? nullptr : &NoArrowOperatorFound); if (Result.isInvalid()) { if (NoArrowOperatorFound) { if (FirstIteration) { Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << BaseType << 1 << Base->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "."); OpKind = tok::period; break; } Diag(OpLoc, diag::err_typecheck_member_reference_arrow) << BaseType << Base->getSourceRange(); CallExpr *CE = dyn_cast(Base); if (Decl *CD = (CE ? CE->getCalleeDecl() : nullptr)) { Diag(CD->getLocStart(), diag::note_member_reference_arrow_from_operator_arrow); } } return ExprError(); } Base = Result.get(); if (CXXOperatorCallExpr *OpCall = dyn_cast(Base)) OperatorArrows.push_back(OpCall->getDirectCallee()); BaseType = Base->getType(); CanQualType CBaseType = Context.getCanonicalType(BaseType); if (!CTypes.insert(CBaseType).second) { Diag(OpLoc, diag::err_operator_arrow_circular) << StartingType; noteOperatorArrows(*this, OperatorArrows); return ExprError(); } FirstIteration = false; } if (OpKind == tok::arrow && (BaseType->isPointerType() || BaseType->isObjCObjectPointerType())) BaseType = BaseType->getPointeeType(); } // Objective-C properties allow "." access on Objective-C pointer types, // so adjust the base type to the object type itself. if (BaseType->isObjCObjectPointerType()) BaseType = BaseType->getPointeeType(); // C++ [basic.lookup.classref]p2: // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete // postfix-expression. // // This also indicates that we could be parsing a pseudo-destructor-name. // Note that Objective-C class and object types can be pseudo-destructor // expressions or normal member (ivar or property) access expressions, and // it's legal for the type to be incomplete if this is a pseudo-destructor // call. We'll do more incomplete-type checks later in the lookup process, // so just skip this check for ObjC types. if (BaseType->isObjCObjectOrInterfaceType()) { ObjectType = ParsedType::make(BaseType); MayBePseudoDestructor = true; return Base; } else if (!BaseType->isRecordType()) { ObjectType = nullptr; MayBePseudoDestructor = true; return Base; } // The object type must be complete (or dependent), or // C++11 [expr.prim.general]p3: // Unlike the object expression in other contexts, *this is not required to // be of complete type for purposes of class member access (5.2.5) outside // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && RequireCompleteType(OpLoc, BaseType, diag::err_incomplete_member_access)) return ExprError(); // C++ [basic.lookup.classref]p2: // If the id-expression in a class member access (5.2.5) is an // unqualified-id, and the type of the object expression is of a class // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = ParsedType::make(BaseType); return Base; } static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, tok::TokenKind& OpKind, SourceLocation OpLoc) { if (Base->hasPlaceholderType()) { ExprResult result = S.CheckPlaceholderExpr(Base); if (result.isInvalid()) return true; Base = result.get(); } ObjectType = Base->getType(); // C++ [expr.pseudo]p2: // The left-hand side of the dot operator shall be of scalar type. The // left-hand side of the arrow operator shall be of pointer to scalar type. // This scalar type is the object type. // Note that this is rather different from the normal handling for the // arrow operator. if (OpKind == tok::arrow) { if (const PointerType *Ptr = ObjectType->getAs()) { ObjectType = Ptr->getPointeeType(); } else if (!Base->isTypeDependent()) { // The user wrote "p->" when they probably meant "p."; fix it. S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true << FixItHint::CreateReplacement(OpLoc, "."); if (S.isSFINAEContext()) return true; OpKind = tok::period; } } return false; } ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, const CXXScopeSpec &SS, TypeSourceInfo *ScopeTypeInfo, SourceLocation CCLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage Destructed) { TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo(); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); if (!ObjectType->isDependentType() && !ObjectType->isScalarType() && !ObjectType->isVectorType()) { if (getLangOpts().MSVCCompat && ObjectType->isVoidType()) Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange(); else { Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar) << ObjectType << Base->getSourceRange(); return ExprError(); } } // C++ [expr.pseudo]p2: // [...] The cv-unqualified versions of the object type and of the type // designated by the pseudo-destructor-name shall be the same type. if (DestructedTypeInfo) { QualType DestructedType = DestructedTypeInfo->getType(); SourceLocation DestructedTypeStart = DestructedTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(); if (!DestructedType->isDependentType() && !ObjectType->isDependentType()) { if (!Context.hasSameUnqualifiedType(DestructedType, ObjectType)) { Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { // Okay: just pretend that the user provided the correctly-qualified // type. } else { Diag(DestructedTypeStart, diag::err_arc_pseudo_dtor_inconstant_quals) << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); } // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } } } // C++ [expr.pseudo]p2: // [...] Furthermore, the two type-names in a pseudo-destructor-name of the // form // // ::[opt] nested-name-specifier[opt] type-name :: ~ type-name // // shall designate the same scalar type. if (ScopeTypeInfo) { QualType ScopeType = ScopeTypeInfo->getType(); if (!ScopeType->isDependentType() && !ObjectType->isDependentType() && !Context.hasSameUnqualifiedType(ScopeType, ObjectType)) { Diag(ScopeTypeInfo->getTypeLoc().getLocalSourceRange().getBegin(), diag::err_pseudo_dtor_type_mismatch) << ObjectType << ScopeType << Base->getSourceRange() << ScopeTypeInfo->getTypeLoc().getLocalSourceRange(); ScopeType = QualType(); ScopeTypeInfo = nullptr; } } Expr *Result = new (Context) CXXPseudoDestructorExpr(Context, Base, OpKind == tok::arrow, OpLoc, SS.getWithLocInContext(Context), ScopeTypeInfo, CCLoc, TildeLoc, Destructed); return Result; } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, CXXScopeSpec &SS, UnqualifiedId &FirstTypeName, SourceLocation CCLoc, SourceLocation TildeLoc, UnqualifiedId &SecondTypeName) { assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) && "Invalid first type name in pseudo-destructor"); assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId || SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) && "Invalid second type name in pseudo-destructor"); QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); // Compute the object type that we should use for name lookup purposes. Only // record types and dependent types matter. ParsedType ObjectTypePtrForLookup; if (!SS.isSet()) { if (ObjectType->isRecordType()) ObjectTypePtrForLookup = ParsedType::make(ObjectType); else if (ObjectType->isDependentType()) ObjectTypePtrForLookup = ParsedType::make(Context.DependentTy); } // Convert the name of the type being destructed (following the ~) into a // type (with source-location information). QualType DestructedType; TypeSourceInfo *DestructedTypeInfo = nullptr; PseudoDestructorTypeStorage Destructed; if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) { ParsedType T = getTypeName(*SecondTypeName.Identifier, SecondTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup); if (!T && ((SS.isSet() && !computeDeclContext(SS, false)) || (!SS.isSet() && ObjectType->isDependentType()))) { // The name of the type being destroyed is a dependent name, and we // couldn't find anything useful in scope. Just store the identifier and // it's location, and we'll perform (qualified) name lookup again at // template instantiation time. Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier, SecondTypeName.StartLocation); } else if (!T) { Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << SecondTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T, &DestructedTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); if (T.isInvalid() || !T.get()) { // Recover by assuming we had the right type all along. DestructedType = ObjectType; } else DestructedType = GetTypeFromParser(T.get(), &DestructedTypeInfo); } // If we've performed some kind of recovery, (re-)build the type source // information. if (!DestructedType.isNull()) { if (!DestructedTypeInfo) DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType, SecondTypeName.StartLocation); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); } // Convert the name of the scope type (the type prior to '::') into a type. TypeSourceInfo *ScopeTypeInfo = nullptr; QualType ScopeType; if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || FirstTypeName.Identifier) { if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) { ParsedType T = getTypeName(*FirstTypeName.Identifier, FirstTypeName.StartLocation, S, &SS, true, false, ObjectTypePtrForLookup); if (!T) { Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_destructor_non_type) << FirstTypeName.Identifier << ObjectType; if (isSFINAEContext()) return ExprError(); // Just drop this type. It's unnecessary anyway. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T, &ScopeTypeInfo); } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->TemplateNameLoc, TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); if (T.isInvalid() || !T.get()) { // Recover by dropping this type. ScopeType = QualType(); } else ScopeType = GetTypeFromParser(T.get(), &ScopeTypeInfo); } } if (!ScopeType.isNull() && !ScopeTypeInfo) ScopeTypeInfo = Context.getTrivialTypeSourceInfo(ScopeType, FirstTypeName.StartLocation); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, SS, ScopeTypeInfo, CCLoc, TildeLoc, Destructed); } ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, SourceLocation TildeLoc, const DeclSpec& DS) { QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc(), false); TypeLocBuilder TLB; DecltypeTypeLoc DecltypeTL = TLB.push(T); DecltypeTL.setNameLoc(DS.getTypeSpecTypeLoc()); TypeSourceInfo *DestructedTypeInfo = TLB.getTypeSourceInfo(Context, T); PseudoDestructorTypeStorage Destructed(DestructedTypeInfo); return BuildPseudoDestructorExpr(Base, OpLoc, OpKind, CXXScopeSpec(), nullptr, SourceLocation(), TildeLoc, Destructed); } ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, CXXConversionDecl *Method, bool HadMultipleCandidates) { if (Method->getParent()->isLambda() && Method->getConversionType()->isBlockPointerType()) { // This is a lambda coversion to block pointer; check if the argument // is a LambdaExpr. Expr *SubE = E; CastExpr *CE = dyn_cast(SubE); if (CE && CE->getCastKind() == CK_NoOp) SubE = CE->getSubExpr(); SubE = SubE->IgnoreParens(); if (CXXBindTemporaryExpr *BE = dyn_cast(SubE)) SubE = BE->getSubExpr(); if (isa(SubE)) { // For the conversion to block pointer on a lambda expression, we // construct a special BlockLiteral instead; this doesn't really make // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext(PotentiallyEvaluated); ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(), E->getExprLoc(), Method, E); PopExpressionEvaluationContext(); if (Exp.isInvalid()) Diag(E->getExprLoc(), diag::note_lambda_to_block_conv); return Exp; } } ExprResult Exp = PerformObjectArgumentInitialization(E, /*Qualifier=*/nullptr, FoundDecl, Method); if (Exp.isInvalid()) return true; MemberExpr *ME = new (Context) MemberExpr( Exp.get(), /*IsArrow=*/false, SourceLocation(), Method, SourceLocation(), Context.BoundMemberTy, VK_RValue, OK_Ordinary); if (HadMultipleCandidates) ME->setHadMultipleCandidates(true); MarkMemberReferenced(ME); QualType ResultType = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultType); ResultType = ResultType.getNonLValueExprType(Context); CXXMemberCallExpr *CE = new (Context) CXXMemberCallExpr(Context, ME, None, ResultType, VK, Exp.get()->getLocEnd()); return CE; } ExprResult Sema::BuildCXXNoexceptExpr(SourceLocation KeyLoc, Expr *Operand, SourceLocation RParen) { // If the operand is an unresolved lookup expression, the expression is ill- // formed per [over.over]p1, because overloaded function names cannot be used // without arguments except in explicit contexts. ExprResult R = CheckPlaceholderExpr(Operand); if (R.isInvalid()) return R; // The operand may have been modified when checking the placeholder type. Operand = R.get(); if (ActiveTemplateInstantiations.empty() && Operand->HasSideEffects(Context, false)) { // The expression operand for noexcept is in an unevaluated expression // context, so side effects could result in unintended consequences. Diag(Operand->getExprLoc(), diag::warn_side_effects_unevaluated_context); } CanThrowResult CanThrow = canThrow(Operand); return new (Context) CXXNoexceptExpr(Context.BoolTy, Operand, CanThrow, KeyLoc, RParen); } ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, Expr *Operand, SourceLocation RParen) { return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } static bool IsSpecialDiscardedValue(Expr *E) { // In C++11, discarded-value expressions of a certain form are special, // according to [expr]p10: // The lvalue-to-rvalue conversion (4.1) is applied only if the // expression is an lvalue of volatile-qualified type and it has // one of the following forms: E = E->IgnoreParens(); // - id-expression (5.1.1), if (isa(E)) return true; // - subscripting (5.2.1), if (isa(E)) return true; // - class member access (5.2.5), if (isa(E)) return true; // - indirection (5.3.1), if (UnaryOperator *UO = dyn_cast(E)) if (UO->getOpcode() == UO_Deref) return true; if (BinaryOperator *BO = dyn_cast(E)) { // - pointer-to-member operation (5.5), if (BO->isPtrMemOp()) return true; // - comma expression (5.18) where the right operand is one of the above. if (BO->getOpcode() == BO_Comma) return IsSpecialDiscardedValue(BO->getRHS()); } // - conditional expression (5.16) where both the second and the third // operands are one of the above, or if (ConditionalOperator *CO = dyn_cast(E)) return IsSpecialDiscardedValue(CO->getTrueExpr()) && IsSpecialDiscardedValue(CO->getFalseExpr()); // The related edge case of "*x ?: *x". if (BinaryConditionalOperator *BCO = dyn_cast(E)) { if (OpaqueValueExpr *OVE = dyn_cast(BCO->getTrueExpr())) return IsSpecialDiscardedValue(OVE->getSourceExpr()) && IsSpecialDiscardedValue(BCO->getFalseExpr()); } // Objective-C++ extensions to the rule. if (isa(E) || isa(E)) return true; return false; } /// Perform the conversions required for an expression used in a /// context that ignores the result. ExprResult Sema::IgnoredValueConversions(Expr *E) { if (E->hasPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(E); if (result.isInvalid()) return E; E = result.get(); } // C99 6.3.2.1: // [Except in specific positions,] an lvalue that does not have // array type is converted to the value stored in the // designated object (and is no longer an lvalue). if (E->isRValue()) { // In C, function designators (i.e. expressions of function type) // are r-values, but we still want to do function-to-pointer decay // on them. This is both technically correct and convenient for // some clients. if (!getLangOpts().CPlusPlus && E->getType()->isFunctionType()) return DefaultFunctionArrayConversion(E); return E; } if (getLangOpts().CPlusPlus) { // The C++11 standard defines the notion of a discarded-value expression; // normally, we don't need to do anything to handle it, but if it is a // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. if (getLangOpts().CPlusPlus11 && E->isGLValue() && E->getType().isVolatileQualified() && IsSpecialDiscardedValue(E)) { ExprResult Res = DefaultLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); } return E; } // GCC seems to also exclude expressions of incomplete enum type. if (const EnumType *T = E->getType()->getAs()) { if (!T->getDecl()->isComplete()) { // FIXME: stupid workaround for a codegen bug! E = ImpCastExprToType(E, Context.VoidTy, CK_ToVoid).get(); return E; } } ExprResult Res = DefaultFunctionArrayLvalueConversion(E); if (Res.isInvalid()) return E; E = Res.get(); if (!E->getType()->isVoidType()) RequireCompleteType(E->getExprLoc(), E->getType(), diag::err_incomplete_type); return E; } // If we can unambiguously determine whether Var can never be used // in a constant expression, return true. // - if the variable and its initializer are non-dependent, then // we can unambiguously check if the variable is a constant expression. // - if the initializer is not value dependent - we can determine whether // it can be used to initialize a constant expression. If Init can not // be used to initialize a constant expression we conclude that Var can // never be a constant expression. // - FXIME: if the initializer is dependent, we can still do some analysis and // identify certain cases unambiguously as non-const by using a Visitor: // - such as those that involve odr-use of a ParmVarDecl, involve a new // delete, lambda-expr, dynamic-cast, reinterpret-cast etc... static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, ASTContext &Context) { if (isa(Var)) return true; const VarDecl *DefVD = nullptr; // If there is no initializer - this can not be a constant expression. if (!Var->getAnyInitializer(DefVD)) return true; assert(DefVD); if (DefVD->isWeak()) return false; EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt(); Expr *Init = cast(Eval->Value); if (Var->getType()->isDependentType() || Init->isValueDependent()) { // FIXME: Teach the constant evaluator to deal with the non-dependent parts // of value-dependent expressions, and use it here to determine whether the // initializer is a potential constant expression. return false; } return !IsVariableAConstantExpression(Var, Context); } /// \brief Check if the current lambda has any potential captures /// that must be captured by any of its enclosing lambdas that are ready to /// capture. If there is a lambda that can capture a nested /// potential-capture, go ahead and do so. Also, check to see if any /// variables are uncaptureable or do not involve an odr-use so do not /// need to be captured. static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { assert(!S.isUnevaluatedContext()); assert(S.CurContext->isDependentContext()); #ifndef NDEBUG DeclContext *DC = S.CurContext; while (DC && isa(DC)) DC = DC->getParent(); assert( CurrentLSI->CallOperator == DC && "The current call operator must be synchronized with Sema's CurContext"); #endif // NDEBUG const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); ArrayRef FunctionScopesArrayRef( S.FunctionScopes.data(), S.FunctionScopes.size()); // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. const unsigned NumPotentialCaptures = CurrentLSI->getNumPotentialVariableCaptures(); for (unsigned I = 0; I != NumPotentialCaptures; ++I) { Expr *VarExpr = nullptr; VarDecl *Var = nullptr; CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr); // If the variable is clearly identified as non-odr-used and the full // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. // For e.g.: // Even though 'x' is not odr-used, it should be captured. // int test() { // const int x = 10; // auto L = [=](auto a) { // (void) +x + a; // }; // } if (CurrentLSI->isVariableExprMarkedAsNonODRUsed(VarExpr) && !IsFullExprInstantiationDependent) continue; // If we have a capture-capable lambda for the variable, go ahead and // capture the variable in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( FunctionScopesArrayRef, Var, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S, &FunctionScopeIndexOfCapturableLambda); } const bool IsVarNeverAConstantExpression = VariableCanNeverBeAConstantExpression(Var, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable // can not be used in a constant expression - which means // this variable must be odr-used here, so diagnose a // capture violation early, if the variable is un-captureable. // This is purely for diagnosing errors early. Otherwise, this // error would get diagnosed when the lambda becomes capture ready. QualType CaptureType, DeclRefType; SourceLocation ExprLoc = VarExpr->getExprLoc(); if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/false, CaptureType, DeclRefType, nullptr)) { // We will never be able to capture this variable, and we need // to be able to in any and all instantiations, so diagnose it. S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, /*EllipsisLoc*/ SourceLocation(), /*BuildAndDiagnose*/true, CaptureType, DeclRefType, nullptr); } } } // Check if 'this' needs to be captured. if (CurrentLSI->hasPotentialThisCapture()) { // If we have a capture-capable lambda for 'this', go ahead and capture // 'this' in that lambda (and all its enclosing lambdas). if (const Optional Index = getStackIndexOfNearestEnclosingCaptureCapableLambda( FunctionScopesArrayRef, /*0 is 'this'*/ nullptr, S)) { const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); S.CheckCXXThisCapture(CurrentLSI->PotentialThisCaptureLocation, /*Explicit*/ false, /*BuildAndDiagnose*/ true, &FunctionScopeIndexOfCapturableLambda); } } // Reset all the potential captures at the end of each full-expression. CurrentLSI->clearPotentialCaptures(); } static ExprResult attemptRecovery(Sema &SemaRef, const TypoCorrectionConsumer &Consumer, const TypoCorrection &TC) { LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), Consumer.getLookupResult().getLookupKind()); const CXXScopeSpec *SS = Consumer.getSS(); CXXScopeSpec NewSS; // Use an approprate CXXScopeSpec for building the expr. if (auto *NNS = TC.getCorrectionSpecifier()) NewSS.MakeTrivial(SemaRef.Context, NNS, TC.getCorrectionRange()); else if (SS && !TC.WillReplaceSpecifier()) NewSS = *SS; if (auto *ND = TC.getFoundDecl()) { R.setLookupName(ND->getDeclName()); R.addDecl(ND); if (ND->isCXXClassMember()) { // Figure out the correct naming class to add to the LookupResult. CXXRecordDecl *Record = nullptr; if (auto *NNS = TC.getCorrectionSpecifier()) Record = NNS->getAsType()->getAsCXXRecordDecl(); if (!Record) Record = dyn_cast(ND->getDeclContext()->getRedeclContext()); if (Record) R.setNamingClass(Record); // Detect and handle the case where the decl might be an implicit // member. bool MightBeImplicitMember; if (!Consumer.isAddressOfOperand()) MightBeImplicitMember = true; else if (!NewSS.isEmpty()) MightBeImplicitMember = false; else if (R.isOverloadedResult()) MightBeImplicitMember = false; else if (R.isUnresolvableResult()) MightBeImplicitMember = true; else MightBeImplicitMember = isa(ND) || isa(ND) || isa(ND); if (MightBeImplicitMember) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, /*TemplateArgs*/ nullptr, /*S*/ nullptr); } else if (auto *Ivar = dyn_cast(ND)) { return SemaRef.LookupInObjCMethod(R, Consumer.getScope(), Ivar->getIdentifier()); } } return SemaRef.BuildDeclarationNameExpr(NewSS, R, /*NeedsADL*/ false, /*AcceptInvalidDecl*/ true); } namespace { class FindTypoExprs : public RecursiveASTVisitor { llvm::SmallSetVector &TypoExprs; public: explicit FindTypoExprs(llvm::SmallSetVector &TypoExprs) : TypoExprs(TypoExprs) {} bool VisitTypoExpr(TypoExpr *TE) { TypoExprs.insert(TE); return true; } }; class TransformTypos : public TreeTransform { typedef TreeTransform BaseTransform; VarDecl *InitDecl; // A decl to avoid as a correction because it is in the // process of being initialized. llvm::function_ref ExprFilter; llvm::SmallSetVector TypoExprs, AmbiguousTypoExprs; llvm::SmallDenseMap TransformCache; llvm::SmallDenseMap OverloadResolution; /// \brief Emit diagnostics for all of the TypoExprs encountered. /// If the TypoExprs were successfully corrected, then the diagnostics should /// suggest the corrections. Otherwise the diagnostics will not suggest /// anything (having been passed an empty TypoCorrection). void EmitAllDiagnostics() { for (auto E : TypoExprs) { TypoExpr *TE = cast(E); auto &State = SemaRef.getTypoExprState(TE); if (State.DiagHandler) { TypoCorrection TC = State.Consumer->getCurrentCorrection(); ExprResult Replacement = TransformCache[TE]; // Extract the NamedDecl from the transformed TypoExpr and add it to the // TypoCorrection, replacing the existing decls. This ensures the right // NamedDecl is used in diagnostics e.g. in the case where overload // resolution was used to select one from several possible decls that // had been stored in the TypoCorrection. if (auto *ND = getDeclFromExpr( Replacement.isInvalid() ? nullptr : Replacement.get())) TC.setCorrectionDecl(ND); State.DiagHandler(TC); } SemaRef.clearDelayedTypo(TE); } } /// \brief If corrections for the first TypoExpr have been exhausted for a /// given combination of the other TypoExprs, retry those corrections against /// the next combination of substitutions for the other TypoExprs by advancing /// to the next potential correction of the second TypoExpr. For the second /// and subsequent TypoExprs, if its stream of corrections has been exhausted, /// the stream is reset and the next TypoExpr's stream is advanced by one (a /// TypoExpr's correction stream is advanced by removing the TypoExpr from the /// TransformCache). Returns true if there is still any untried combinations /// of corrections. bool CheckAndAdvanceTypoExprCorrectionStreams() { for (auto TE : TypoExprs) { auto &State = SemaRef.getTypoExprState(TE); TransformCache.erase(TE); if (!State.Consumer->finished()) return true; State.Consumer->resetCorrectionStream(); } return false; } NamedDecl *getDeclFromExpr(Expr *E) { if (auto *OE = dyn_cast_or_null(E)) E = OverloadResolution[OE]; if (!E) return nullptr; if (auto *DRE = dyn_cast(E)) return DRE->getFoundDecl(); if (auto *ME = dyn_cast(E)) return ME->getFoundDecl(); // FIXME: Add any other expr types that could be be seen by the delayed typo // correction TreeTransform for which the corresponding TypoCorrection could // contain multiple decls. return nullptr; } ExprResult TryTransform(Expr *E) { Sema::SFINAETrap Trap(SemaRef); ExprResult Res = TransformExpr(E); if (Trap.hasErrorOccurred() || Res.isInvalid()) return ExprError(); return ExprFilter(Res.get()); } public: TransformTypos(Sema &SemaRef, VarDecl *InitDecl, llvm::function_ref Filter) : BaseTransform(SemaRef), InitDecl(InitDecl), ExprFilter(Filter) {} ExprResult RebuildCallExpr(Expr *Callee, SourceLocation LParenLoc, MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig = nullptr) { auto Result = BaseTransform::RebuildCallExpr(Callee, LParenLoc, Args, RParenLoc, ExecConfig); if (auto *OE = dyn_cast(Callee)) { if (Result.isUsable()) { Expr *ResultCall = Result.get(); if (auto *BE = dyn_cast(ResultCall)) ResultCall = BE->getSubExpr(); if (auto *CE = dyn_cast(ResultCall)) OverloadResolution[OE] = CE->getCallee(); } } return Result; } ExprResult TransformLambdaExpr(LambdaExpr *E) { return Owned(E); } ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } ExprResult TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { return Owned(E); } ExprResult TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { return Owned(E); } ExprResult Transform(Expr *E) { ExprResult Res; while (true) { Res = TryTransform(E); // Exit if either the transform was valid or if there were no TypoExprs // to transform that still have any untried correction candidates.. if (!Res.isInvalid() || !CheckAndAdvanceTypoExprCorrectionStreams()) break; } // Ensure none of the TypoExprs have multiple typo correction candidates // with the same edit length that pass all the checks and filters. // TODO: Properly handle various permutations of possible corrections when // there is more than one potentially ambiguous typo correction. // Also, disable typo correction while attempting the transform when // handling potentially ambiguous typo corrections as any new TypoExprs will // have been introduced by the application of one of the correction // candidates and add little to no value if corrected. SemaRef.DisableTypoCorrection = true; while (!AmbiguousTypoExprs.empty()) { auto TE = AmbiguousTypoExprs.back(); auto Cached = TransformCache[TE]; auto &State = SemaRef.getTypoExprState(TE); State.Consumer->saveCurrentPosition(); TransformCache.erase(TE); if (!TryTransform(E).isInvalid()) { State.Consumer->resetCorrectionStream(); TransformCache.erase(TE); Res = ExprError(); break; } AmbiguousTypoExprs.remove(TE); State.Consumer->restoreSavedPosition(); TransformCache[TE] = Cached; } SemaRef.DisableTypoCorrection = false; // Ensure that all of the TypoExprs within the current Expr have been found. if (!Res.isUsable()) FindTypoExprs(TypoExprs).TraverseStmt(E); EmitAllDiagnostics(); return Res; } ExprResult TransformTypoExpr(TypoExpr *E) { // If the TypoExpr hasn't been seen before, record it. Otherwise, return the // cached transformation result if there is one and the TypoExpr isn't the // first one that was encountered. auto &CacheEntry = TransformCache[E]; if (!TypoExprs.insert(E) && !CacheEntry.isUnset()) { return CacheEntry; } auto &State = SemaRef.getTypoExprState(E); assert(State.Consumer && "Cannot transform a cleared TypoExpr"); // For the first TypoExpr and an uncached TypoExpr, find the next likely // typo correction and return it. while (TypoCorrection TC = State.Consumer->getNextCorrection()) { if (InitDecl && TC.getFoundDecl() == InitDecl) continue; ExprResult NE = State.RecoveryHandler ? State.RecoveryHandler(SemaRef, E, TC) : attemptRecovery(SemaRef, *State.Consumer, TC); if (!NE.isInvalid()) { // Check whether there may be a second viable correction with the same // edit distance; if so, remember this TypoExpr may have an ambiguous // correction so it can be more thoroughly vetted later. TypoCorrection Next; if ((Next = State.Consumer->peekNextCorrection()) && Next.getEditDistance(false) == TC.getEditDistance(false)) { AmbiguousTypoExprs.insert(E); } else { AmbiguousTypoExprs.remove(E); } assert(!NE.isUnset() && "Typo was transformed into a valid-but-null ExprResult"); return CacheEntry = NE; } } return CacheEntry = ExprError(); } }; } ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, llvm::function_ref Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to // resolve any TypoExpr nodes that might be in the expression. if (E && !ExprEvalContexts.empty() && ExprEvalContexts.back().NumTypos && (E->isTypeDependent() || E->isValueDependent() || E->isInstantiationDependent())) { auto TyposInContext = ExprEvalContexts.back().NumTypos; assert(TyposInContext < ~0U && "Recursive call of CorrectDelayedTyposInExpr"); ExprEvalContexts.back().NumTypos = ~0U; auto TyposResolved = DelayedTypos.size(); auto Result = TransformTypos(*this, InitDecl, Filter).Transform(E); ExprEvalContexts.back().NumTypos = TyposInContext; TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); } return E; } ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, bool IsConstexpr, bool IsLambdaInitCaptureInitializer) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); // If we are an init-expression in a lambdas init-capture, we should not // diagnose an unexpanded pack now (will be diagnosed once lambda-expr // containing full-expression is done). // template void test(Ts ... t) { // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now. // return a; // }() ...); // } // FIXME: This is a hack. It would be better if we pushed the lambda scope // when we parse the lambda introducer, and teach capturing (but not // unexpanded pack detection) to walk over LambdaScopeInfos which don't have a // corresponding class yet (that is, have LambdaScopeInfo either represent a // lambda where we've entered the introducer but not the body, or represent a // lambda where we've entered the body, depending on where the // parser/instantiation has got to). if (!IsLambdaInitCaptureInitializer && DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); // Top-level expressions default to 'id' when we're in a debugger. if (DiscardedValue && getLangOpts().DebuggerCastResultToId && FullExpr.get()->getType() == Context.UnknownAnyTy) { FullExpr = forceUnknownAnyToType(FullExpr.get(), Context.getObjCIdType()); if (FullExpr.isInvalid()) return ExprError(); } if (DiscardedValue) { FullExpr = CheckPlaceholderExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); FullExpr = IgnoredValueConversions(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); } FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); if (FullExpr.isInvalid()) return ExprError(); CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); // At the end of this full expression (which could be a deeply nested // lambda), if there is a potential capture within the nested lambda, // have the outer capture-able lambda try and capture it. // Consider the following code: // void f(int, int); // void f(const int&, double); // void foo() { // const int x = 10, y = 20; // auto L = [=](auto a) { // auto M = [=](auto b) { // f(x, b); <-- requires x to be captured by L and M // f(y, a); <-- requires y to be captured by L, but not all Ms // }; // }; // } // FIXME: Also consider what happens for something like this that involves // the gnu-extension statement-expressions or even lambda-init-captures: // void f() { // const int n = 0; // auto L = [&](auto a) { // +n + ({ 0; a; }); // }; // } // // Here, we see +n, and then the full-expression 0; ends, so we don't // capture n (and instead remove it from our list of potential captures), // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. LambdaScopeInfo *const CurrentLSI = getCurLambda(/*IgnoreCapturedRegions=*/true); // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report // for an example of the code that might cause this asynchrony. // By ensuring we are in the context of a lambda's call operator // we can fix the bug (we only need to check whether we need to capture // if we are within a lambda's body); but per the comments in that // PR, a proper fix would entail : // "Alternative suggestion: // - Add to Sema an integer holding the smallest (outermost) scope // index that we are *lexically* within, and save/restore/set to // FunctionScopes.size() in InstantiatingTemplate's // constructor/destructor. // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." DeclContext *DC = CurContext; while (DC && isa(DC)) DC = DC->getParent(); const bool IsInLambdaDeclContext = isLambdaCallOperator(DC); if (IsInLambdaDeclContext && CurrentLSI && CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid()) CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI, *this); return MaybeCreateExprWithCleanups(FullExpr); } StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { if (!FullStmt) return StmtError(); return MaybeCreateStmtWithCleanups(FullStmt); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo) { DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return IER_DoesNotExist; // If the name itself is dependent, then the result is dependent. if (TargetName.isDependentName()) return IER_Dependent; // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); LookupParsedName(R, S, &SS); R.suppressDiagnostics(); switch (R.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: case LookupResult::Ambiguous: return IER_Exists; case LookupResult::NotFound: return IER_DoesNotExist; case LookupResult::NotFoundInCurrentInstantiation: return IER_Dependent; } llvm_unreachable("Invalid LookupResult Kind!"); } Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); // Check for unexpanded parameter packs. SmallVector Unexpanded; collectUnexpandedParameterPacks(SS, Unexpanded); collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); if (!Unexpanded.empty()) { DiagnoseUnexpandedParameterPacks(KeywordLoc, IsIfExists? UPPC_IfExists : UPPC_IfNotExists, Unexpanded); return IER_Error; } return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } diff --git a/test/CodeGen/builtins-mips-msa-error.c b/test/CodeGen/builtins-mips-msa-error.c new file mode 100644 index 000000000000..fcdf6f0c48c8 --- /dev/null +++ b/test/CodeGen/builtins-mips-msa-error.c @@ -0,0 +1,421 @@ +// REQUIRES: mips-registered-target +// RUN: not %clang_cc1 -triple mips-unknown-linux-gnu -fsyntax-only %s \ +// RUN: -target-feature +msa -target-feature +fp64 \ +// RUN: -mfloat-abi hard -o - 2>&1 | FileCheck %s + +#include + +void test(void) { + v16i8 v16i8_a = (v16i8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + v16i8 v16i8_r; + v8i16 v8i16_a = (v8i16) {0, 1, 2, 3, 4, 5, 6, 7}; + v8i16 v8i16_r; + v4i32 v4i32_a = (v4i32) {0, 1, 2, 3}; + v4i32 v4i32_r; + v2i64 v2i64_a = (v2i64) {0, 1}; + v2i64 v2i64_r; + + v16u8 v16u8_a = (v16u8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + v16u8 v16u8_r; + v8u16 v8u16_a = (v8u16) {0, 1, 2, 3, 4, 5, 6, 7}; + v8u16 v8u16_r; + v4u32 v4u32_a = (v4u32) {0, 1, 2, 3}; + v4u32 v4u32_r; + v2u64 v2u64_a = (v2u64) {0, 1}; + v2u64 v2u64_r; + + + int int_r; + long long ll_r; + + v16u8_r = __msa_addvi_b(v16u8_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_addvi_h(v8u16_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_addvi_w(v4u32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_addvi_d(v2u64_a, 32); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_andi_b(v16i8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_andi_b(v8i16_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_andi_b(v4i32_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v2i64_r = __msa_andi_b(v2i64_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_bclri_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bclri_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bclri_w(v4i32_a, 33); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bclri_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_binsli_b(v16i8_r, v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_binsli_h(v8i16_r, v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_binsli_w(v4i32_r, v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_binsli_d(v2i64_r, v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_binsri_b(v16i8_r, v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_binsri_h(v8i16_r, v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_binsri_w(v4i32_r, v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_binsri_d(v2i64_r, v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_bmnzi_b(v16i8_r, v16i8_a, 256); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bmzi_b(v16i8_r, v16i8_a, 256); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bnegi_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bnegi_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bnegi_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bnegi_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_bseli_b(v16i8_r, v16i8_a, 256); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bseti_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bseti_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bseti_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bseti_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_ceqi_b(v16i8_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_ceqi_h(v8i16_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_ceqi_w(v4i32_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_ceqi_d(v2i64_a, 16); // expected-error {{argument should be a value from -16 to 15}} + + v16i8_r = __msa_clei_s_b(v16i8_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_clei_s_h(v8i16_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_clei_s_w(v4i32_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_clei_s_d(v2i64_a, 16); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_clei_u_b(v16u8_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_clei_u_h(v8u16_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_clei_u_w(v4u32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_clei_u_d(v2u64_a, 32); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_clti_s_b(v16i8_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_clti_s_h(v8i16_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_clti_s_w(v4i32_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_clti_s_d(v2i64_a, 16); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_clti_u_b(v16u8_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_clti_u_h(v8u16_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_clti_u_w(v4u32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_clti_u_d(v2u64_a, 32); // expected-error {{argument should be a value from 0 to 31}} + + int_r = __msa_copy_s_b(v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}} + int_r = __msa_copy_s_h(v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}} + int_r = __msa_copy_s_w(v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}} + ll_r = __msa_copy_s_d(v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}} + + int_r = __msa_copy_u_b(v16u8_a, 16); // expected-error {{argument should be a value from 0 to 15}} + int_r = __msa_copy_u_h(v8u16_a, 8); // expected-error {{argument should be a value from 0 to 7}} + int_r = __msa_copy_u_w(v4u32_a, 4); // expected-error {{argument should be a value from 0 to 3}} + ll_r = __msa_copy_u_d(v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_insve_b(v16i8_r, 16, v16i8_a); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_insve_h(v8i16_r, 8, v8i16_a); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_insve_w(v4i32_r, 4, v4i32_a); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_insve_d(v2i64_r, 2, v2i64_a); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_ld_b(&v16i8_a, 23); // expected-error {{argument should be a multiple of 16}} + v8i16_r = __msa_ld_h(&v8i16_a, 77); // expected-error {{argument should be a multiple of 16}} + v4i32_r = __msa_ld_w(&v4i32_a, 14); // expected-error {{argument should be a multiple of 16}} + v2i64_r = __msa_ld_d(&v2i64_a, 23); // expected-error {{argument should be a multiple of 16}} + + v16i8_r = __msa_ld_b(&v16i8_a, 512); // expected-error {{argument should be a value from -512 to 511}} + v8i16_r = __msa_ld_h(&v8i16_a, 512); // expected-error {{argument should be a value from -512 to 511}} + v4i32_r = __msa_ld_w(&v4i32_a, 512); // expected-error {{argument should be a value from -512 to 511}} + v2i64_r = __msa_ld_d(&v2i64_a, 512); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_ldi_b(512); // expected-error {{argument should be a value from -512 to 511}} + v8i16_r = __msa_ldi_h(512); // expected-error {{argument should be a value from -512 to 511}} + v4i32_r = __msa_ldi_w(512); // expected-error {{argument should be a value from -512 to 511}} + v2i64_r = __msa_ldi_d(512); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_maxi_s_b(v16i8_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_maxi_s_h(v8i16_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_maxi_s_w(v4i32_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_maxi_s_d(v2i64_a, 16); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_maxi_u_b(v16u8_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_maxi_u_h(v8u16_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_maxi_u_w(v4u32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_maxi_u_d(v2u64_a, 32); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_mini_s_b(v16i8_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_mini_s_h(v8i16_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_mini_s_w(v4i32_a, 16); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_mini_s_d(v2i64_a, 16); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_mini_u_b(v16u8_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_mini_u_h(v8u16_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_mini_u_w(v4u32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_mini_u_d(v2u64_a, 32); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_nori_b(v16i8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_ori_b(v16i8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_sat_s_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_sat_s_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_sat_s_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_sat_s_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_sat_u_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_sat_u_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_sat_u_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_sat_u_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_shf_b(v16i8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_shf_h(v8i16_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_shf_w(v4i32_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_sldi_d(v2i64_r, v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_slli_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_slli_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_slli_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_slli_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_splati_b(v16i8_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_splati_h(v8i16_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_splati_w(v4i32_a, 4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_splati_d(v2i64_a, 2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_srai_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srai_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srai_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srai_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srari_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srari_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srari_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srari_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srli_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srli_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srli_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srli_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srlri_b(v16i8_a, 8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srlri_h(v8i16_a, 16); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srlri_w(v4i32_a, 32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srlri_d(v2i64_a, 64); // expected-error {{argument should be a value from 0 to 63}} + + __msa_st_b(v16i8_b, &v16i8_a, 52); // expected-error {{argument should be a multiple of 16}} + __msa_st_h(v8i16_b, &v8i16_a, 51); // expected-error {{argument should be a multiple of 16}} + __msa_st_w(v4i32_b, &v4i32_a, 51); // expected-error {{argument should be a multiple of 16}} + __msa_st_d(v2i64_b, &v2i64_a, 12); // expected-error {{argument should be a multiple of 16}} + + __msa_st_b(v16i8_b, &v16i8_a, 512); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_h(v8i16_b, &v8i16_a, 512); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_w(v4i32_b, &v4i32_a, 512); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_d(v2i64_b, &v2i64_a, 512); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_subvi_b(v16i8_a, 256); // expected-error {{argument should be a value from 0 to 31}} + v8i16_r = __msa_subvi_h(v8i16_a, 256); // expected-error {{argument should be a value from 0 to 31}} + v4i32_r = __msa_subvi_w(v4i32_a, 256); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_subvi_d(v2i64_a, 256); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_xori_b(v16i8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_xori_b(v8i16_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_xori_b(v4i32_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v2i64_r = __msa_xori_b(v2i64_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + v16u8_r = __msa_xori_b(v16u8_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v8u16_r = __msa_xori_b(v8u16_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v4u32_r = __msa_xori_b(v4u32_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + v2u64_r = __msa_xori_b(v2u64_a, 256); // CHECK: warning: argument should be a value from 0 to 255}} + + // Test the lower bounds + + v16u8_r = __msa_addvi_b(v16u8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_addvi_h(v8u16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_addvi_w(v4u32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_addvi_d(v2u64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_andi_b(v16i8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_andi_b(v8i16_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_andi_b(v4i32_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v2i64_r = __msa_andi_b(v2i64_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_bclri_b(v16i8_a, -1); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bclri_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bclri_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bclri_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_binsli_b(v16i8_r, v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_binsli_h(v8i16_r, v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_binsli_w(v4i32_r, v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_binsli_d(v2i64_r, v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_binsri_b(v16i8_r, v16i8_a, -1); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_binsri_h(v8i16_r, v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_binsri_w(v4i32_r, v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_binsri_d(v2i64_r, v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_bmnzi_b(v16i8_r, v16i8_a, -1); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bmzi_b(v16i8_r, v16i8_a, -1); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bnegi_b(v16i8_a, -1); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bnegi_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bnegi_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bnegi_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_bseli_b(v16i8_r, v16i8_a, -1); // expected-error {{argument should be a value from 0 to 255}} + + v16i8_r = __msa_bseti_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_bseti_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_bseti_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_bseti_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_ceqi_b(v16i8_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_ceqi_h(v8i16_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_ceqi_w(v4i32_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_ceqi_d(v2i64_a, -17); // expected-error {{argument should be a value from -16 to 15}} + + v16i8_r = __msa_clei_s_b(v16i8_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_clei_s_h(v8i16_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_clei_s_w(v4i32_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_clei_s_d(v2i64_a, -17); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_clei_u_b(v16u8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_clei_u_h(v8u16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_clei_u_w(v4u32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_clei_u_d(v2u64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_clti_s_b(v16i8_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_clti_s_h(v8i16_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_clti_s_w(v4i32_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_clti_s_d(v2i64_a, -17); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_clti_u_b(v16u8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_clti_u_h(v8u16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_clti_u_w(v4u32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_clti_u_d(v2u64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + int_r = __msa_copy_s_b(v16i8_a, -1); // expected-error {{argument should be a value from 0 to 15}} + int_r = __msa_copy_s_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 7}} + int_r = __msa_copy_s_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 3}} + ll_r = __msa_copy_s_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 1}} + + int_r = __msa_copy_u_b(v16u8_a, -17); // expected-error {{argument should be a value from 0 to 15}} + int_r = __msa_copy_u_h(v8u16_a, -8); // expected-error {{argument should be a value from 0 to 7}} + int_r = __msa_copy_u_w(v4u32_a, -4); // expected-error {{argument should be a value from 0 to 3}} + ll_r = __msa_copy_u_d(v2i64_a, -2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_insve_b(v16i8_r, 16, v16i8_a); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_insve_h(v8i16_r, 8, v8i16_a); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_insve_w(v4i32_r, 4, v4i32_a); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_insve_d(v2i64_r, 2, v2i64_a); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_ld_b(&v16i8_a, -513); // expected-error {{argument should be a value from -512 to 511}} + v8i16_r = __msa_ld_h(&v8i16_a, -513); // expected-error {{argument should be a value from -512 to 511}} + v4i32_r = __msa_ld_w(&v4i32_a, -513); // expected-error {{argument should be a value from -512 to 511}} + v2i64_r = __msa_ld_d(&v2i64_a, -513); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_ldi_b(-513); // expected-error {{argument should be a value from -512 to 511}} + v8i16_r = __msa_ldi_h(-513); // expected-error {{argument should be a value from -512 to 511}} + v4i32_r = __msa_ldi_w(-513); // expected-error {{argument should be a value from -512 to 511}} + v2i64_r = __msa_ldi_d(-513); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_maxi_s_b(v16i8_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_maxi_s_h(v8i16_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_maxi_s_w(v4i32_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_maxi_s_d(v2i64_a, -17); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_maxi_u_b(v16u8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_maxi_u_h(v8u16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_maxi_u_w(v4u32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_maxi_u_d(v2u64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_mini_s_b(v16i8_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v8i16_r = __msa_mini_s_h(v8i16_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v4i32_r = __msa_mini_s_w(v4i32_a, -17); // expected-error {{argument should be a value from -16 to 15}} + v2i64_r = __msa_mini_s_d(v2i64_a, -17); // expected-error {{argument should be a value from -16 to 15}} + + v16u8_r = __msa_mini_u_b(v16u8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8u16_r = __msa_mini_u_h(v8u16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4u32_r = __msa_mini_u_w(v4u32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2u64_r = __msa_mini_u_d(v2u64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_nori_b(v16i8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_ori_b(v16i8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_sat_s_b(v16i8_a, -1); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_sat_s_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_sat_s_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_sat_s_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_sat_u_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_sat_u_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_sat_u_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_sat_u_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_shf_b(v16i8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_shf_h(v8i16_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_shf_w(v4i32_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + + v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, -4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, -2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, -4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_sldi_d(v2i64_r, v2i64_a, -2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_slli_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_slli_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_slli_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_slli_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_splati_b(v16i8_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v8i16_r = __msa_splati_h(v8i16_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v4i32_r = __msa_splati_w(v4i32_a, -4); // expected-error {{argument should be a value from 0 to 3}} + v2i64_r = __msa_splati_d(v2i64_a, -2); // expected-error {{argument should be a value from 0 to 1}} + + v16i8_r = __msa_srai_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srai_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srai_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srai_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srari_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srari_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srari_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srari_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srli_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srli_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srli_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srli_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + v16i8_r = __msa_srlri_b(v16i8_a, -8); // expected-error {{argument should be a value from 0 to 7}} + v8i16_r = __msa_srlri_h(v8i16_a, -17); // expected-error {{argument should be a value from 0 to 15}} + v4i32_r = __msa_srlri_w(v4i32_a, -32); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_srlri_d(v2i64_a, -64); // expected-error {{argument should be a value from 0 to 63}} + + __msa_st_b(v16i8_b, &v16i8_a, -513); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_h(v8i16_b, &v8i16_a, -513); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_w(v4i32_b, &v4i32_a, -513); // expected-error {{argument should be a value from -512 to 511}} + __msa_st_d(v2i64_b, &v2i64_a, -513); // expected-error {{argument should be a value from -512 to 511}} + + v16i8_r = __msa_subvi_b(v16i8_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v8i16_r = __msa_subvi_h(v8i16_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v4i32_r = __msa_subvi_w(v4i32_a, -1); // expected-error {{argument should be a value from 0 to 31}} + v2i64_r = __msa_subvi_d(v2i64_a, -1); // expected-error {{argument should be a value from 0 to 31}} + + v16i8_r = __msa_xori_b(v16i8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v8i16_r = __msa_xori_b(v8i16_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v4i32_r = __msa_xori_b(v4i32_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v2i64_r = __msa_xori_b(v2i64_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + + v16u8_r = __msa_xori_b(v16u8_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v8u16_r = __msa_xori_b(v8u16_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v4u32_r = __msa_xori_b(v4u32_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + v2u64_r = __msa_xori_b(v2u64_a, -1); // CHECK: warning: argument should be a value from 0 to 255}} + +} diff --git a/test/CodeGen/builtins-mips-msa.c b/test/CodeGen/builtins-mips-msa.c index 38aea04d9c36..125679545601 100644 --- a/test/CodeGen/builtins-mips-msa.c +++ b/test/CodeGen/builtins-mips-msa.c @@ -1,829 +1,822 @@ // REQUIRES: mips-registered-target -// RUN: %clang_cc1 -triple mips-unknown-linux-gnu -emit-llvm %s -o - \ -// RUN: | FileCheck %s - -typedef signed char v16i8 __attribute__ ((vector_size(16))); -typedef signed short v8i16 __attribute__ ((vector_size(16))); -typedef signed int v4i32 __attribute__ ((vector_size(16))); -typedef signed long long v2i64 __attribute__ ((vector_size(16))); -typedef unsigned char v16u8 __attribute__ ((vector_size(16))); -typedef unsigned short v8u16 __attribute__ ((vector_size(16))); -typedef unsigned int v4u32 __attribute__ ((vector_size(16))); -typedef unsigned long long v2u64 __attribute__ ((vector_size(16))); +// RUN: %clang_cc1 -triple mips-unknown-linux-gnu -emit-llvm %s \ +// RUN: -target-feature +msa -target-feature +fp64 \ +// RUN: -mfloat-abi hard -o - | FileCheck %s + +#include + typedef __fp16 v8f16 __attribute__ ((vector_size(16))); -typedef float v4f32 __attribute__ ((vector_size(16))); -typedef double v2f64 __attribute__ ((vector_size(16))); void test(void) { v16i8 v16i8_a = (v16i8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; v16i8 v16i8_b = (v16i8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; v16i8 v16i8_r; v8i16 v8i16_a = (v8i16) {0, 1, 2, 3, 4, 5, 6, 7}; v8i16 v8i16_b = (v8i16) {1, 2, 3, 4, 5, 6, 7, 8}; v8i16 v8i16_r; v4i32 v4i32_a = (v4i32) {0, 1, 2, 3}; v4i32 v4i32_b = (v4i32) {1, 2, 3, 4}; v4i32 v4i32_r; v2i64 v2i64_a = (v2i64) {0, 1}; v2i64 v2i64_b = (v2i64) {1, 2}; v2i64 v2i64_r; v16u8 v16u8_a = (v16u8) {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; v16u8 v16u8_b = (v16u8) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; v16u8 v16u8_r; v8u16 v8u16_a = (v8u16) {0, 1, 2, 3, 4, 5, 6, 7}; v8u16 v8u16_b = (v8u16) {1, 2, 3, 4, 5, 6, 7, 8}; v8u16 v8u16_r; v4u32 v4u32_a = (v4u32) {0, 1, 2, 3}; v4u32 v4u32_b = (v4u32) {1, 2, 3, 4}; v4u32 v4u32_r; v2u64 v2u64_a = (v2u64) {0, 1}; v2u64 v2u64_b = (v2u64) {1, 2}; v2u64 v2u64_r; v8f16 v8f16_a = (v8f16) {0.5, 1, 2, 3, 4, 5, 6, 7}; v8f16 v8f16_b = (v8f16) {1.5, 2, 3, 4, 5, 6, 7, 8}; v8f16 v8f16_r; v4f32 v4f32_a = (v4f32) {0.5, 1, 2, 3}; v4f32 v4f32_b = (v4f32) {1.5, 2, 3, 4}; v4f32 v4f32_r; v2f64 v2f64_a = (v2f64) {0.5, 1}; v2f64 v2f64_b = (v2f64) {1.5, 2}; v2f64 v2f64_r; int int_r; long long ll_r; int int_a = 0; - v16i8_r = __builtin_msa_add_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.add.a.b( - v8i16_r = __builtin_msa_add_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.add.a.h( - v4i32_r = __builtin_msa_add_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.add.a.w( - v2i64_r = __builtin_msa_add_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.add.a.d( - - v16i8_r = __builtin_msa_adds_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.a.b( - v8i16_r = __builtin_msa_adds_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.a.h( - v4i32_r = __builtin_msa_adds_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.a.w( - v2i64_r = __builtin_msa_adds_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.a.d( - - v16i8_r = __builtin_msa_adds_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.s.b( - v8i16_r = __builtin_msa_adds_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.s.h( - v4i32_r = __builtin_msa_adds_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.s.w( - v2i64_r = __builtin_msa_adds_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.s.d( - - v16u8_r = __builtin_msa_adds_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.adds.u.b( - v8u16_r = __builtin_msa_adds_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.adds.u.h( - v4u32_r = __builtin_msa_adds_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.adds.u.w( - v2u64_r = __builtin_msa_adds_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.adds.u.d( - - v16i8_r = __builtin_msa_addv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b( - v8i16_r = __builtin_msa_addv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h( - v4i32_r = __builtin_msa_addv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w( - v2i64_r = __builtin_msa_addv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d( - - v16u8_r = __builtin_msa_addv_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b( - v8u16_r = __builtin_msa_addv_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h( - v4u32_r = __builtin_msa_addv_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w( - v2u64_r = __builtin_msa_addv_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d( - - v16i8_r = __builtin_msa_addvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b( - v8i16_r = __builtin_msa_addvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h( - v4i32_r = __builtin_msa_addvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w( - v2i64_r = __builtin_msa_addvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d( - - v16u8_r = __builtin_msa_addvi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b( - v8u16_r = __builtin_msa_addvi_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h( - v4u32_r = __builtin_msa_addvi_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w( - v2u64_r = __builtin_msa_addvi_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d( - - v16i8_r = __builtin_msa_and_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.and.v( - v8i16_r = __builtin_msa_and_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.and.v( - v4i32_r = __builtin_msa_and_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.and.v( - v2i64_r = __builtin_msa_and_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.and.v( - - v16i8_r = __builtin_msa_andi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v8i16_r = __builtin_msa_andi_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v4i32_r = __builtin_msa_andi_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v2i64_r = __builtin_msa_andi_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - - v16u8_r = __builtin_msa_andi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v8u16_r = __builtin_msa_andi_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v4u32_r = __builtin_msa_andi_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - v2u64_r = __builtin_msa_andi_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( - - v16i8_r = __builtin_msa_asub_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.asub.s.b( - v8i16_r = __builtin_msa_asub_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.asub.s.h( - v4i32_r = __builtin_msa_asub_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.asub.s.w( - v2i64_r = __builtin_msa_asub_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.asub.s.d( - - v16u8_r = __builtin_msa_asub_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.asub.u.b( - v8u16_r = __builtin_msa_asub_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.asub.u.h( - v4u32_r = __builtin_msa_asub_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.asub.u.w( - v2u64_r = __builtin_msa_asub_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.asub.u.d( - - v16i8_r = __builtin_msa_ave_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ave.s.b( - v8i16_r = __builtin_msa_ave_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ave.s.h( - v4i32_r = __builtin_msa_ave_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ave.s.w( - v2i64_r = __builtin_msa_ave_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ave.s.d( - - v16u8_r = __builtin_msa_ave_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.ave.u.b( - v8u16_r = __builtin_msa_ave_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.ave.u.h( - v4u32_r = __builtin_msa_ave_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.ave.u.w( - v2u64_r = __builtin_msa_ave_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.ave.u.d( - - v16i8_r = __builtin_msa_aver_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.aver.s.b( - v8i16_r = __builtin_msa_aver_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.aver.s.h( - v4i32_r = __builtin_msa_aver_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.aver.s.w( - v2i64_r = __builtin_msa_aver_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.aver.s.d( - - v16u8_r = __builtin_msa_aver_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.aver.u.b( - v8u16_r = __builtin_msa_aver_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.aver.u.h( - v4u32_r = __builtin_msa_aver_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.aver.u.w( - v2u64_r = __builtin_msa_aver_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.aver.u.d( - - v16i8_r = __builtin_msa_bclr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bclr.b( - v8i16_r = __builtin_msa_bclr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bclr.h( - v4i32_r = __builtin_msa_bclr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bclr.w( - v2i64_r = __builtin_msa_bclr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bclr.d( - - v16i8_r = __builtin_msa_bclri_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bclri.b( - v8i16_r = __builtin_msa_bclri_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bclri.h( - v4i32_r = __builtin_msa_bclri_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bclri.w( - v2i64_r = __builtin_msa_bclri_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bclri.d( - - v16i8_r = __builtin_msa_binsl_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsl.b( - v8i16_r = __builtin_msa_binsl_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsl.h( - v4i32_r = __builtin_msa_binsl_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsl.w( - v2i64_r = __builtin_msa_binsl_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsl.d( - - v16i8_r = __builtin_msa_binsli_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.binsli.b( - v8i16_r = __builtin_msa_binsli_h(v8i16_r, v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.binsli.h( - v4i32_r = __builtin_msa_binsli_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsli.w( - v2i64_r = __builtin_msa_binsli_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsli.d( - - v16i8_r = __builtin_msa_binsr_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsr.b( - v8i16_r = __builtin_msa_binsr_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsr.h( - v4i32_r = __builtin_msa_binsr_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsr.w( - v2i64_r = __builtin_msa_binsr_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsr.d( - - v16i8_r = __builtin_msa_binsri_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.binsri.b( - v8i16_r = __builtin_msa_binsri_h(v8i16_r, v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.binsri.h( - v4i32_r = __builtin_msa_binsri_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsri.w( - v2i64_r = __builtin_msa_binsri_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsri.d( - - v16i8_r = __builtin_msa_bmnz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( - v8i16_r = __builtin_msa_bmnz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( - v4i32_r = __builtin_msa_bmnz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( - v2i64_r = __builtin_msa_bmnz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( - - v16i8_r = __builtin_msa_bmnzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmnzi.b( - - v16i8_r = __builtin_msa_bmz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( - v8i16_r = __builtin_msa_bmz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( - v4i32_r = __builtin_msa_bmz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( - v2i64_r = __builtin_msa_bmz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( - - v16i8_r = __builtin_msa_bmzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmzi.b( - - v16i8_r = __builtin_msa_bneg_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bneg.b( - v8i16_r = __builtin_msa_bneg_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bneg.h( - v4i32_r = __builtin_msa_bneg_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bneg.w( - v2i64_r = __builtin_msa_bneg_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bneg.d( - - v16i8_r = __builtin_msa_bnegi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bnegi.b( - v8i16_r = __builtin_msa_bnegi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bnegi.h( - v4i32_r = __builtin_msa_bnegi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bnegi.w( - v2i64_r = __builtin_msa_bnegi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bnegi.d( - - int_r = __builtin_msa_bnz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.b( - int_r = __builtin_msa_bnz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.h( - int_r = __builtin_msa_bnz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.w( - int_r = __builtin_msa_bnz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.d( - - int_r = __builtin_msa_bnz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.v( - - v16i8_r = __builtin_msa_bsel_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( - v8i16_r = __builtin_msa_bsel_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( - v4i32_r = __builtin_msa_bsel_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( - v2i64_r = __builtin_msa_bsel_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( - - v16i8_r = __builtin_msa_bseli_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bseli.b( - - v16i8_r = __builtin_msa_bset_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bset.b( - v8i16_r = __builtin_msa_bset_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bset.h( - v4i32_r = __builtin_msa_bset_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bset.w( - v2i64_r = __builtin_msa_bset_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bset.d( - - v16i8_r = __builtin_msa_bseti_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bseti.b( - v8i16_r = __builtin_msa_bseti_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.bseti.h( - v4i32_r = __builtin_msa_bseti_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bseti.w( - v2i64_r = __builtin_msa_bseti_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bseti.d( - - int_r = __builtin_msa_bz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bz.b( - int_r = __builtin_msa_bz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bz.h( - int_r = __builtin_msa_bz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bz.w( - int_r = __builtin_msa_bz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bz.d( - - int_r = __builtin_msa_bz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bz.v( - - v16i8_r = __builtin_msa_ceq_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ceq.b( - v8i16_r = __builtin_msa_ceq_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ceq.h( - v4i32_r = __builtin_msa_ceq_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ceq.w( - v2i64_r = __builtin_msa_ceq_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ceq.d( - - v16i8_r = __builtin_msa_ceqi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ceqi.b( - v8i16_r = __builtin_msa_ceqi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.ceqi.h( - v4i32_r = __builtin_msa_ceqi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.ceqi.w( - v2i64_r = __builtin_msa_ceqi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.ceqi.d( - - int_r = __builtin_msa_cfcmsa(1); // CHECK: call i32 @llvm.mips.cfcmsa( - - v16i8_r = __builtin_msa_cle_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.cle.s.b( - v8i16_r = __builtin_msa_cle_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.cle.s.h( - v4i32_r = __builtin_msa_cle_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.cle.s.w( - v2i64_r = __builtin_msa_cle_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.cle.s.d( - - v16u8_r = __builtin_msa_cle_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.cle.u.b( - v8u16_r = __builtin_msa_cle_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.cle.u.h( - v4u32_r = __builtin_msa_cle_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.cle.u.w( - v2u64_r = __builtin_msa_cle_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.cle.u.d( - - v16i8_r = __builtin_msa_clei_s_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clei.s.b( - v8i16_r = __builtin_msa_clei_s_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clei.s.h( - v4i32_r = __builtin_msa_clei_s_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clei.s.w( - v2i64_r = __builtin_msa_clei_s_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clei.s.d( - - v16u8_r = __builtin_msa_clei_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clei.u.b( - v8u16_r = __builtin_msa_clei_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clei.u.h( - v4u32_r = __builtin_msa_clei_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clei.u.w( - v2u64_r = __builtin_msa_clei_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clei.u.d( - - v16i8_r = __builtin_msa_clt_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.clt.s.b( - v8i16_r = __builtin_msa_clt_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.clt.s.h( - v4i32_r = __builtin_msa_clt_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.clt.s.w( - v2i64_r = __builtin_msa_clt_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.clt.s.d( - - v16u8_r = __builtin_msa_clt_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.clt.u.b( - v8u16_r = __builtin_msa_clt_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.clt.u.h( - v4u32_r = __builtin_msa_clt_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.clt.u.w( - v2u64_r = __builtin_msa_clt_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.clt.u.d( - - v16i8_r = __builtin_msa_clti_s_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clti.s.b( - v8i16_r = __builtin_msa_clti_s_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clti.s.h( - v4i32_r = __builtin_msa_clti_s_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clti.s.w( - v2i64_r = __builtin_msa_clti_s_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clti.s.d( - - v16u8_r = __builtin_msa_clti_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clti.u.b( - v8u16_r = __builtin_msa_clti_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clti.u.h( - v4u32_r = __builtin_msa_clti_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clti.u.w( - v2u64_r = __builtin_msa_clti_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clti.u.d( - - int_r = __builtin_msa_copy_s_b(v16i8_a, 1); // CHECK: call i32 @llvm.mips.copy.s.b( - int_r = __builtin_msa_copy_s_h(v8i16_a, 1); // CHECK: call i32 @llvm.mips.copy.s.h( - int_r = __builtin_msa_copy_s_w(v4i32_a, 1); // CHECK: call i32 @llvm.mips.copy.s.w( - ll_r = __builtin_msa_copy_s_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.s.d( - - int_r = __builtin_msa_copy_u_b(v16u8_a, 1); // CHECK: call i32 @llvm.mips.copy.u.b( - int_r = __builtin_msa_copy_u_h(v8u16_a, 1); // CHECK: call i32 @llvm.mips.copy.u.h( - int_r = __builtin_msa_copy_u_w(v4u32_a, 1); // CHECK: call i32 @llvm.mips.copy.u.w( - ll_r = __builtin_msa_copy_u_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.u.d( + v16i8_r = __msa_add_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.add.a.b( + v8i16_r = __msa_add_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.add.a.h( + v4i32_r = __msa_add_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.add.a.w( + v2i64_r = __msa_add_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.add.a.d( + + v16i8_r = __msa_adds_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.a.b( + v8i16_r = __msa_adds_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.a.h( + v4i32_r = __msa_adds_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.a.w( + v2i64_r = __msa_adds_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.a.d( + + v16i8_r = __msa_adds_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.adds.s.b( + v8i16_r = __msa_adds_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.adds.s.h( + v4i32_r = __msa_adds_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.adds.s.w( + v2i64_r = __msa_adds_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.adds.s.d( + + v16u8_r = __msa_adds_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.adds.u.b( + v8u16_r = __msa_adds_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.adds.u.h( + v4u32_r = __msa_adds_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.adds.u.w( + v2u64_r = __msa_adds_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.adds.u.d( + + v16i8_r = __msa_addv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b( + v8i16_r = __msa_addv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h( + v4i32_r = __msa_addv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w( + v2i64_r = __msa_addv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d( + + v16u8_r = __msa_addv_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.addv.b( + v8u16_r = __msa_addv_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.addv.h( + v4u32_r = __msa_addv_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.addv.w( + v2u64_r = __msa_addv_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.addv.d( + + v16i8_r = __msa_addvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b( + v8i16_r = __msa_addvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h( + v4i32_r = __msa_addvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w( + v2i64_r = __msa_addvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d( + + v16u8_r = __msa_addvi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.addvi.b( + v8u16_r = __msa_addvi_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.addvi.h( + v4u32_r = __msa_addvi_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.addvi.w( + v2u64_r = __msa_addvi_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.addvi.d( + + v16i8_r = __msa_and_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.and.v( + v8i16_r = __msa_and_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.and.v( + v4i32_r = __msa_and_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.and.v( + v2i64_r = __msa_and_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.and.v( + + v16i8_r = __msa_andi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v8i16_r = __msa_andi_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v4i32_r = __msa_andi_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v2i64_r = __msa_andi_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + + v16u8_r = __msa_andi_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v8u16_r = __msa_andi_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v4u32_r = __msa_andi_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + v2u64_r = __msa_andi_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.andi.b( + + v16i8_r = __msa_asub_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.asub.s.b( + v8i16_r = __msa_asub_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.asub.s.h( + v4i32_r = __msa_asub_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.asub.s.w( + v2i64_r = __msa_asub_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.asub.s.d( + + v16u8_r = __msa_asub_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.asub.u.b( + v8u16_r = __msa_asub_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.asub.u.h( + v4u32_r = __msa_asub_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.asub.u.w( + v2u64_r = __msa_asub_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.asub.u.d( + + v16i8_r = __msa_ave_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ave.s.b( + v8i16_r = __msa_ave_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ave.s.h( + v4i32_r = __msa_ave_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ave.s.w( + v2i64_r = __msa_ave_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ave.s.d( + + v16u8_r = __msa_ave_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.ave.u.b( + v8u16_r = __msa_ave_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.ave.u.h( + v4u32_r = __msa_ave_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.ave.u.w( + v2u64_r = __msa_ave_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.ave.u.d( + + v16i8_r = __msa_aver_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.aver.s.b( + v8i16_r = __msa_aver_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.aver.s.h( + v4i32_r = __msa_aver_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.aver.s.w( + v2i64_r = __msa_aver_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.aver.s.d( + + v16u8_r = __msa_aver_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.aver.u.b( + v8u16_r = __msa_aver_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.aver.u.h( + v4u32_r = __msa_aver_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.aver.u.w( + v2u64_r = __msa_aver_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.aver.u.d( + + v16i8_r = __msa_bclr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bclr.b( + v8i16_r = __msa_bclr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bclr.h( + v4i32_r = __msa_bclr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bclr.w( + v2i64_r = __msa_bclr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bclr.d( + + v16i8_r = __msa_bclri_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.bclri.b( + v8i16_r = __msa_bclri_h(v8i16_a, 8); // CHECK: call <8 x i16> @llvm.mips.bclri.h( + v4i32_r = __msa_bclri_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bclri.w( + v2i64_r = __msa_bclri_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bclri.d( + + v16i8_r = __msa_binsl_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsl.b( + v8i16_r = __msa_binsl_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsl.h( + v4i32_r = __msa_binsl_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsl.w( + v2i64_r = __msa_binsl_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsl.d( + + v16i8_r = __msa_binsli_b(v16i8_r, v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.binsli.b( + v8i16_r = __msa_binsli_h(v8i16_r, v8i16_a, 8); // CHECK: call <8 x i16> @llvm.mips.binsli.h( + v4i32_r = __msa_binsli_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsli.w( + v2i64_r = __msa_binsli_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsli.d( + + v16i8_r = __msa_binsr_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.binsr.b( + v8i16_r = __msa_binsr_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.binsr.h( + v4i32_r = __msa_binsr_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.binsr.w( + v2i64_r = __msa_binsr_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.binsr.d( + + v16i8_r = __msa_binsri_b(v16i8_r, v16i8_a, 5); // CHECK: call <16 x i8> @llvm.mips.binsri.b( + v8i16_r = __msa_binsri_h(v8i16_r, v8i16_a, 15); // CHECK: call <8 x i16> @llvm.mips.binsri.h( + v4i32_r = __msa_binsri_w(v4i32_r, v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.binsri.w( + v2i64_r = __msa_binsri_d(v2i64_r, v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.binsri.d( + + v16i8_r = __msa_bmnz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( + v8i16_r = __msa_bmnz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( + v4i32_r = __msa_bmnz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( + v2i64_r = __msa_bmnz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmnz.v( + + v16i8_r = __msa_bmnzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmnzi.b( + + v16i8_r = __msa_bmz_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( + v8i16_r = __msa_bmz_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( + v4i32_r = __msa_bmz_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( + v2i64_r = __msa_bmz_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bmz.v( + + v16i8_r = __msa_bmzi_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bmzi.b( + + v16i8_r = __msa_bneg_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bneg.b( + v8i16_r = __msa_bneg_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bneg.h( + v4i32_r = __msa_bneg_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bneg.w( + v2i64_r = __msa_bneg_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bneg.d( + + v16i8_r = __msa_bnegi_b(v16i8_a, 6); // CHECK: call <16 x i8> @llvm.mips.bnegi.b( + v8i16_r = __msa_bnegi_h(v8i16_a, 14); // CHECK: call <8 x i16> @llvm.mips.bnegi.h( + v4i32_r = __msa_bnegi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bnegi.w( + v2i64_r = __msa_bnegi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bnegi.d( + + int_r = __msa_test_bnz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.b( + int_r = __msa_test_bnz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.h( + int_r = __msa_test_bnz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.w( + int_r = __msa_test_bnz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.d( + + int_r = __msa_test_bnz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bnz.v( + + v16i8_r = __msa_bsel_v(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( + v8i16_r = __msa_bsel_v(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( + v4i32_r = __msa_bsel_v(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( + v2i64_r = __msa_bsel_v(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.bsel.v( + + v16i8_r = __msa_bseli_b(v16i8_r, v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.bseli.b( + + v16i8_r = __msa_bset_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.bset.b( + v8i16_r = __msa_bset_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.bset.h( + v4i32_r = __msa_bset_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.bset.w( + v2i64_r = __msa_bset_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.bset.d( + + v16i8_r = __msa_bseti_b(v16i8_a, 5); // CHECK: call <16 x i8> @llvm.mips.bseti.b( + v8i16_r = __msa_bseti_h(v8i16_a, 15); // CHECK: call <8 x i16> @llvm.mips.bseti.h( + v4i32_r = __msa_bseti_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.bseti.w( + v2i64_r = __msa_bseti_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.bseti.d( + + int_r = __msa_test_bz_b(v16i8_a); // CHECK: call i32 @llvm.mips.bz.b( + int_r = __msa_test_bz_h(v16i8_a); // CHECK: call i32 @llvm.mips.bz.h( + int_r = __msa_test_bz_w(v16i8_a); // CHECK: call i32 @llvm.mips.bz.w( + int_r = __msa_test_bz_d(v16i8_a); // CHECK: call i32 @llvm.mips.bz.d( + + int_r = __msa_test_bz_v(v16i8_a); // CHECK: call i32 @llvm.mips.bz.v( + + v16i8_r = __msa_ceq_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ceq.b( + v8i16_r = __msa_ceq_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ceq.h( + v4i32_r = __msa_ceq_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ceq.w( + v2i64_r = __msa_ceq_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ceq.d( + + v16i8_r = __msa_ceqi_b(v16i8_a, -3); // CHECK: call <16 x i8> @llvm.mips.ceqi.b( + v8i16_r = __msa_ceqi_h(v8i16_a, -12); // CHECK: call <8 x i16> @llvm.mips.ceqi.h( + v4i32_r = __msa_ceqi_w(v4i32_a, 14); // CHECK: call <4 x i32> @llvm.mips.ceqi.w( + v2i64_r = __msa_ceqi_d(v2i64_a, 15); // CHECK: call <2 x i64> @llvm.mips.ceqi.d( + + int_r = __msa_cfcmsa(1); // CHECK: call i32 @llvm.mips.cfcmsa( + + v16i8_r = __msa_cle_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.cle.s.b( + v8i16_r = __msa_cle_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.cle.s.h( + v4i32_r = __msa_cle_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.cle.s.w( + v2i64_r = __msa_cle_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.cle.s.d( + + v16u8_r = __msa_cle_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.cle.u.b( + v8u16_r = __msa_cle_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.cle.u.h( + v4u32_r = __msa_cle_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.cle.u.w( + v2u64_r = __msa_cle_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.cle.u.d( + + v16i8_r = __msa_clei_s_b(v16i8_a, 12); // CHECK: call <16 x i8> @llvm.mips.clei.s.b( + v8i16_r = __msa_clei_s_h(v8i16_a, 13); // CHECK: call <8 x i16> @llvm.mips.clei.s.h( + v4i32_r = __msa_clei_s_w(v4i32_a, 14); // CHECK: call <4 x i32> @llvm.mips.clei.s.w( + v2i64_r = __msa_clei_s_d(v2i64_a, 15); // CHECK: call <2 x i64> @llvm.mips.clei.s.d( + + v16u8_r = __msa_clei_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clei.u.b( + v8u16_r = __msa_clei_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clei.u.h( + v4u32_r = __msa_clei_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clei.u.w( + v2u64_r = __msa_clei_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clei.u.d( + + v16i8_r = __msa_clt_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.clt.s.b( + v8i16_r = __msa_clt_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.clt.s.h( + v4i32_r = __msa_clt_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.clt.s.w( + v2i64_r = __msa_clt_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.clt.s.d( + + v16u8_r = __msa_clt_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.clt.u.b( + v8u16_r = __msa_clt_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.clt.u.h( + v4u32_r = __msa_clt_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.clt.u.w( + v2u64_r = __msa_clt_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.clt.u.d( + + v16i8_r = __msa_clti_s_b(v16i8_a, 15); // CHECK: call <16 x i8> @llvm.mips.clti.s.b( + v8i16_r = __msa_clti_s_h(v8i16_a, 15); // CHECK: call <8 x i16> @llvm.mips.clti.s.h( + v4i32_r = __msa_clti_s_w(v4i32_a, 15); // CHECK: call <4 x i32> @llvm.mips.clti.s.w( + v2i64_r = __msa_clti_s_d(v2i64_a, 15); // CHECK: call <2 x i64> @llvm.mips.clti.s.d( + + v16u8_r = __msa_clti_u_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.clti.u.b( + v8u16_r = __msa_clti_u_h(v8u16_a, 25); // CHECK: call <8 x i16> @llvm.mips.clti.u.h( + v4u32_r = __msa_clti_u_w(v4u32_a, 25); // CHECK: call <4 x i32> @llvm.mips.clti.u.w( + v2u64_r = __msa_clti_u_d(v2u64_a, 25); // CHECK: call <2 x i64> @llvm.mips.clti.u.d( + + int_r = __msa_copy_s_b(v16i8_a, 1); // CHECK: call i32 @llvm.mips.copy.s.b( + int_r = __msa_copy_s_h(v8i16_a, 1); // CHECK: call i32 @llvm.mips.copy.s.h( + int_r = __msa_copy_s_w(v4i32_a, 1); // CHECK: call i32 @llvm.mips.copy.s.w( + ll_r = __msa_copy_s_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.s.d( + + int_r = __msa_copy_u_b(v16u8_a, 1); // CHECK: call i32 @llvm.mips.copy.u.b( + int_r = __msa_copy_u_h(v8u16_a, 1); // CHECK: call i32 @llvm.mips.copy.u.h( + int_r = __msa_copy_u_w(v4u32_a, 1); // CHECK: call i32 @llvm.mips.copy.u.w( + ll_r = __msa_copy_u_d(v2i64_a, 1); // CHECK: call i64 @llvm.mips.copy.u.d( __builtin_msa_ctcmsa(1, int_a); // CHECK: call void @llvm.mips.ctcmsa( - v16i8_r = __builtin_msa_div_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.div.s.b( - v8i16_r = __builtin_msa_div_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.div.s.h( - v4i32_r = __builtin_msa_div_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.div.s.w( - v2i64_r = __builtin_msa_div_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.div.s.d( + v16i8_r = __msa_div_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.div.s.b( + v8i16_r = __msa_div_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.div.s.h( + v4i32_r = __msa_div_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.div.s.w( + v2i64_r = __msa_div_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.div.s.d( - v16u8_r = __builtin_msa_div_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.div.u.b( - v8u16_r = __builtin_msa_div_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.div.u.h( - v4u32_r = __builtin_msa_div_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.div.u.w( - v2u64_r = __builtin_msa_div_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.div.u.d( + v16u8_r = __msa_div_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.div.u.b( + v8u16_r = __msa_div_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.div.u.h( + v4u32_r = __msa_div_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.div.u.w( + v2u64_r = __msa_div_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.div.u.d( - v8i16_r = __builtin_msa_dotp_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.s.h( - v4i32_r = __builtin_msa_dotp_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.s.w( - v2i64_r = __builtin_msa_dotp_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.s.d( + v8i16_r = __msa_dotp_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.s.h( + v4i32_r = __msa_dotp_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.s.w( + v2i64_r = __msa_dotp_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.s.d( - v8u16_r = __builtin_msa_dotp_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.u.h( - v4u32_r = __builtin_msa_dotp_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.u.w( - v2u64_r = __builtin_msa_dotp_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.u.d( + v8u16_r = __msa_dotp_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dotp.u.h( + v4u32_r = __msa_dotp_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dotp.u.w( + v2u64_r = __msa_dotp_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dotp.u.d( - v8i16_r = __builtin_msa_dpadd_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.s.h( - v4i32_r = __builtin_msa_dpadd_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.s.w( - v2i64_r = __builtin_msa_dpadd_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.s.d( + v8i16_r = __msa_dpadd_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.s.h( + v4i32_r = __msa_dpadd_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.s.w( + v2i64_r = __msa_dpadd_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.s.d( - v8u16_r = __builtin_msa_dpadd_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.u.h( - v4u32_r = __builtin_msa_dpadd_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.u.w( - v2u64_r = __builtin_msa_dpadd_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.u.d( + v8u16_r = __msa_dpadd_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpadd.u.h( + v4u32_r = __msa_dpadd_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpadd.u.w( + v2u64_r = __msa_dpadd_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpadd.u.d( - v8i16_r = __builtin_msa_dpsub_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.s.h( - v4i32_r = __builtin_msa_dpsub_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.s.w( - v2i64_r = __builtin_msa_dpsub_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.s.d( + v8i16_r = __msa_dpsub_s_h(v8i16_r, v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.s.h( + v4i32_r = __msa_dpsub_s_w(v4i32_r, v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.s.w( + v2i64_r = __msa_dpsub_s_d(v2i64_r, v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.s.d( - v8u16_r = __builtin_msa_dpsub_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.u.h( - v4u32_r = __builtin_msa_dpsub_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.u.w( - v2u64_r = __builtin_msa_dpsub_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.u.d( + v8u16_r = __msa_dpsub_u_h(v8u16_r, v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.dpsub.u.h( + v4u32_r = __msa_dpsub_u_w(v4u32_r, v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.dpsub.u.w( + v2u64_r = __msa_dpsub_u_d(v2u64_r, v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.dpsub.u.d( - v4f32_r = __builtin_msa_fadd_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fadd.w( - v2f64_r = __builtin_msa_fadd_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fadd.d( + v4f32_r = __msa_fadd_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fadd.w( + v2f64_r = __msa_fadd_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fadd.d( - v4i32_r = __builtin_msa_fcaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcaf.w( - v2i64_r = __builtin_msa_fcaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcaf.d( + v4i32_r = __msa_fcaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcaf.w( + v2i64_r = __msa_fcaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcaf.d( - v4i32_r = __builtin_msa_fceq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fceq.w( - v2i64_r = __builtin_msa_fceq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fceq.d( + v4i32_r = __msa_fceq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fceq.w( + v2i64_r = __msa_fceq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fceq.d( - v4i32_r = __builtin_msa_fclass_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.fclass.w( - v2i64_r = __builtin_msa_fclass_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.fclass.d( + v4i32_r = __msa_fclass_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.fclass.w( + v2i64_r = __msa_fclass_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.fclass.d( - v4i32_r = __builtin_msa_fcle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcle.w( - v2i64_r = __builtin_msa_fcle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcle.d( + v4i32_r = __msa_fcle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcle.w( + v2i64_r = __msa_fcle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcle.d( - v4i32_r = __builtin_msa_fclt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fclt.w( - v2i64_r = __builtin_msa_fclt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fclt.d( + v4i32_r = __msa_fclt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fclt.w( + v2i64_r = __msa_fclt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fclt.d( - v4i32_r = __builtin_msa_fcne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcne.w( - v2i64_r = __builtin_msa_fcne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcne.d( + v4i32_r = __msa_fcne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcne.w( + v2i64_r = __msa_fcne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcne.d( - v4i32_r = __builtin_msa_fcor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcor.w( - v2i64_r = __builtin_msa_fcor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcor.d( + v4i32_r = __msa_fcor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcor.w( + v2i64_r = __msa_fcor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcor.d( - v4i32_r = __builtin_msa_fcueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcueq.w( - v2i64_r = __builtin_msa_fcueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcueq.d( + v4i32_r = __msa_fcueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcueq.w( + v2i64_r = __msa_fcueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcueq.d( - v4i32_r = __builtin_msa_fcule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcule.w( - v2i64_r = __builtin_msa_fcule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcule.d( + v4i32_r = __msa_fcule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcule.w( + v2i64_r = __msa_fcule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcule.d( - v4i32_r = __builtin_msa_fcult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcult.w( - v2i64_r = __builtin_msa_fcult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcult.d( + v4i32_r = __msa_fcult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcult.w( + v2i64_r = __msa_fcult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcult.d( - v4i32_r = __builtin_msa_fcun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcun.w( - v2i64_r = __builtin_msa_fcun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcun.d( + v4i32_r = __msa_fcun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcun.w( + v2i64_r = __msa_fcun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcun.d( - v4i32_r = __builtin_msa_fcune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcune.w( - v2i64_r = __builtin_msa_fcune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcune.d( + v4i32_r = __msa_fcune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fcune.w( + v2i64_r = __msa_fcune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fcune.d( - v4f32_r = __builtin_msa_fdiv_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fdiv.w( - v2f64_r = __builtin_msa_fdiv_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fdiv.d( + v4f32_r = __msa_fdiv_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fdiv.w( + v2f64_r = __msa_fdiv_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fdiv.d( - v8f16_r = __builtin_msa_fexdo_h(v4f32_a, v4f32_b); // CHECK: call <8 x half> @llvm.mips.fexdo.h( - v4f32_r = __builtin_msa_fexdo_w(v2f64_a, v2f64_b); // CHECK: call <4 x float> @llvm.mips.fexdo.w( + v8f16_r = __msa_fexdo_h(v4f32_a, v4f32_b); // CHECK: call <8 x half> @llvm.mips.fexdo.h( + v4f32_r = __msa_fexdo_w(v2f64_a, v2f64_b); // CHECK: call <4 x float> @llvm.mips.fexdo.w( - v4f32_r = __builtin_msa_fexp2_w(v4f32_a, v4i32_b); // CHECK: call <4 x float> @llvm.mips.fexp2.w( - v2f64_r = __builtin_msa_fexp2_d(v2f64_a, v2i64_b); // CHECK: call <2 x double> @llvm.mips.fexp2.d( + v4f32_r = __msa_fexp2_w(v4f32_a, v4i32_b); // CHECK: call <4 x float> @llvm.mips.fexp2.w( + v2f64_r = __msa_fexp2_d(v2f64_a, v2i64_b); // CHECK: call <2 x double> @llvm.mips.fexp2.d( - v4f32_r = __builtin_msa_fexupl_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupl.w( - v2f64_r = __builtin_msa_fexupl_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupl.d( + v4f32_r = __msa_fexupl_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupl.w( + v2f64_r = __msa_fexupl_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupl.d( - v4f32_r = __builtin_msa_fexupr_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupr.w( - v2f64_r = __builtin_msa_fexupr_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupr.d( + v4f32_r = __msa_fexupr_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fexupr.w( + v2f64_r = __msa_fexupr_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fexupr.d( - v4f32_r = __builtin_msa_ffint_s_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.s.w( - v2f64_r = __builtin_msa_ffint_s_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.s.d( + v4f32_r = __msa_ffint_s_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.s.w( + v2f64_r = __msa_ffint_s_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.s.d( - v4f32_r = __builtin_msa_ffint_u_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.u.w( - v2f64_r = __builtin_msa_ffint_u_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.u.d( + v4f32_r = __msa_ffint_u_w(v4i32_a); // CHECK: call <4 x float> @llvm.mips.ffint.u.w( + v2f64_r = __msa_ffint_u_d(v2i64_a); // CHECK: call <2 x double> @llvm.mips.ffint.u.d( - v4f32_r = __builtin_msa_ffql_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffql.w( - v2f64_r = __builtin_msa_ffql_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffql.d( + v4f32_r = __msa_ffql_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffql.w( + v2f64_r = __msa_ffql_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffql.d( - v4f32_r = __builtin_msa_ffqr_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffqr.w( - v2f64_r = __builtin_msa_ffqr_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffqr.d( + v4f32_r = __msa_ffqr_w(v8i16_a); // CHECK: call <4 x float> @llvm.mips.ffqr.w( + v2f64_r = __msa_ffqr_d(v4i32_a); // CHECK: call <2 x double> @llvm.mips.ffqr.d( - v16i8_r = __builtin_msa_fill_b(3); // CHECK: call <16 x i8> @llvm.mips.fill.b( - v8i16_r = __builtin_msa_fill_h(3); // CHECK: call <8 x i16> @llvm.mips.fill.h( - v4i32_r = __builtin_msa_fill_w(3); // CHECK: call <4 x i32> @llvm.mips.fill.w( - v2i64_r = __builtin_msa_fill_d(3); // CHECK: call <2 x i64> @llvm.mips.fill.d( + v16i8_r = __msa_fill_b(3); // CHECK: call <16 x i8> @llvm.mips.fill.b( + v8i16_r = __msa_fill_h(3); // CHECK: call <8 x i16> @llvm.mips.fill.h( + v4i32_r = __msa_fill_w(3); // CHECK: call <4 x i32> @llvm.mips.fill.w( + v2i64_r = __msa_fill_d(3); // CHECK: call <2 x i64> @llvm.mips.fill.d( - v4f32_r = __builtin_msa_flog2_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.flog2.w( - v2f64_r = __builtin_msa_flog2_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.flog2.d( + v4f32_r = __msa_flog2_w(v4f32_a); // CHECK: call <4 x float> @llvm.mips.flog2.w( + v2f64_r = __msa_flog2_d(v2f64_a); // CHECK: call <2 x double> @llvm.mips.flog2.d( - v4f32_r = __builtin_msa_fmadd_w(v8f16_r, v8f16_a, v8f16_b); // CHECK: call <4 x float> @llvm.mips.fmadd.w( - v2f64_r = __builtin_msa_fmadd_d(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <2 x double> @llvm.mips.fmadd.d( + v4f32_r = __msa_fmadd_w(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmadd.w( + v2f64_r = __msa_fmadd_d(v2f64_r, v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmadd.d( - v4f32_r = __builtin_msa_fmax_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.w( - v2f64_r = __builtin_msa_fmax_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.d( + v4f32_r = __msa_fmax_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.w( + v2f64_r = __msa_fmax_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.d( - v4f32_r = __builtin_msa_fmax_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.a.w( - v2f64_r = __builtin_msa_fmax_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.a.d( + v4f32_r = __msa_fmax_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmax.a.w( + v2f64_r = __msa_fmax_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmax.a.d( - v4f32_r = __builtin_msa_fmin_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.w( - v2f64_r = __builtin_msa_fmin_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.d( + v4f32_r = __msa_fmin_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.w( + v2f64_r = __msa_fmin_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.d( - v4f32_r = __builtin_msa_fmin_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.a.w( - v2f64_r = __builtin_msa_fmin_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.a.d( + v4f32_r = __msa_fmin_a_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmin.a.w( + v2f64_r = __msa_fmin_a_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmin.a.d( - v4f32_r = __builtin_msa_fmsub_w(v8f16_r, v8f16_a, v8f16_b); // CHECK: call <4 x float> @llvm.mips.fmsub.w( - v2f64_r = __builtin_msa_fmsub_d(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <2 x double> @llvm.mips.fmsub.d( + v4f32_r = __msa_fmsub_w(v4f32_r, v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmsub.w( + v2f64_r = __msa_fmsub_d(v2f64_r, v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmsub.d( - v4f32_r = __builtin_msa_fmul_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmul.w( - v2f64_r = __builtin_msa_fmul_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmul.d( + v4f32_r = __msa_fmul_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fmul.w( + v2f64_r = __msa_fmul_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fmul.d( - v4f32_r = __builtin_msa_frint_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frint.w( - v2f64_r = __builtin_msa_frint_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frint.d( + v4f32_r = __msa_frint_w(v4f32_a); // CHECK: call <4 x float> @llvm.mips.frint.w( + v2f64_r = __msa_frint_d(v2f64_a); // CHECK: call <2 x double> @llvm.mips.frint.d( - v4f32_r = __builtin_msa_frcp_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frcp.w( - v2f64_r = __builtin_msa_frcp_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frcp.d( + v4f32_r = __msa_frcp_w(v4f32_a); // CHECK: call <4 x float> @llvm.mips.frcp.w( + v2f64_r = __msa_frcp_d(v2f64_a); // CHECK: call <2 x double> @llvm.mips.frcp.d( - v4f32_r = __builtin_msa_frsqrt_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.frsqrt.w( - v2f64_r = __builtin_msa_frsqrt_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.frsqrt.d( + v4f32_r = __msa_frsqrt_w(v4f32_a); // CHECK: call <4 x float> @llvm.mips.frsqrt.w( + v2f64_r = __msa_frsqrt_d(v2f64_a); // CHECK: call <2 x double> @llvm.mips.frsqrt.d( - v4i32_r = __builtin_msa_fseq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fseq.w( - v2i64_r = __builtin_msa_fseq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fseq.d( + v4i32_r = __msa_fseq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fseq.w( + v2i64_r = __msa_fseq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fseq.d( - v4i32_r = __builtin_msa_fsaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsaf.w( - v2i64_r = __builtin_msa_fsaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsaf.d( + v4i32_r = __msa_fsaf_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsaf.w( + v2i64_r = __msa_fsaf_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsaf.d( - v4i32_r = __builtin_msa_fsle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsle.w( - v2i64_r = __builtin_msa_fsle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsle.d( + v4i32_r = __msa_fsle_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsle.w( + v2i64_r = __msa_fsle_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsle.d( - v4i32_r = __builtin_msa_fslt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fslt.w( - v2i64_r = __builtin_msa_fslt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fslt.d( + v4i32_r = __msa_fslt_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fslt.w( + v2i64_r = __msa_fslt_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fslt.d( - v4i32_r = __builtin_msa_fsne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsne.w( - v2i64_r = __builtin_msa_fsne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsne.d( + v4i32_r = __msa_fsne_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsne.w( + v2i64_r = __msa_fsne_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsne.d( - v4i32_r = __builtin_msa_fsor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsor.w( - v2i64_r = __builtin_msa_fsor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsor.d( + v4i32_r = __msa_fsor_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsor.w( + v2i64_r = __msa_fsor_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsor.d( - v4f32_r = __builtin_msa_fsqrt_w(v8f16_a); // CHECK: call <4 x float> @llvm.mips.fsqrt.w( - v2f64_r = __builtin_msa_fsqrt_d(v4f32_a); // CHECK: call <2 x double> @llvm.mips.fsqrt.d( + v4f32_r = __msa_fsqrt_w(v4f32_a); // CHECK: call <4 x float> @llvm.mips.fsqrt.w( + v2f64_r = __msa_fsqrt_d(v2f64_a); // CHECK: call <2 x double> @llvm.mips.fsqrt.d( - v4f32_r = __builtin_msa_fsub_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fsub.w( - v2f64_r = __builtin_msa_fsub_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fsub.d( + v4f32_r = __msa_fsub_w(v4f32_a, v4f32_b); // CHECK: call <4 x float> @llvm.mips.fsub.w( + v2f64_r = __msa_fsub_d(v2f64_a, v2f64_b); // CHECK: call <2 x double> @llvm.mips.fsub.d( - v4i32_r = __builtin_msa_fsueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsueq.w( - v2i64_r = __builtin_msa_fsueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsueq.d( + v4i32_r = __msa_fsueq_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsueq.w( + v2i64_r = __msa_fsueq_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsueq.d( - v4i32_r = __builtin_msa_fsule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsule.w( - v2i64_r = __builtin_msa_fsule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsule.d( + v4i32_r = __msa_fsule_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsule.w( + v2i64_r = __msa_fsule_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsule.d( - v4i32_r = __builtin_msa_fsult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsult.w( - v2i64_r = __builtin_msa_fsult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsult.d( + v4i32_r = __msa_fsult_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsult.w( + v2i64_r = __msa_fsult_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsult.d( - v4i32_r = __builtin_msa_fsun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsun.w( - v2i64_r = __builtin_msa_fsun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsun.d( + v4i32_r = __msa_fsun_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsun.w( + v2i64_r = __msa_fsun_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsun.d( - v4i32_r = __builtin_msa_fsune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsune.w( - v2i64_r = __builtin_msa_fsune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsune.d( + v4i32_r = __msa_fsune_w(v4f32_a, v4f32_b); // CHECK: call <4 x i32> @llvm.mips.fsune.w( + v2i64_r = __msa_fsune_d(v2f64_a, v2f64_b); // CHECK: call <2 x i64> @llvm.mips.fsune.d( - v4i32_r = __builtin_msa_ftint_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.s.w( - v2i64_r = __builtin_msa_ftint_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.s.d( + v4i32_r = __msa_ftint_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.s.w( + v2i64_r = __msa_ftint_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.s.d( - v4i32_r = __builtin_msa_ftint_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.u.w( - v2i64_r = __builtin_msa_ftint_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.u.d( + v4i32_r = __msa_ftint_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftint.u.w( + v2i64_r = __msa_ftint_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftint.u.d( - v8i16_r = __builtin_msa_ftq_h(v4f32_a, v4f32_b); // CHECK: call <8 x i16> @llvm.mips.ftq.h( - v4i32_r = __builtin_msa_ftq_w(v2f64_a, v2f64_b); // CHECK: call <4 x i32> @llvm.mips.ftq.w( + v8i16_r = __msa_ftq_h(v4f32_a, v4f32_b); // CHECK: call <8 x i16> @llvm.mips.ftq.h( + v4i32_r = __msa_ftq_w(v2f64_a, v2f64_b); // CHECK: call <4 x i32> @llvm.mips.ftq.w( - v4i32_r = __builtin_msa_ftrunc_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.s.w( - v2i64_r = __builtin_msa_ftrunc_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.s.d( + v4i32_r = __msa_ftrunc_s_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.s.w( + v2i64_r = __msa_ftrunc_s_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.s.d( - v4i32_r = __builtin_msa_ftrunc_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.u.w( - v2i64_r = __builtin_msa_ftrunc_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.u.d( + v4i32_r = __msa_ftrunc_u_w(v4f32_a); // CHECK: call <4 x i32> @llvm.mips.ftrunc.u.w( + v2i64_r = __msa_ftrunc_u_d(v2f64_a); // CHECK: call <2 x i64> @llvm.mips.ftrunc.u.d( - v8i16_r = __builtin_msa_hadd_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.s.h( - v4i32_r = __builtin_msa_hadd_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.s.w( - v2i64_r = __builtin_msa_hadd_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.s.d( + v8i16_r = __msa_hadd_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.s.h( + v4i32_r = __msa_hadd_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.s.w( + v2i64_r = __msa_hadd_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.s.d( - v8u16_r = __builtin_msa_hadd_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.u.h( - v4u32_r = __builtin_msa_hadd_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.u.w( - v2u64_r = __builtin_msa_hadd_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.u.d( + v8u16_r = __msa_hadd_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hadd.u.h( + v4u32_r = __msa_hadd_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hadd.u.w( + v2u64_r = __msa_hadd_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hadd.u.d( - v8i16_r = __builtin_msa_hsub_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.s.h( - v4i32_r = __builtin_msa_hsub_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.s.w( - v2i64_r = __builtin_msa_hsub_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.s.d( + v8i16_r = __msa_hsub_s_h(v16i8_a, v16i8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.s.h( + v4i32_r = __msa_hsub_s_w(v8i16_a, v8i16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.s.w( + v2i64_r = __msa_hsub_s_d(v4i32_a, v4i32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.s.d( - v8u16_r = __builtin_msa_hsub_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.u.h( - v4u32_r = __builtin_msa_hsub_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.u.w( - v2u64_r = __builtin_msa_hsub_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.u.d( + v8u16_r = __msa_hsub_u_h(v16u8_a, v16u8_b); // CHECK: call <8 x i16> @llvm.mips.hsub.u.h( + v4u32_r = __msa_hsub_u_w(v8u16_a, v8u16_b); // CHECK: call <4 x i32> @llvm.mips.hsub.u.w( + v2u64_r = __msa_hsub_u_d(v4u32_a, v4u32_b); // CHECK: call <2 x i64> @llvm.mips.hsub.u.d( - v16i8_r = __builtin_msa_ilvev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvev.b( - v8i16_r = __builtin_msa_ilvev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvev.h( - v4i32_r = __builtin_msa_ilvev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvev.w( - v2i64_r = __builtin_msa_ilvev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvev.d( + v16i8_r = __msa_ilvev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvev.b( + v8i16_r = __msa_ilvev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvev.h( + v4i32_r = __msa_ilvev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvev.w( + v2i64_r = __msa_ilvev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvev.d( - v16i8_r = __builtin_msa_ilvl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvl.b( - v8i16_r = __builtin_msa_ilvl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvl.h( - v4i32_r = __builtin_msa_ilvl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvl.w( - v2i64_r = __builtin_msa_ilvl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvl.d( + v16i8_r = __msa_ilvl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvl.b( + v8i16_r = __msa_ilvl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvl.h( + v4i32_r = __msa_ilvl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvl.w( + v2i64_r = __msa_ilvl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvl.d( - v16i8_r = __builtin_msa_ilvod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvod.b( - v8i16_r = __builtin_msa_ilvod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvod.h( - v4i32_r = __builtin_msa_ilvod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvod.w( - v2i64_r = __builtin_msa_ilvod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvod.d( + v16i8_r = __msa_ilvod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvod.b( + v8i16_r = __msa_ilvod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvod.h( + v4i32_r = __msa_ilvod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvod.w( + v2i64_r = __msa_ilvod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvod.d( - v16i8_r = __builtin_msa_ilvr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvr.b( - v8i16_r = __builtin_msa_ilvr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvr.h( - v4i32_r = __builtin_msa_ilvr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvr.w( - v2i64_r = __builtin_msa_ilvr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvr.d( + v16i8_r = __msa_ilvr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.ilvr.b( + v8i16_r = __msa_ilvr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.ilvr.h( + v4i32_r = __msa_ilvr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.ilvr.w( + v2i64_r = __msa_ilvr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.ilvr.d( - v16i8_r = __builtin_msa_insert_b(v16i8_r, 1, 25); // CHECK: call <16 x i8> @llvm.mips.insert.b( - v8i16_r = __builtin_msa_insert_h(v8i16_r, 1, 25); // CHECK: call <8 x i16> @llvm.mips.insert.h( - v4i32_r = __builtin_msa_insert_w(v4i32_r, 1, 25); // CHECK: call <4 x i32> @llvm.mips.insert.w( - v2i64_r = __builtin_msa_insert_d(v2i64_r, 1, 25); // CHECK: call <2 x i64> @llvm.mips.insert.d( + v16i8_r = __msa_insert_b(v16i8_r, 1, 25); // CHECK: call <16 x i8> @llvm.mips.insert.b( + v8i16_r = __msa_insert_h(v8i16_r, 1, 25); // CHECK: call <8 x i16> @llvm.mips.insert.h( + v4i32_r = __msa_insert_w(v4i32_r, 1, 25); // CHECK: call <4 x i32> @llvm.mips.insert.w( + v2i64_r = __msa_insert_d(v2i64_r, 1, 25); // CHECK: call <2 x i64> @llvm.mips.insert.d( - v16i8_r = __builtin_msa_insve_b(v16i8_r, 1, v16i8_a); // CHECK: call <16 x i8> @llvm.mips.insve.b( - v8i16_r = __builtin_msa_insve_h(v8i16_r, 1, v8i16_a); // CHECK: call <8 x i16> @llvm.mips.insve.h( - v4i32_r = __builtin_msa_insve_w(v4i32_r, 1, v4i32_a); // CHECK: call <4 x i32> @llvm.mips.insve.w( - v2i64_r = __builtin_msa_insve_d(v2i64_r, 1, v2i64_a); // CHECK: call <2 x i64> @llvm.mips.insve.d( + v16i8_r = __msa_insve_b(v16i8_r, 1, v16i8_a); // CHECK: call <16 x i8> @llvm.mips.insve.b( + v8i16_r = __msa_insve_h(v8i16_r, 1, v8i16_a); // CHECK: call <8 x i16> @llvm.mips.insve.h( + v4i32_r = __msa_insve_w(v4i32_r, 1, v4i32_a); // CHECK: call <4 x i32> @llvm.mips.insve.w( + v2i64_r = __msa_insve_d(v2i64_r, 1, v2i64_a); // CHECK: call <2 x i64> @llvm.mips.insve.d( - v16i8_r = __builtin_msa_ld_b(&v16i8_a, 1); // CHECK: call <16 x i8> @llvm.mips.ld.b( - v8i16_r = __builtin_msa_ld_h(&v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.ld.h( - v4i32_r = __builtin_msa_ld_w(&v4i32_a, 4); // CHECK: call <4 x i32> @llvm.mips.ld.w( - v2i64_r = __builtin_msa_ld_d(&v2i64_a, 8); // CHECK: call <2 x i64> @llvm.mips.ld.d( + v16i8_r = __msa_ld_b(&v16i8_a, 16); // CHECK: call <16 x i8> @llvm.mips.ld.b( + v8i16_r = __msa_ld_h(&v8i16_a, 32); // CHECK: call <8 x i16> @llvm.mips.ld.h( + v4i32_r = __msa_ld_w(&v4i32_a, 48); // CHECK: call <4 x i32> @llvm.mips.ld.w( + v2i64_r = __msa_ld_d(&v2i64_a, 96); // CHECK: call <2 x i64> @llvm.mips.ld.d( - v16i8_r = __builtin_msa_ldi_b(3); // CHECK: call <16 x i8> @llvm.mips.ldi.b( - v8i16_r = __builtin_msa_ldi_h(3); // CHECK: call <8 x i16> @llvm.mips.ldi.h( - v4i32_r = __builtin_msa_ldi_w(3); // CHECK: call <4 x i32> @llvm.mips.ldi.w( - v2i64_r = __builtin_msa_ldi_d(3); // CHECK: call <2 x i64> @llvm.mips.ldi.d( + v16i8_r = __msa_ldi_b(3); // CHECK: call <16 x i8> @llvm.mips.ldi.b( + v8i16_r = __msa_ldi_h(3); // CHECK: call <8 x i16> @llvm.mips.ldi.h( + v4i32_r = __msa_ldi_w(3); // CHECK: call <4 x i32> @llvm.mips.ldi.w( + v2i64_r = __msa_ldi_d(3); // CHECK: call <2 x i64> @llvm.mips.ldi.d( - v8i16_r = __builtin_msa_madd_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.madd.q.h( - v4i32_r = __builtin_msa_madd_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.madd.q.w( - - v8i16_r = __builtin_msa_maddr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddr.q.h( - v4i32_r = __builtin_msa_maddr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddr.q.w( - - v16i8_r = __builtin_msa_maddv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.maddv.b( - v8i16_r = __builtin_msa_maddv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddv.h( - v4i32_r = __builtin_msa_maddv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddv.w( - v2i64_r = __builtin_msa_maddv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.maddv.d( - - v16i8_r = __builtin_msa_max_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.a.b( - v8i16_r = __builtin_msa_max_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.a.h( - v4i32_r = __builtin_msa_max_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.a.w( - v2i64_r = __builtin_msa_max_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.a.d( - - v16i8_r = __builtin_msa_max_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.s.b( - v8i16_r = __builtin_msa_max_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.s.h( - v4i32_r = __builtin_msa_max_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.s.w( - v2i64_r = __builtin_msa_max_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.s.d( - - v16u8_r = __builtin_msa_max_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.max.u.b( - v8u16_r = __builtin_msa_max_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.max.u.h( - v4u32_r = __builtin_msa_max_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.max.u.w( - v2u64_r = __builtin_msa_max_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.max.u.d( - - v16i8_r = __builtin_msa_maxi_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.s.b( - v8i16_r = __builtin_msa_maxi_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.s.h( - v4i32_r = __builtin_msa_maxi_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.s.w( - v2i64_r = __builtin_msa_maxi_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.s.d( - - v16u8_r = __builtin_msa_maxi_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.u.b( - v8u16_r = __builtin_msa_maxi_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.u.h( - v4u32_r = __builtin_msa_maxi_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.u.w( - v2u64_r = __builtin_msa_maxi_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.u.d( - - v16i8_r = __builtin_msa_min_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.a.b( - v8i16_r = __builtin_msa_min_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.a.h( - v4i32_r = __builtin_msa_min_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.a.w( - v2i64_r = __builtin_msa_min_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.a.d( - - v16i8_r = __builtin_msa_min_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.s.b( - v8i16_r = __builtin_msa_min_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.s.h( - v4i32_r = __builtin_msa_min_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.s.w( - v2i64_r = __builtin_msa_min_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.s.d( - - v16u8_r = __builtin_msa_min_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.min.u.b( - v8u16_r = __builtin_msa_min_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.min.u.h( - v4u32_r = __builtin_msa_min_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.min.u.w( - v2u64_r = __builtin_msa_min_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.min.u.d( - - v16i8_r = __builtin_msa_mini_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.s.b( - v8i16_r = __builtin_msa_mini_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.s.h( - v4i32_r = __builtin_msa_mini_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.s.w( - v2i64_r = __builtin_msa_mini_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.s.d( - - v16u8_r = __builtin_msa_mini_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.u.b( - v8u16_r = __builtin_msa_mini_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.u.h( - v4u32_r = __builtin_msa_mini_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.u.w( - v2u64_r = __builtin_msa_mini_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.u.d( - - v16i8_r = __builtin_msa_mod_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mod.s.b( - v8i16_r = __builtin_msa_mod_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mod.s.h( - v4i32_r = __builtin_msa_mod_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mod.s.w( - v2i64_r = __builtin_msa_mod_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mod.s.d( - - v16u8_r = __builtin_msa_mod_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.mod.u.b( - v8u16_r = __builtin_msa_mod_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.mod.u.h( - v4u32_r = __builtin_msa_mod_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.mod.u.w( - v2u64_r = __builtin_msa_mod_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.mod.u.d( - - v16i8_r = __builtin_msa_move_v(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.move.v( - - v8i16_r = __builtin_msa_msub_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msub.q.h( - v4i32_r = __builtin_msa_msub_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msub.q.w( - - v8i16_r = __builtin_msa_msubr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubr.q.h( - v4i32_r = __builtin_msa_msubr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubr.q.w( - - v16i8_r = __builtin_msa_msubv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.msubv.b( - v8i16_r = __builtin_msa_msubv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubv.h( - v4i32_r = __builtin_msa_msubv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubv.w( - v2i64_r = __builtin_msa_msubv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.msubv.d( - - v8i16_r = __builtin_msa_mul_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mul.q.h( - v4i32_r = __builtin_msa_mul_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mul.q.w( - - v8i16_r = __builtin_msa_mulr_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulr.q.h( - v4i32_r = __builtin_msa_mulr_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulr.q.w( - - v16i8_r = __builtin_msa_mulv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mulv.b( - v8i16_r = __builtin_msa_mulv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulv.h( - v4i32_r = __builtin_msa_mulv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulv.w( - v2i64_r = __builtin_msa_mulv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mulv.d( - - v16i8_r = __builtin_msa_nloc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nloc.b( - v8i16_r = __builtin_msa_nloc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nloc.h( - v4i32_r = __builtin_msa_nloc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nloc.w( - v2i64_r = __builtin_msa_nloc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nloc.d( - - v16i8_r = __builtin_msa_nlzc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nlzc.b( - v8i16_r = __builtin_msa_nlzc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nlzc.h( - v4i32_r = __builtin_msa_nlzc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nlzc.w( - v2i64_r = __builtin_msa_nlzc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nlzc.d( - - v16i8_r = __builtin_msa_nor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( - v8i16_r = __builtin_msa_nor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( - v4i32_r = __builtin_msa_nor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( - v2i64_r = __builtin_msa_nor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( - - v16i8_r = __builtin_msa_nori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v8i16_r = __builtin_msa_nori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v4i32_r = __builtin_msa_nori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v2i64_r = __builtin_msa_nori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - - v16u8_r = __builtin_msa_nori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v8u16_r = __builtin_msa_nori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v4u32_r = __builtin_msa_nori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - v2u64_r = __builtin_msa_nori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( - - v16i8_r = __builtin_msa_or_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.or.v( - v8i16_r = __builtin_msa_or_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.or.v( - v4i32_r = __builtin_msa_or_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.or.v( - v2i64_r = __builtin_msa_or_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.or.v( - - v16i8_r = __builtin_msa_ori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v8i16_r = __builtin_msa_ori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v4i32_r = __builtin_msa_ori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v2i64_r = __builtin_msa_ori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - - v16u8_r = __builtin_msa_ori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v8u16_r = __builtin_msa_ori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v4u32_r = __builtin_msa_ori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - v2u64_r = __builtin_msa_ori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( - - v16i8_r = __builtin_msa_pckev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckev.b( - v8i16_r = __builtin_msa_pckev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckev.h( - v4i32_r = __builtin_msa_pckev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckev.w( - v2i64_r = __builtin_msa_pckev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckev.d( - - v16i8_r = __builtin_msa_pckod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckod.b( - v8i16_r = __builtin_msa_pckod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckod.h( - v4i32_r = __builtin_msa_pckod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckod.w( - v2i64_r = __builtin_msa_pckod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckod.d( - - v16i8_r = __builtin_msa_pcnt_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.pcnt.b( - v8i16_r = __builtin_msa_pcnt_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.pcnt.h( - v4i32_r = __builtin_msa_pcnt_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.pcnt.w( - v2i64_r = __builtin_msa_pcnt_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.pcnt.d( - - v16i8_r = __builtin_msa_sat_s_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.s.b( - v8i16_r = __builtin_msa_sat_s_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.s.h( - v4i32_r = __builtin_msa_sat_s_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.s.w( - v2i64_r = __builtin_msa_sat_s_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.s.d( - - v16i8_r = __builtin_msa_sat_u_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.u.b( - v8i16_r = __builtin_msa_sat_u_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.u.h( - v4i32_r = __builtin_msa_sat_u_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.u.w( - v2i64_r = __builtin_msa_sat_u_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.u.d( - - v16i8_r = __builtin_msa_shf_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.shf.b( - v8i16_r = __builtin_msa_shf_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.shf.h( - v4i32_r = __builtin_msa_shf_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.shf.w( - - v16i8_r = __builtin_msa_sld_b(v16i8_r, v16i8_a, 10); // CHECK: call <16 x i8> @llvm.mips.sld.b( - v8i16_r = __builtin_msa_sld_h(v8i16_r, v8i16_a, 10); // CHECK: call <8 x i16> @llvm.mips.sld.h( - v4i32_r = __builtin_msa_sld_w(v4i32_r, v4i32_a, 10); // CHECK: call <4 x i32> @llvm.mips.sld.w( - v2i64_r = __builtin_msa_sld_d(v2i64_r, v2i64_a, 10); // CHECK: call <2 x i64> @llvm.mips.sld.d( - - v16i8_r = __builtin_msa_sldi_b(v16i8_r, v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sldi.b( - v8i16_r = __builtin_msa_sldi_h(v8i16_r, v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sldi.h( - v4i32_r = __builtin_msa_sldi_w(v4i32_r, v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sldi.w( - v2i64_r = __builtin_msa_sldi_d(v2i64_r, v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sldi.d( - - v16i8_r = __builtin_msa_sll_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sll.b( - v8i16_r = __builtin_msa_sll_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sll.h( - v4i32_r = __builtin_msa_sll_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sll.w( - v2i64_r = __builtin_msa_sll_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sll.d( - - v16i8_r = __builtin_msa_slli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.slli.b( - v8i16_r = __builtin_msa_slli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.slli.h( - v4i32_r = __builtin_msa_slli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.slli.w( - v2i64_r = __builtin_msa_slli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.slli.d( - - v16i8_r = __builtin_msa_splat_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splat.b( - v8i16_r = __builtin_msa_splat_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splat.h( - v4i32_r = __builtin_msa_splat_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splat.w( - v2i64_r = __builtin_msa_splat_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.splat.d( - - v16i8_r = __builtin_msa_splati_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splati.b( - v8i16_r = __builtin_msa_splati_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splati.h( - v4i32_r = __builtin_msa_splati_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splati.w( - v2i64_r = __builtin_msa_splati_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.splati.d( - - v16i8_r = __builtin_msa_sra_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sra.b( - v8i16_r = __builtin_msa_sra_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sra.h( - v4i32_r = __builtin_msa_sra_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sra.w( - v2i64_r = __builtin_msa_sra_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sra.d( - - v16i8_r = __builtin_msa_srai_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srai.b( - v8i16_r = __builtin_msa_srai_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srai.h( - v4i32_r = __builtin_msa_srai_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srai.w( - v2i64_r = __builtin_msa_srai_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srai.d( - - v16i8_r = __builtin_msa_srar_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srar.b( - v8i16_r = __builtin_msa_srar_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srar.h( - v4i32_r = __builtin_msa_srar_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srar.w( - v2i64_r = __builtin_msa_srar_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srar.d( - - v16i8_r = __builtin_msa_srari_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srari.b( - v8i16_r = __builtin_msa_srari_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srari.h( - v4i32_r = __builtin_msa_srari_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srari.w( - v2i64_r = __builtin_msa_srari_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srari.d( - - v16i8_r = __builtin_msa_srl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srl.b( - v8i16_r = __builtin_msa_srl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srl.h( - v4i32_r = __builtin_msa_srl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srl.w( - v2i64_r = __builtin_msa_srl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srl.d( - - v16i8_r = __builtin_msa_srli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srli.b( - v8i16_r = __builtin_msa_srli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srli.h( - v4i32_r = __builtin_msa_srli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srli.w( - v2i64_r = __builtin_msa_srli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srli.d( - - v16i8_r = __builtin_msa_srlr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srlr.b( - v8i16_r = __builtin_msa_srlr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srlr.h( - v4i32_r = __builtin_msa_srlr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srlr.w( - v2i64_r = __builtin_msa_srlr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srlr.d( - - v16i8_r = __builtin_msa_srlri_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srlri.b( - v8i16_r = __builtin_msa_srlri_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srlri.h( - v4i32_r = __builtin_msa_srlri_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srlri.w( - v2i64_r = __builtin_msa_srlri_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srlri.d( - - __builtin_msa_st_b(v16i8_b, &v16i8_a, 1); // CHECK: call void @llvm.mips.st.b( - __builtin_msa_st_h(v8i16_b, &v8i16_a, 2); // CHECK: call void @llvm.mips.st.h( - __builtin_msa_st_w(v4i32_b, &v4i32_a, 4); // CHECK: call void @llvm.mips.st.w( - __builtin_msa_st_d(v2i64_b, &v2i64_a, 8); // CHECK: call void @llvm.mips.st.d( - - v16i8_r = __builtin_msa_subs_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subs.s.b( - v8i16_r = __builtin_msa_subs_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subs.s.h( - v4i32_r = __builtin_msa_subs_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subs.s.w( - v2i64_r = __builtin_msa_subs_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subs.s.d( - - v16u8_r = __builtin_msa_subs_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subs.u.b( - v8u16_r = __builtin_msa_subs_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subs.u.h( - v4u32_r = __builtin_msa_subs_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subs.u.w( - v2u64_r = __builtin_msa_subs_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subs.u.d( - - v16u8_r = __builtin_msa_subsus_u_b(v16u8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subsus.u.b( - v8u16_r = __builtin_msa_subsus_u_h(v8u16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subsus.u.h( - v4u32_r = __builtin_msa_subsus_u_w(v4u32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subsus.u.w( - v2u64_r = __builtin_msa_subsus_u_d(v2u64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subsus.u.d( - - v16i8_r = __builtin_msa_subsuu_s_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subsuu.s.b( - v8i16_r = __builtin_msa_subsuu_s_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subsuu.s.h( - v4i32_r = __builtin_msa_subsuu_s_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subsuu.s.w( - v2i64_r = __builtin_msa_subsuu_s_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subsuu.s.d( - - v16i8_r = __builtin_msa_subv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subv.b( - v8i16_r = __builtin_msa_subv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subv.h( - v4i32_r = __builtin_msa_subv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subv.w( - v2i64_r = __builtin_msa_subv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subv.d( - - v16i8_r = __builtin_msa_subvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.subvi.b( - v8i16_r = __builtin_msa_subvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.subvi.h( - v4i32_r = __builtin_msa_subvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.subvi.w( - v2i64_r = __builtin_msa_subvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.subvi.d( - - v16i8_r = __builtin_msa_vshf_b(v16i8_a, v16i8_b, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.vshf.b( - v8i16_r = __builtin_msa_vshf_h(v8i16_a, v8i16_b, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.vshf.h( - v4i32_r = __builtin_msa_vshf_w(v4i32_a, v4i32_b, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.vshf.w( - v2i64_r = __builtin_msa_vshf_d(v2i64_a, v2i64_b, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.vshf.d( - - v16i8_r = __builtin_msa_xor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( - v8i16_r = __builtin_msa_xor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( - v4i32_r = __builtin_msa_xor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( - v2i64_r = __builtin_msa_xor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( - - v16i8_r = __builtin_msa_xori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v8i16_r = __builtin_msa_xori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v4i32_r = __builtin_msa_xori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v2i64_r = __builtin_msa_xori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - - v16u8_r = __builtin_msa_xori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v8u16_r = __builtin_msa_xori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v4u32_r = __builtin_msa_xori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( - v2u64_r = __builtin_msa_xori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v8i16_r = __msa_madd_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.madd.q.h( + v4i32_r = __msa_madd_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.madd.q.w( + + v8i16_r = __msa_maddr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddr.q.h( + v4i32_r = __msa_maddr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddr.q.w( + + v16i8_r = __msa_maddv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.maddv.b( + v8i16_r = __msa_maddv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.maddv.h( + v4i32_r = __msa_maddv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.maddv.w( + v2i64_r = __msa_maddv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.maddv.d( + + v16i8_r = __msa_max_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.a.b( + v8i16_r = __msa_max_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.a.h( + v4i32_r = __msa_max_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.a.w( + v2i64_r = __msa_max_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.a.d( + + v16i8_r = __msa_max_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.max.s.b( + v8i16_r = __msa_max_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.max.s.h( + v4i32_r = __msa_max_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.max.s.w( + v2i64_r = __msa_max_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.max.s.d( + + v16u8_r = __msa_max_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.max.u.b( + v8u16_r = __msa_max_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.max.u.h( + v4u32_r = __msa_max_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.max.u.w( + v2u64_r = __msa_max_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.max.u.d( + + v16i8_r = __msa_maxi_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.s.b( + v8i16_r = __msa_maxi_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.s.h( + v4i32_r = __msa_maxi_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.s.w( + v2i64_r = __msa_maxi_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.s.d( + + v16u8_r = __msa_maxi_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.maxi.u.b( + v8u16_r = __msa_maxi_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.maxi.u.h( + v4u32_r = __msa_maxi_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.maxi.u.w( + v2u64_r = __msa_maxi_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.maxi.u.d( + + v16i8_r = __msa_min_a_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.a.b( + v8i16_r = __msa_min_a_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.a.h( + v4i32_r = __msa_min_a_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.a.w( + v2i64_r = __msa_min_a_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.a.d( + + v16i8_r = __msa_min_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.min.s.b( + v8i16_r = __msa_min_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.min.s.h( + v4i32_r = __msa_min_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.min.s.w( + v2i64_r = __msa_min_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.min.s.d( + + v16u8_r = __msa_min_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.min.u.b( + v8u16_r = __msa_min_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.min.u.h( + v4u32_r = __msa_min_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.min.u.w( + v2u64_r = __msa_min_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.min.u.d( + + v16i8_r = __msa_mini_s_b(v16i8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.s.b( + v8i16_r = __msa_mini_s_h(v8i16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.s.h( + v4i32_r = __msa_mini_s_w(v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.s.w( + v2i64_r = __msa_mini_s_d(v2i64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.s.d( + + v16u8_r = __msa_mini_u_b(v16u8_a, 2); // CHECK: call <16 x i8> @llvm.mips.mini.u.b( + v8u16_r = __msa_mini_u_h(v8u16_a, 2); // CHECK: call <8 x i16> @llvm.mips.mini.u.h( + v4u32_r = __msa_mini_u_w(v4u32_a, 2); // CHECK: call <4 x i32> @llvm.mips.mini.u.w( + v2u64_r = __msa_mini_u_d(v2u64_a, 2); // CHECK: call <2 x i64> @llvm.mips.mini.u.d( + + v16i8_r = __msa_mod_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mod.s.b( + v8i16_r = __msa_mod_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mod.s.h( + v4i32_r = __msa_mod_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mod.s.w( + v2i64_r = __msa_mod_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mod.s.d( + + v16u8_r = __msa_mod_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.mod.u.b( + v8u16_r = __msa_mod_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.mod.u.h( + v4u32_r = __msa_mod_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.mod.u.w( + v2u64_r = __msa_mod_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.mod.u.d( + + v16i8_r = __msa_move_v(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.move.v( + + v8i16_r = __msa_msub_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msub.q.h( + v4i32_r = __msa_msub_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msub.q.w( + + v8i16_r = __msa_msubr_q_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubr.q.h( + v4i32_r = __msa_msubr_q_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubr.q.w( + + v16i8_r = __msa_msubv_b(v16i8_r, v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.msubv.b( + v8i16_r = __msa_msubv_h(v8i16_r, v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.msubv.h( + v4i32_r = __msa_msubv_w(v4i32_r, v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.msubv.w( + v2i64_r = __msa_msubv_d(v2i64_r, v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.msubv.d( + + v8i16_r = __msa_mul_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mul.q.h( + v4i32_r = __msa_mul_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mul.q.w( + + v8i16_r = __msa_mulr_q_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulr.q.h( + v4i32_r = __msa_mulr_q_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulr.q.w( + + v16i8_r = __msa_mulv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.mulv.b( + v8i16_r = __msa_mulv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.mulv.h( + v4i32_r = __msa_mulv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.mulv.w( + v2i64_r = __msa_mulv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.mulv.d( + + v16i8_r = __msa_nloc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nloc.b( + v8i16_r = __msa_nloc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nloc.h( + v4i32_r = __msa_nloc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nloc.w( + v2i64_r = __msa_nloc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nloc.d( + + v16i8_r = __msa_nlzc_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.nlzc.b( + v8i16_r = __msa_nlzc_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.nlzc.h( + v4i32_r = __msa_nlzc_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.nlzc.w( + v2i64_r = __msa_nlzc_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.nlzc.d( + + v16i8_r = __msa_nor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( + v8i16_r = __msa_nor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( + v4i32_r = __msa_nor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( + v2i64_r = __msa_nor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.nor.v( + + v16i8_r = __msa_nori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v8i16_r = __msa_nori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v4i32_r = __msa_nori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v2i64_r = __msa_nori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + + v16u8_r = __msa_nori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v8u16_r = __msa_nori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v4u32_r = __msa_nori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + v2u64_r = __msa_nori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.nori.b( + + v16i8_r = __msa_or_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.or.v( + v8i16_r = __msa_or_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.or.v( + v4i32_r = __msa_or_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.or.v( + v2i64_r = __msa_or_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.or.v( + + v16i8_r = __msa_ori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v8i16_r = __msa_ori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v4i32_r = __msa_ori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v2i64_r = __msa_ori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + + v16u8_r = __msa_ori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v8u16_r = __msa_ori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v4u32_r = __msa_ori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + v2u64_r = __msa_ori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.ori.b( + + v16i8_r = __msa_pckev_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckev.b( + v8i16_r = __msa_pckev_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckev.h( + v4i32_r = __msa_pckev_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckev.w( + v2i64_r = __msa_pckev_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckev.d( + + v16i8_r = __msa_pckod_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.pckod.b( + v8i16_r = __msa_pckod_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.pckod.h( + v4i32_r = __msa_pckod_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.pckod.w( + v2i64_r = __msa_pckod_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.pckod.d( + + v16i8_r = __msa_pcnt_b(v16i8_a); // CHECK: call <16 x i8> @llvm.mips.pcnt.b( + v8i16_r = __msa_pcnt_h(v8i16_a); // CHECK: call <8 x i16> @llvm.mips.pcnt.h( + v4i32_r = __msa_pcnt_w(v4i32_a); // CHECK: call <4 x i32> @llvm.mips.pcnt.w( + v2i64_r = __msa_pcnt_d(v2i64_a); // CHECK: call <2 x i64> @llvm.mips.pcnt.d( + + v16i8_r = __msa_sat_s_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.s.b( + v8i16_r = __msa_sat_s_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.s.h( + v4i32_r = __msa_sat_s_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.s.w( + v2i64_r = __msa_sat_s_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.s.d( + + v16i8_r = __msa_sat_u_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.sat.u.b( + v8i16_r = __msa_sat_u_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sat.u.h( + v4i32_r = __msa_sat_u_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sat.u.w( + v2i64_r = __msa_sat_u_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.sat.u.d( + + v16i8_r = __msa_shf_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.shf.b( + v8i16_r = __msa_shf_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.shf.h( + v4i32_r = __msa_shf_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.shf.w( + + v16i8_r = __msa_sld_b(v16i8_r, v16i8_a, 7); // CHECK: call <16 x i8> @llvm.mips.sld.b( + v8i16_r = __msa_sld_h(v8i16_r, v8i16_a, 5); // CHECK: call <8 x i16> @llvm.mips.sld.h( + v4i32_r = __msa_sld_w(v4i32_r, v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.sld.w( + v2i64_r = __msa_sld_d(v2i64_r, v2i64_a, 1); // CHECK: call <2 x i64> @llvm.mips.sld.d( + + v16i8_r = __msa_sldi_b(v16i8_r, v16i8_a, 7); // CHECK: call <16 x i8> @llvm.mips.sldi.b( + v8i16_r = __msa_sldi_h(v8i16_r, v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.sldi.h( + v4i32_r = __msa_sldi_w(v4i32_r, v4i32_a, 2); // CHECK: call <4 x i32> @llvm.mips.sldi.w( + v2i64_r = __msa_sldi_d(v2i64_r, v2i64_a, 1); // CHECK: call <2 x i64> @llvm.mips.sldi.d( + + v16i8_r = __msa_sll_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sll.b( + v8i16_r = __msa_sll_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sll.h( + v4i32_r = __msa_sll_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sll.w( + v2i64_r = __msa_sll_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sll.d( + + v16i8_r = __msa_slli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.slli.b( + v8i16_r = __msa_slli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.slli.h( + v4i32_r = __msa_slli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.slli.w( + v2i64_r = __msa_slli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.slli.d( + + v16i8_r = __msa_splat_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splat.b( + v8i16_r = __msa_splat_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splat.h( + v4i32_r = __msa_splat_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splat.w( + v2i64_r = __msa_splat_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.splat.d( + + v16i8_r = __msa_splati_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.splati.b( + v8i16_r = __msa_splati_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.splati.h( + v4i32_r = __msa_splati_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.splati.w( + v2i64_r = __msa_splati_d(v2i64_a, 1); // CHECK: call <2 x i64> @llvm.mips.splati.d( + + v16i8_r = __msa_sra_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.sra.b( + v8i16_r = __msa_sra_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.sra.h( + v4i32_r = __msa_sra_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.sra.w( + v2i64_r = __msa_sra_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.sra.d( + + v16i8_r = __msa_srai_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srai.b( + v8i16_r = __msa_srai_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srai.h( + v4i32_r = __msa_srai_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srai.w( + v2i64_r = __msa_srai_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srai.d( + + v16i8_r = __msa_srar_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srar.b( + v8i16_r = __msa_srar_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srar.h( + v4i32_r = __msa_srar_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srar.w( + v2i64_r = __msa_srar_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srar.d( + + v16i8_r = __msa_srari_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srari.b( + v8i16_r = __msa_srari_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srari.h( + v4i32_r = __msa_srari_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srari.w( + v2i64_r = __msa_srari_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srari.d( + + v16i8_r = __msa_srl_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srl.b( + v8i16_r = __msa_srl_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srl.h( + v4i32_r = __msa_srl_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srl.w( + v2i64_r = __msa_srl_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srl.d( + + v16i8_r = __msa_srli_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srli.b( + v8i16_r = __msa_srli_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srli.h( + v4i32_r = __msa_srli_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srli.w( + v2i64_r = __msa_srli_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srli.d( + + v16i8_r = __msa_srlr_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.srlr.b( + v8i16_r = __msa_srlr_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.srlr.h( + v4i32_r = __msa_srlr_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.srlr.w( + v2i64_r = __msa_srlr_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.srlr.d( + + v16i8_r = __msa_srlri_b(v16i8_a, 3); // CHECK: call <16 x i8> @llvm.mips.srlri.b( + v8i16_r = __msa_srlri_h(v8i16_a, 3); // CHECK: call <8 x i16> @llvm.mips.srlri.h( + v4i32_r = __msa_srlri_w(v4i32_a, 3); // CHECK: call <4 x i32> @llvm.mips.srlri.w( + v2i64_r = __msa_srlri_d(v2i64_a, 3); // CHECK: call <2 x i64> @llvm.mips.srlri.d( + + __msa_st_b(v16i8_b, &v16i8_a, 16); // CHECK: call void @llvm.mips.st.b( + __msa_st_h(v8i16_b, &v8i16_a, 32); // CHECK: call void @llvm.mips.st.h( + __msa_st_w(v4i32_b, &v4i32_a, 48); // CHECK: call void @llvm.mips.st.w( + __msa_st_d(v2i64_b, &v2i64_a, 96); // CHECK: call void @llvm.mips.st.d( + + v16i8_r = __msa_subs_s_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subs.s.b( + v8i16_r = __msa_subs_s_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subs.s.h( + v4i32_r = __msa_subs_s_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subs.s.w( + v2i64_r = __msa_subs_s_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subs.s.d( + + v16u8_r = __msa_subs_u_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subs.u.b( + v8u16_r = __msa_subs_u_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subs.u.h( + v4u32_r = __msa_subs_u_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subs.u.w( + v2u64_r = __msa_subs_u_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subs.u.d( + + v16u8_r = __msa_subsus_u_b(v16u8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subsus.u.b( + v8u16_r = __msa_subsus_u_h(v8u16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subsus.u.h( + v4u32_r = __msa_subsus_u_w(v4u32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subsus.u.w( + v2u64_r = __msa_subsus_u_d(v2u64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subsus.u.d( + + v16i8_r = __msa_subsuu_s_b(v16u8_a, v16u8_b); // CHECK: call <16 x i8> @llvm.mips.subsuu.s.b( + v8i16_r = __msa_subsuu_s_h(v8u16_a, v8u16_b); // CHECK: call <8 x i16> @llvm.mips.subsuu.s.h( + v4i32_r = __msa_subsuu_s_w(v4u32_a, v4u32_b); // CHECK: call <4 x i32> @llvm.mips.subsuu.s.w( + v2i64_r = __msa_subsuu_s_d(v2u64_a, v2u64_b); // CHECK: call <2 x i64> @llvm.mips.subsuu.s.d( + + v16i8_r = __msa_subv_b(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.subv.b( + v8i16_r = __msa_subv_h(v8i16_a, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.subv.h( + v4i32_r = __msa_subv_w(v4i32_a, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.subv.w( + v2i64_r = __msa_subv_d(v2i64_a, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.subv.d( + + v16i8_r = __msa_subvi_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.subvi.b( + v8i16_r = __msa_subvi_h(v8i16_a, 25); // CHECK: call <8 x i16> @llvm.mips.subvi.h( + v4i32_r = __msa_subvi_w(v4i32_a, 25); // CHECK: call <4 x i32> @llvm.mips.subvi.w( + v2i64_r = __msa_subvi_d(v2i64_a, 25); // CHECK: call <2 x i64> @llvm.mips.subvi.d( + + v16i8_r = __msa_vshf_b(v16i8_a, v16i8_b, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.vshf.b( + v8i16_r = __msa_vshf_h(v8i16_a, v8i16_b, v8i16_b); // CHECK: call <8 x i16> @llvm.mips.vshf.h( + v4i32_r = __msa_vshf_w(v4i32_a, v4i32_b, v4i32_b); // CHECK: call <4 x i32> @llvm.mips.vshf.w( + v2i64_r = __msa_vshf_d(v2i64_a, v2i64_b, v2i64_b); // CHECK: call <2 x i64> @llvm.mips.vshf.d( + + v16i8_r = __msa_xor_v(v16i8_a, v16i8_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( + v8i16_r = __msa_xor_v(v8i16_a, v8i16_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( + v4i32_r = __msa_xor_v(v4i32_a, v4i32_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( + v2i64_r = __msa_xor_v(v2i64_a, v2i64_b); // CHECK: call <16 x i8> @llvm.mips.xor.v( + + v16i8_r = __msa_xori_b(v16i8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v8i16_r = __msa_xori_b(v8i16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v4i32_r = __msa_xori_b(v4i32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v2i64_r = __msa_xori_b(v2i64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + + v16u8_r = __msa_xori_b(v16u8_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v8u16_r = __msa_xori_b(v8u16_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v4u32_r = __msa_xori_b(v4u32_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( + v2u64_r = __msa_xori_b(v2u64_a, 25); // CHECK: call <16 x i8> @llvm.mips.xori.b( } diff --git a/test/OpenMP/cancel_codegen.cpp b/test/OpenMP/cancel_codegen.cpp index 059a8d3901f4..a09214c9319c 100644 --- a/test/OpenMP/cancel_codegen.cpp +++ b/test/OpenMP/cancel_codegen.cpp @@ -1,174 +1,174 @@ // RUN: %clang_cc1 -verify -fopenmp -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - %s | FileCheck %s // RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-apple-darwin13.4.0 -emit-pch -o %t %s // RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -fsyntax-only -verify %s -triple x86_64-apple-darwin13.4.0 -emit-llvm -o - | FileCheck %s // expected-no-diagnostics // REQUIRES: x86-registered-target #ifndef HEADER #define HEADER float flag; int main (int argc, char **argv) { // CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num( #pragma omp parallel { #pragma omp cancel parallel if(flag) argv[0][0] = argc; } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( #pragma omp sections { #pragma omp cancel sections } // CHECK: call void @__kmpc_for_static_init_4( // CHECK: call i32 @__kmpc_cancel( // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: call void @__kmpc_for_static_fini( // CHECK: call void @__kmpc_barrier(%ident_t* #pragma omp sections { #pragma omp cancel sections #pragma omp section { #pragma omp cancel sections } } // CHECK: call void @__kmpc_for_static_init_4( // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: call void @__kmpc_for_static_fini( #pragma omp for for (int i = 0; i < argc; ++i) { #pragma omp cancel for if(cancel: flag) } // CHECK: call void @__kmpc_for_static_init_4( // CHECK: [[FLAG:%.+]] = load float, float* @{{.+}}, // CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00 // CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]] // CHECK: [[THEN]] // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 2) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: [[ELSE]] // CHECK: br label // CHECK: call void @__kmpc_for_static_fini( // CHECK: call void @__kmpc_barrier(%ident_t* #pragma omp task { #pragma omp cancel taskgroup } // CHECK: call i8* @__kmpc_omp_task_alloc( // CHECK: call i32 @__kmpc_omp_task( #pragma omp parallel sections { #pragma omp cancel sections } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( #pragma omp parallel sections { #pragma omp cancel sections #pragma omp section { #pragma omp cancel sections } } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( int r = 0; -#pragma omp parallel for reduction(+:r) +#pragma omp parallel for reduction(+: r) for (int i = 0; i < argc; ++i) { #pragma omp cancel for r += i; } // CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call( return argc; } // CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}, // CHECK: [[FLAG:%.+]] = load float, float* @{{.+}}, // CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00 // CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]] // CHECK: [[THEN]] // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label %[[RETURN:.+]] // CHECK: [[ELSE]] // CHECK: br label // CHECK: [[RETURN]] // CHECK: ret void // CHECK: define internal i32 @{{[^(]+}}(i32 // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 4) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]], // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label %[[RETURN:.+]] // CHECK: [[RETURN]] // CHECK: ret i32 0 // CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}) // CHECK: call void @__kmpc_for_static_init_4( // CHECK: call i32 @__kmpc_cancel( // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: call void @__kmpc_for_static_fini( // CHECK: ret void // CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}) // CHECK: call void @__kmpc_for_static_init_4( // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID:%.+]], i32 3) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 3) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: call void @__kmpc_for_static_fini( // CHECK: ret void // CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}}, // CHECK: call void @__kmpc_for_static_init_4( // CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID:%.+]], i32 2) // CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0 // CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]] // CHECK: [[EXIT]] // CHECK: call i32 @__kmpc_cancel_barrier(%ident_t* // CHECK: br label // CHECK: [[CONTINUE]] // CHECK: br label // CHECK: call void @__kmpc_for_static_fini( // CHECK: call i32 @__kmpc_reduce_nowait( // CHECK: call void @__kmpc_end_reduce_nowait( // CHECK: call void @__kmpc_for_static_fini( // CHECK: ret void #endif diff --git a/test/SemaCXX/cxx11-crashes.cpp b/test/SemaCXX/cxx11-crashes.cpp index 97c959454c35..7c455eecd5fa 100644 --- a/test/SemaCXX/cxx11-crashes.cpp +++ b/test/SemaCXX/cxx11-crashes.cpp @@ -1,93 +1,105 @@ // RUN: %clang_cc1 -std=c++11 -verify %s // rdar://12240916 stack overflow. namespace rdar12240916 { struct S2 { S2(const S2&); S2(); }; struct S { // expected-note {{not complete}} S x; // expected-error {{incomplete type}} S2 y; }; S foo() { S s; return s; } struct S3; // expected-note {{forward declaration}} struct S4 { S3 x; // expected-error {{incomplete type}} S2 y; }; struct S3 { S4 x; S2 y; }; S4 foo2() { S4 s; return s; } } // rdar://12542261 stack overflow. namespace rdar12542261 { template struct check_complete { static_assert(sizeof(_Tp) > 0, "Type must be complete."); }; template class function // expected-note 2 {{candidate}} { public: template function(_Fp, typename check_complete<_Fp>::type* = 0); // expected-note {{candidate}} }; void foobar() { auto LeftCanvas = new Canvas(); // expected-error {{unknown type name}} function m_OnChange = [&, LeftCanvas]() { }; // expected-error {{no viable conversion}} } } namespace b6981007 { struct S {}; // expected-note 3{{candidate}} void f() { S s(1, 2, 3); // expected-error {{no matching}} for (auto x : s) { // We used to attempt to evaluate the initializer of this variable, // and crash because it has an undeduced type. const int &n(x); } } } namespace incorrect_auto_type_deduction_for_typo { struct S { template S(T t) { (void)sizeof(t); (void)new auto(t); } }; void Foo(S); void test(int some_number) { // expected-note {{'some_number' declared here}} auto x = sum_number; // expected-error {{use of undeclared identifier 'sum_number'; did you mean 'some_number'?}} auto lambda = [x] {}; Foo(lambda); } } + +namespace pr29091 { + struct X{ X(const X &x); }; + struct Y: X { using X::X; }; + bool foo() { return __has_nothrow_constructor(Y); } + bool bar() { return __has_nothrow_copy(Y); } + + struct A { template A(); }; + struct B : A { using A::A; }; + bool baz() { return __has_nothrow_constructor(B); } + bool qux() { return __has_nothrow_copy(B); } +}