From c688008cb5c7ea9bdda9523758ea1498dd42bad0 Mon Sep 17 00:00:00 2001 From: Masahiro ARAKAWA Date: Fri, 10 Jul 2026 14:08:58 +0900 Subject: [PATCH] Add C++17/C++20 language feature tests for LLVM test-suite --- C++/CMakeLists.txt | 2 + C++/cxx17/CMakeLists.txt | 45 ++ C++/cxx17/aggregate_init_with_base.cpp | 74 +++ C++/cxx17/attr_namespace_enum.cpp | 40 ++ C++/cxx17/attribute_namespace_using.cpp | 46 ++ C++/cxx17/auto_non_type_template_param.cpp | 49 ++ C++/cxx17/bool_increment_removed.cpp | 25 + .../class_template_argument_deduction.cpp | 62 +++ C++/cxx17/constexpr_if.cpp | 43 ++ C++/cxx17/constexpr_lambda.cpp | 33 ++ C++/cxx17/direct_list_init_auto.cpp | 41 ++ C++/cxx17/enum_direct_list_init.cpp | 56 +++ C++/cxx17/exception-spec-type.cpp | 54 +++ C++/cxx17/fallthrough_attr.cpp | 63 +++ C++/cxx17/fold_expression.cpp | 72 +++ C++/cxx17/guaranteed_copy_elision.cpp | 45 ++ C++/cxx17/has_include_preprocessor.cpp | 46 ++ C++/cxx17/hex_float_literal.cpp | 45 ++ C++/cxx17/if_switch_init_statement.cpp | 55 +++ C++/cxx17/ignore_unknown_attributes.cpp | 41 ++ C++/cxx17/inline_variables.cpp | 44 ++ C++/cxx17/inline_variables.hpp | 12 + C++/cxx17/lambda_capture_this_value.cpp | 59 +++ C++/cxx17/maybe_unused_attr.cpp | 45 ++ C++/cxx17/nested_namespace_definition.cpp | 81 ++++ C++/cxx17/no_trigraphs.cpp | 40 ++ C++/cxx17/nodiscard_attr.cpp | 51 ++ C++/cxx17/non_type_template_consteval.cpp | 65 +++ C++/cxx17/overaligned_allocation.cpp | 46 ++ .../pack_expansion_using_declaration.cpp | 46 ++ C++/cxx17/range_for_sentinel.cpp | 81 ++++ C++/cxx17/remove_register_storage_class.cpp | 15 + C++/cxx17/removed_dynamic_exception_spec.cpp | 49 ++ C++/cxx17/static_assert_no_message.cpp | 17 + .../stricter_expression_evaluation_order.cpp | 138 ++++++ C++/cxx17/structured_bindings.cpp | 68 +++ C++/cxx17/template_template_compat.cpp | 32 ++ C++/cxx17/template_template_typename.cpp | 32 ++ C++/cxx17/u8_char_literals.cpp | 37 ++ C++/cxx20/CMakeLists.txt | 54 +++ .../access_checking_on_specializations.cpp | 140 ++++++ C++/cxx20/adl_hidden_function_templates.cpp | 55 +++ C++/cxx20/aggregate_ctad.cpp | 88 ++++ C++/cxx20/aggregate_paren_init.cpp | 251 ++++++++++ C++/cxx20/alias_template_ctad.cpp | 125 +++++ C++/cxx20/array_unknown_bound_conversion.cpp | 91 ++++ .../bitfield_default_member_initializer.cpp | 216 +++++++++ C++/cxx20/char8_t_literal_type.cpp | 73 +++ C++/cxx20/class_types_as_nttp.cpp | 68 +++ C++/cxx20/concepts.cpp | 70 +++ C++/cxx20/conditional_explicit.cpp | 79 +++ .../const_ref_qualified_member_pointer.cpp | 43 ++ .../consteval_mandatory_compile_time.cpp | 54 +++ C++/cxx20/constexpr_relaxations.cpp | 228 +++++++++ C++/cxx20/constinit.cpp | 83 ++++ C++/cxx20/coroutines.cpp | 132 ++++++ .../defaulted_copy_ctor_const_mismatch.cpp | 42 ++ C++/cxx20/deprecated_subscript_comma.cpp | 52 ++ C++/cxx20/deprecated_volatile_operations.cpp | 64 +++ C++/cxx20/designated_initializers.cpp | 90 ++++ C++/cxx20/destroying_delete_basic.cpp | 60 +++ C++/cxx20/feature_test_macros.cpp | 269 +++++++++++ C++/cxx20/generalized_nttp_scalar_types.cpp | 94 ++++ C++/cxx20/is_constant_evaluated_paths.cpp | 68 +++ .../lambda-init-capture-pack-expansion.cpp | 76 +++ C++/cxx20/lambda_capture_equals_this.cpp | 45 ++ C++/cxx20/lambda_template_parameter_list.cpp | 59 +++ C++/cxx20/lambdas_in_unevaluated_contexts.cpp | 50 ++ C++/cxx20/likely_unlikely_attributes.cpp | 230 +++++++++ C++/cxx20/modules.cpp | 43 ++ C++/cxx20/modules.cppm | 44 ++ C++/cxx20/more_implicit_moves.cpp | 221 +++++++++ C++/cxx20/nested-inline-namespaces.cpp | 61 +++ C++/cxx20/no_unique_address_member_layout.cpp | 53 +++ C++/cxx20/nodiscard_with_reason.cpp | 61 +++ .../nodiscard_with_reason_diagnostics.cpp | 78 +++ .../prohibit_aggregate_user_declared_ctor.cpp | 174 +++++++ C++/cxx20/pseudo_destructor_lifetime.cpp | 89 ++++ C++/cxx20/range_for_with_initializer.cpp | 137 ++++++ C++/cxx20/signed_integers_twos_complement.cpp | 81 ++++ ...ss_lambda_default_construct_and_assign.cpp | 52 ++ C++/cxx20/stronger_unicode_requirements.cpp | 135 ++++++ C++/cxx20/structured_binding_extensions.cpp | 448 ++++++++++++++++++ C++/cxx20/three_way_comparison.cpp | 130 +++++ .../typename_optional_in_more_contexts.cpp | 128 +++++ C++/cxx20/using_enum.cpp | 131 +++++ C++/cxx20/va_opt_comma_elision.cpp | 38 ++ 87 files changed, 7048 insertions(+) create mode 100644 C++/cxx17/CMakeLists.txt create mode 100644 C++/cxx17/aggregate_init_with_base.cpp create mode 100644 C++/cxx17/attr_namespace_enum.cpp create mode 100644 C++/cxx17/attribute_namespace_using.cpp create mode 100644 C++/cxx17/auto_non_type_template_param.cpp create mode 100644 C++/cxx17/bool_increment_removed.cpp create mode 100644 C++/cxx17/class_template_argument_deduction.cpp create mode 100644 C++/cxx17/constexpr_if.cpp create mode 100644 C++/cxx17/constexpr_lambda.cpp create mode 100644 C++/cxx17/direct_list_init_auto.cpp create mode 100644 C++/cxx17/enum_direct_list_init.cpp create mode 100644 C++/cxx17/exception-spec-type.cpp create mode 100644 C++/cxx17/fallthrough_attr.cpp create mode 100644 C++/cxx17/fold_expression.cpp create mode 100644 C++/cxx17/guaranteed_copy_elision.cpp create mode 100644 C++/cxx17/has_include_preprocessor.cpp create mode 100644 C++/cxx17/hex_float_literal.cpp create mode 100644 C++/cxx17/if_switch_init_statement.cpp create mode 100644 C++/cxx17/ignore_unknown_attributes.cpp create mode 100644 C++/cxx17/inline_variables.cpp create mode 100644 C++/cxx17/inline_variables.hpp create mode 100644 C++/cxx17/lambda_capture_this_value.cpp create mode 100644 C++/cxx17/maybe_unused_attr.cpp create mode 100644 C++/cxx17/nested_namespace_definition.cpp create mode 100644 C++/cxx17/no_trigraphs.cpp create mode 100644 C++/cxx17/nodiscard_attr.cpp create mode 100644 C++/cxx17/non_type_template_consteval.cpp create mode 100644 C++/cxx17/overaligned_allocation.cpp create mode 100644 C++/cxx17/pack_expansion_using_declaration.cpp create mode 100644 C++/cxx17/range_for_sentinel.cpp create mode 100644 C++/cxx17/remove_register_storage_class.cpp create mode 100644 C++/cxx17/removed_dynamic_exception_spec.cpp create mode 100644 C++/cxx17/static_assert_no_message.cpp create mode 100644 C++/cxx17/stricter_expression_evaluation_order.cpp create mode 100644 C++/cxx17/structured_bindings.cpp create mode 100644 C++/cxx17/template_template_compat.cpp create mode 100644 C++/cxx17/template_template_typename.cpp create mode 100644 C++/cxx17/u8_char_literals.cpp create mode 100644 C++/cxx20/CMakeLists.txt create mode 100644 C++/cxx20/access_checking_on_specializations.cpp create mode 100644 C++/cxx20/adl_hidden_function_templates.cpp create mode 100644 C++/cxx20/aggregate_ctad.cpp create mode 100644 C++/cxx20/aggregate_paren_init.cpp create mode 100644 C++/cxx20/alias_template_ctad.cpp create mode 100644 C++/cxx20/array_unknown_bound_conversion.cpp create mode 100644 C++/cxx20/bitfield_default_member_initializer.cpp create mode 100644 C++/cxx20/char8_t_literal_type.cpp create mode 100644 C++/cxx20/class_types_as_nttp.cpp create mode 100644 C++/cxx20/concepts.cpp create mode 100644 C++/cxx20/conditional_explicit.cpp create mode 100644 C++/cxx20/const_ref_qualified_member_pointer.cpp create mode 100644 C++/cxx20/consteval_mandatory_compile_time.cpp create mode 100644 C++/cxx20/constexpr_relaxations.cpp create mode 100644 C++/cxx20/constinit.cpp create mode 100644 C++/cxx20/coroutines.cpp create mode 100644 C++/cxx20/defaulted_copy_ctor_const_mismatch.cpp create mode 100644 C++/cxx20/deprecated_subscript_comma.cpp create mode 100644 C++/cxx20/deprecated_volatile_operations.cpp create mode 100644 C++/cxx20/designated_initializers.cpp create mode 100644 C++/cxx20/destroying_delete_basic.cpp create mode 100644 C++/cxx20/feature_test_macros.cpp create mode 100644 C++/cxx20/generalized_nttp_scalar_types.cpp create mode 100644 C++/cxx20/is_constant_evaluated_paths.cpp create mode 100644 C++/cxx20/lambda-init-capture-pack-expansion.cpp create mode 100644 C++/cxx20/lambda_capture_equals_this.cpp create mode 100644 C++/cxx20/lambda_template_parameter_list.cpp create mode 100644 C++/cxx20/lambdas_in_unevaluated_contexts.cpp create mode 100644 C++/cxx20/likely_unlikely_attributes.cpp create mode 100644 C++/cxx20/modules.cpp create mode 100644 C++/cxx20/modules.cppm create mode 100644 C++/cxx20/more_implicit_moves.cpp create mode 100644 C++/cxx20/nested-inline-namespaces.cpp create mode 100644 C++/cxx20/no_unique_address_member_layout.cpp create mode 100644 C++/cxx20/nodiscard_with_reason.cpp create mode 100644 C++/cxx20/nodiscard_with_reason_diagnostics.cpp create mode 100644 C++/cxx20/prohibit_aggregate_user_declared_ctor.cpp create mode 100644 C++/cxx20/pseudo_destructor_lifetime.cpp create mode 100644 C++/cxx20/range_for_with_initializer.cpp create mode 100644 C++/cxx20/signed_integers_twos_complement.cpp create mode 100644 C++/cxx20/stateless_lambda_default_construct_and_assign.cpp create mode 100644 C++/cxx20/stronger_unicode_requirements.cpp create mode 100644 C++/cxx20/structured_binding_extensions.cpp create mode 100644 C++/cxx20/three_way_comparison.cpp create mode 100644 C++/cxx20/typename_optional_in_more_contexts.cpp create mode 100644 C++/cxx20/using_enum.cpp create mode 100644 C++/cxx20/va_opt_comma_elision.cpp diff --git a/C++/CMakeLists.txt b/C++/CMakeLists.txt index 41a8e677af..d76b110d25 100644 --- a/C++/CMakeLists.txt +++ b/C++/CMakeLists.txt @@ -53,3 +53,5 @@ add_subdirectory(0050) add_subdirectory(0051) add_subdirectory(0052) add_subdirectory(0053) +add_subdirectory(cxx17) +add_subdirectory(cxx20) diff --git a/C++/cxx17/CMakeLists.txt b/C++/cxx17/CMakeLists.txt new file mode 100644 index 0000000000..faa613a67f --- /dev/null +++ b/C++/cxx17/CMakeLists.txt @@ -0,0 +1,45 @@ +set(cxx17_sources + aggregate_init_with_base.cpp + attr_namespace_enum.cpp + attribute_namespace_using.cpp + auto_non_type_template_param.cpp + # bool_increment_removed.cpp + class_template_argument_deduction.cpp + constexpr_if.cpp + constexpr_lambda.cpp + direct_list_init_auto.cpp + enum_direct_list_init.cpp + exception-spec-type.cpp + fallthrough_attr.cpp + fold_expression.cpp + guaranteed_copy_elision.cpp + has_include_preprocessor.cpp + hex_float_literal.cpp + if_switch_init_statement.cpp + ignore_unknown_attributes.cpp + inline_variables.cpp + lambda_capture_this_value.cpp + maybe_unused_attr.cpp + nested_namespace_definition.cpp + no_trigraphs.cpp + nodiscard_attr.cpp + non_type_template_consteval.cpp + overaligned_allocation.cpp + pack_expansion_using_declaration.cpp + range_for_sentinel.cpp + # remove_register_storage_class.cpp + removed_dynamic_exception_spec.cpp + static_assert_no_message.cpp + stricter_expression_evaluation_order.cpp + structured_bindings.cpp + template_template_compat.cpp + template_template_typename.cpp + u8_char_literals.cpp +) + +foreach(src ${cxx17_sources}) + set_property(SOURCE ${src} + APPEND PROPERTY COMPILE_OPTIONS "-std=c++17") +endforeach() + +llvm_singlesource_fujitsu(PREFIX "Fujitsu-C++-") diff --git a/C++/cxx17/aggregate_init_with_base.cpp b/C++/cxx17/aggregate_init_with_base.cpp new file mode 100644 index 0000000000..1f1048b385 --- /dev/null +++ b/C++/cxx17/aggregate_init_with_base.cpp @@ -0,0 +1,74 @@ +/* +FEATURE: Aggregate initialization of classes with base classes +SPEC: C++17 standard — aggregate initialization rules for classes with base classes (see C++17 draft / standard aggregate definition) +PURPOSE: Verify that a class deriving from a public non-virtual base with no user-provided constructors + is treated as an aggregate under C++17 and can be initialized via aggregate initialization, + including both braced base-subobject form and flat initializer-list form. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror -Wno-missing-braces aggregate_init_with_base.cpp +*/ + +#include // for std::fabs +#include // for std::int32_t +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// Simple base and derived types that qualify as aggregates under C++17: +// - no user-provided constructors +// - no private or protected non-static data members +// - no virtual base classes +// - public (default for struct) inheritance +struct Base { + int a; + double b; +}; + +struct Derived : Base { + int c; +}; + +// Another example with two base classes and an own member to show order-of-initialization behavior. +struct Left { + int l; +}; + +struct Right { + int r; +}; + +struct MultiDerived : Left, Right { + int m; +}; + +// Helper for floating-point comparison +bool almost_equal(double x, double y, double eps = 1e-12) { + return std::fabs(x - y) <= eps; +} + +int main() { + // 1) Initialize Derived by explicitly initializing the base subobject, then derived members. + // This form uses nested braces for the base subobject. + Derived d1{ { 1, 2.5 }, 3 }; + + if (d1.a != 1) return EXIT_FAILURE; + if (!almost_equal(d1.b, 2.5)) return EXIT_FAILURE; + if (d1.c != 3) return EXIT_FAILURE; + + // 2) Initialize Derived using a flat initializer-list (C++17 allows the base's members + // to be initialized in declaration order without explicit nested braces). + Derived d2{ 10, 20.5, 30 }; + + if (d2.a != 10) return EXIT_FAILURE; + if (!almost_equal(d2.b, 20.5)) return EXIT_FAILURE; + if (d2.c != 30) return EXIT_FAILURE; + + // 3) Multi-base example: initializer-list initializes base subobjects in declaration + // order (Left, then Right), then members of the most-derived class. + MultiDerived m{ 7, 8, 9 }; // maps to Left::l = 7, Right::r = 8, MultiDerived::m = 9 + + if (m.l != 7) return EXIT_FAILURE; + if (m.r != 8) return EXIT_FAILURE; + if (m.m != 9) return EXIT_FAILURE; + + // If all checks passed, return success (0). + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/attr_namespace_enum.cpp b/C++/cxx17/attr_namespace_enum.cpp new file mode 100644 index 0000000000..8ff4af4a11 --- /dev/null +++ b/C++/cxx17/attr_namespace_enum.cpp @@ -0,0 +1,40 @@ +/* +FEATURE: Attributes for namespaces and enumerators +SPEC: N4266 §7.6.1 [dcl.attr.grammar] +PURPOSE: Verify that C++17 allows applying attributes to namespaces and individual enumerators, + and that the compiler emits appropriate warnings for deprecated elements. +RUN: clang++ -std=c++17 -Wall -Wextra attr_namespace_enum.cpp +*/ + +#include + +// Apply an attribute to a namespace +namespace +[[deprecated("use new_namespace instead")]] +old_namespace { + inline int get_value() { return 42; } +} + +// Apply an attribute to an enumerator +enum class Color { + Red, + Green, + Blue [[deprecated("Blue is deprecated")]] +}; + +int main() { + int result = 0; + + // Accessing deprecated namespace should trigger a warning + int val = old_namespace::get_value(); + if (val != 42) + result = 1; + + // Using deprecated enumerator should trigger a warning + Color c = Color::Blue; + if (c != Color::Blue) + result = 2; + + // Return 0 if all runtime checks are OK + return result; +} diff --git a/C++/cxx17/attribute_namespace_using.cpp b/C++/cxx17/attribute_namespace_using.cpp new file mode 100644 index 0000000000..96f370c138 --- /dev/null +++ b/C++/cxx17/attribute_namespace_using.cpp @@ -0,0 +1,46 @@ +/* +FEATURE: Using attribute namespaces without repetition +SPEC: N4266 §7 (C++17 attribute namespace grouping) +PURPOSE: Verify that the compiler correctly accepts the C++17 syntax + `[[using ns: attr1, attr2]]` where an attribute namespace is + specified once and reused for multiple attributes without repetition. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror attribute_namespace_using.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// Define a custom attribute namespace for testing +namespace vendor { + // GNU-style attribute handling for testing; actual effect is irrelevant. + // These do nothing but allow syntax checking. +#if defined(__clang__) + // Using clang's vendor-specific attribute handling mechanism + [[clang::syntax_only]] // No-op to ensure the namespace is recognized + inline void dummy() {} +#endif +} + +// Apply attributes using the C++17 grouping syntax +[[using vendor: unused]] +void func1() { + // This function intentionally left blank +} + +// Apply multiple attributes in the same namespace +[[using vendor: unused, unused]] +void func2() { + // This function intentionally left blank +} + +int main() { + // The purpose of the test is strictly syntactic. + // If the compiler accepts the grouped attribute syntax, this test passes. + // If compilation fails, the test framework will treat it as a failure. + + func1(); + func2(); + + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/auto_non_type_template_param.cpp b/C++/cxx17/auto_non_type_template_param.cpp new file mode 100644 index 0000000000..7c1be3ad43 --- /dev/null +++ b/C++/cxx17/auto_non_type_template_param.cpp @@ -0,0 +1,49 @@ +/* +FEATURE: Non-type template parameters with auto type +SPEC: ISO/IEC 14882:2017 (C++17) [temp.param] (see also P0127R2) +PURPOSE: Verify that non-type template parameters can use 'auto' so that + the parameter type is deduced from the provided constant expression. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror auto_non_type_template_param.cpp +*/ + +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// A template with a non-type template parameter using auto. +template +struct Holder { + static constexpr auto value = Value; +}; + +int main() +{ + // Integer constant: type should be deduced as int. + Holder<42> h_int; + static_assert(std::is_same::value, + "Type of Value should be int"); + + // Size-related constant: type should be deduced as std::size_t. + Holder h_size; + static_assert(std::is_same::value, + "Type of Value should be std::size_t"); + + // Pointer constant: type should be deduced as a pointer type. + static int global = 0; + Holder<&global> h_ptr; + static_assert(std::is_same::value, + "Type of Value should be int* const"); + + // Runtime check to ensure the values are usable. + if (h_int.value != 42) { + return EXIT_FAILURE; + } + if (h_size.value != sizeof(int)) { + return EXIT_FAILURE; + } + if (h_ptr.value != &global) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/C++/cxx17/bool_increment_removed.cpp b/C++/cxx17/bool_increment_removed.cpp new file mode 100644 index 0000000000..d9a06050d2 --- /dev/null +++ b/C++/cxx17/bool_increment_removed.cpp @@ -0,0 +1,25 @@ +/* +FEATURE: Remove deprecated bool increment +SPEC: N4296 §4.5; P0001R1 +PURPOSE: Confirm that increment/decrement operators applied to bool are removed in C++17 and must produce a compile-time error. +RUN: clang++ -std=c++17 -Wall -Wextra bool_increment_removed.cpp +*/ + +// This program is a negative test. It is expected to fail to compile on a +// conforming C++17 compiler because incrementing a bool is removed in C++17. + +bool test_bool_increment() { + bool b = false; + // The following line must produce a compile error in C++17. + ++b; // expected-error: increment of bool is removed in C++17 + return b; +} + +int main() { + // This function would never be reached in a correct C++17 implementation + // because the translation must fail before linking. + int ret = 0; // A value other than 0 indicates that the test failed. + if (test_bool_increment() == false) ret= 1; + return ret; +} + diff --git a/C++/cxx17/class_template_argument_deduction.cpp b/C++/cxx17/class_template_argument_deduction.cpp new file mode 100644 index 0000000000..ddeeb0076f --- /dev/null +++ b/C++/cxx17/class_template_argument_deduction.cpp @@ -0,0 +1,62 @@ +/* +FEATURE: Template argument deduction for class templates +SPEC: ISO/IEC 14882:2017 (C++17), §17.8.2 [temp.deduct.guide] +PURPOSE: Verify that class template arguments can be deduced from constructor arguments (CTAD), + including standard library templates and a user-defined template with a deduction guide. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror class_template_argument_deduction.cpp +*/ + +#include +#include +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +/* + A simple user-defined class template. +*/ +template +struct Box { + T first; + U second; + + Box(T a, U b) : first(a), second(b) {} +}; + +/* + A deduction guide that forces the second template argument to be std::size_t + when the second constructor argument is an integer literal. +*/ +template +Box(T, int) -> Box; + +int main() +{ + // --- Standard library examples --- + + // CTAD for std::pair + std::pair p(1, 2.5); // deduced as std::pair + static_assert(std::is_same_v>, + "CTAD failed for std::pair"); + + // CTAD for std::vector + std::vector v{1, 2, 3}; // deduced as std::vector + static_assert(std::is_same_v>, + "CTAD failed for std::vector"); + + // --- User-defined class template example --- + + // Basic CTAD without an explicit deduction guide + Box b1(10, 3.14); // deduced as Box + static_assert(std::is_same_v>, + "CTAD failed for user-defined template (default deduction)"); + + // CTAD with an explicit deduction guide + Box b2(42, 7); // deduced as Box due to the deduction guide + static_assert(std::is_same_v>, + "CTAD failed for user-defined template with deduction guide"); + + // If all static assertions pass, the test succeeds. + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/constexpr_if.cpp b/C++/cxx17/constexpr_if.cpp new file mode 100644 index 0000000000..2dd4956a52 --- /dev/null +++ b/C++/cxx17/constexpr_if.cpp @@ -0,0 +1,43 @@ +/* +FEATURE: C++17 constexpr if-statements +SPEC: ISO/IEC 14882:2017 (C++17) §8.5.2 [stmt.if] +PURPOSE: Verify that if constexpr evaluates conditions at compile time and discards + non-selected branches so that ill-formed code in discarded branches does + not cause compilation errors. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror constexpr_if.cpp +*/ + +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// This template uses if constexpr to select code paths depending on the type. +// The discarded branch intentionally contains code that would be ill-formed +// if it were instantiated. +template +constexpr std::size_t type_dependent_size() +{ + if constexpr (std::is_integral::value) { + // Valid branch for integral types + return sizeof(T); + } else { + // This code would be ill-formed if instantiated, because T does not + // have a member named non_existent_member. + // It must not be compiled when the condition is false. + return T::non_existent_member; + } +} + +int main() +{ + // For int, the integral branch must be selected at compile time. + constexpr std::size_t s = type_dependent_size(); + + // Basic runtime check to confirm expected behavior. + if (s != sizeof(int)) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/constexpr_lambda.cpp b/C++/cxx17/constexpr_lambda.cpp new file mode 100644 index 0000000000..2927ce1c99 --- /dev/null +++ b/C++/cxx17/constexpr_lambda.cpp @@ -0,0 +1,33 @@ +/* +FEATURE: constexpr lambda expressions +SPEC: N4659 §8.1.5 / P0170R1 +PURPOSE: Verify that lambda expressions can be declared constexpr and evaluated at compile time. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror constexpr_lambda.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +int main() { + // A simple constexpr lambda returning the square of a number. + constexpr auto square = [](int x) constexpr { + return x * x; + }; + + // Use the constexpr lambda in a constexpr context. + constexpr int result = square(10); + + // Validate compile-time result. + static_assert(result == 100, "constexpr lambda evaluation failed"); + + // Also confirm that run-time invocation works as expected. + int runtime_value = square(100); + if (runtime_value != 10000) { + std::printf("Runtime check failed: %d\n", runtime_value); + return EXIT_FAILURE; + } + + // Success + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/direct_list_init_auto.cpp b/C++/cxx17/direct_list_init_auto.cpp new file mode 100644 index 0000000000..503c51ab94 --- /dev/null +++ b/C++/cxx17/direct_list_init_auto.cpp @@ -0,0 +1,41 @@ +/* FEATURE: New auto rules for direct-list-initialization + +SPEC: C++17 Standard (N4659 [dcl.init.list]) +PURPOSE: Verify that in C++17, 'auto' with direct-list-initialization + follows the new deduction rules: + - 'auto x{expr};' deduces std::initializer_list if possible. + - 'auto x = {expr};' always deduces std::initializer_list. + - 'auto x{expr1, expr2, ...};' is ill-formed (no deduction). + - 'auto x{single_value};' deduces the type of single_value directly. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror direct_list_init_auto.cpp +*/ + +#include +#include + +int main() { + // Case 1: Simple direct-list-initialization with a single value + // In C++17, 'auto x{1};' deduces 'int', not 'std::initializer_list' + auto x{1}; + static_assert(std::is_same_v, "auto x{1} should deduce int"); + + // Case 2: Direct-list-initialization with multiple elements + // This should be ill-formed in C++17; it fails to compile. + // Uncommenting the next line should cause a compilation error. + // auto y{1, 2}; // ERROR: cannot deduce from braced-init-list with multiple elements + + // Case 3: Copy-list-initialization with '=' + // 'auto z = {1, 2};' deduces 'std::initializer_list' + auto z = {1, 2}; + static_assert(std::is_same_v>, + "auto z = {1, 2} should deduce std::initializer_list"); + + // Case 4: Explicit initializer_list construction + // Confirm consistency with the deduction rules + std::initializer_list expected = {1, 2}; + static_assert(std::is_same_v, + "Both should be std::initializer_list"); + + return 0; // success +} + diff --git a/C++/cxx17/enum_direct_list_init.cpp b/C++/cxx17/enum_direct_list_init.cpp new file mode 100644 index 0000000000..d38a9ccf0d --- /dev/null +++ b/C++/cxx17/enum_direct_list_init.cpp @@ -0,0 +1,56 @@ +/* +FEATURE: C++17 Direct-list-initialization of enums +SPEC: ISO/IEC 14882:2017 (C++17) [dcl.init.list] §11.6.4 +PURPOSE: Verify that direct-list-initialization of enum types is allowed in C++17 + and that only valid enumerator values are accepted. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror enum_direct_list_init.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// Scoped enum for type safety +enum class Color : int { + Red = 0, + Green = 1, + Blue = 2 +}; + +// Unscoped enum +enum Status { + Idle = 0, + Busy = 1, + Error = 2 +}; + +int main() +{ + // Valid direct-list-initialization (must compile in C++17) + Color c1{0}; // Maps to Color::Red + Color c2{1}; // Maps to Color::Green + // Status s1{2}; // Maps to Status::Error + + // Runtime verification of the values + if (c1 != Color::Red) { + return EXIT_FAILURE; // 1; + } + + if (c2 != Color::Green) { + return EXIT_FAILURE; // 2; + } + + // if (s1 != Status::Error) { + // return EXIT_FAILURE; // 3; + // } + + // Type safety check for scoped enum + static_assert(std::is_enum::value, "Color must be an enum type"); + + // The following code must FAIL to compile in C++17 because the value + // is not representable by the enumeration. + // Uncommenting it should cause a compilation error. + // + // Color invalid{3}; + + return EXIT_SUCCESS; // Success +} diff --git a/C++/cxx17/exception-spec-type.cpp b/C++/cxx17/exception-spec-type.cpp new file mode 100644 index 0000000000..c98ff9a696 --- /dev/null +++ b/C++/cxx17/exception-spec-type.cpp @@ -0,0 +1,54 @@ +/* +FEATURE: Make exception specifications part of the type system +SPEC: N4659 §14.5; P0012R1 +PURPOSE: Ensure that noexcept specifications are part of function types and cause type distinction. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror exception-spec-type.cpp +*/ + +#include + +// Function declarations with and without noexcept +void f_noexcept() noexcept; +void f_plain(); + +using fn_noexcept_t = void() noexcept; +using fn_plain_t = void(); + +int main() { + // Check that the types are different as required in C++17 + bool types_are_different = + !std::is_same::value; + + if (!types_are_different) { + return 1; // failed + } + + // Check that function pointers also reflect the distinction + using fp_noexcept_t = void(*)() noexcept; + using fp_plain_t = void(*)(); + + bool pointer_types_are_different = + !std::is_same::value; + + if (!pointer_types_are_different) { + return 2; // failed + } + + // Check that taking the address of the functions produces distinct types + bool addr_f_noexcept_ok = + std::is_same::value; + + if (!addr_f_noexcept_ok) { + return 3; // failed + } + + bool addr_f_plain_ok = + std::is_same::value; + + if (!addr_f_plain_ok) { + return 4; // failed + } + + return 0; // success +} + diff --git a/C++/cxx17/fallthrough_attr.cpp b/C++/cxx17/fallthrough_attr.cpp new file mode 100644 index 0000000000..e5b756a52c --- /dev/null +++ b/C++/cxx17/fallthrough_attr.cpp @@ -0,0 +1,63 @@ +/* +FEATURE: [[fallthrough]] attribute +SPEC: N4659 §9.12 (Attributes) / §6.7 (switch statement) +PURPOSE: Verify that the C++17 [[fallthrough]] attribute correctly marks intentional fallthrough and suppresses warnings under -Wall/-Wextra/-Werror. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror fallthrough_attr.cpp +*/ + +#include + +#define _FAIL 1 + +int check_fallthrough_behavior(int x) { + int value = 0; + + switch (x) { + case 1: + value = 10; + [[fallthrough]]; // Intentional fallthrough to case 2 + case 2: + value += 5; + break; + + case 3: + value = 100; + // No fallthrough attribute here; break is intentional + break; + + default: + value = -1; + break; + } + + return value; +} + +int main() { + // Case 1 should fall through to case 2: 10 + 5 = 15 + if (check_fallthrough_behavior(1) != 15) { + std::cerr << "FAIL: fallthrough from case 1 to case 2 did not work as expected.\n"; + return _FAIL; + } + + // Case 2 should execute only case 2 logic: value = 5 + if (check_fallthrough_behavior(2) != 5) { + std::cerr << "FAIL: case 2 did not return expected result.\n"; + return _FAIL; + } + + // Case 3 should not fall through + if (check_fallthrough_behavior(3) != 100) { + std::cerr << "FAIL: case 3 did not return expected result.\n"; + return _FAIL; + } + + // Default case check + if (check_fallthrough_behavior(99) != -1) { + std::cerr << "FAIL: default case did not return expected result.\n"; + return _FAIL; + } + + return 0; // All tests passed +} + diff --git a/C++/cxx17/fold_expression.cpp b/C++/cxx17/fold_expression.cpp new file mode 100644 index 0000000000..0e8386e681 --- /dev/null +++ b/C++/cxx17/fold_expression.cpp @@ -0,0 +1,72 @@ +/* FEATURE: Fold expressions + +SPEC: C++17 Standard (N4659 §8.5.9 [expr.fold]) +PURPOSE: Verify that C++17 fold expressions work correctly for unary and binary folds. + This test checks different forms of fold expressions: + - Unary right fold: (... op pack) + - Unary left fold: (pack op ...) + - Binary fold with an initial value: (init op ... op pack), (pack op ... op init) + Each case validates that the expression expands and evaluates as expected. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror fold_expression.cpp +*/ + +#include +#include + +// A template function using a fold expression to compute the sum of arguments +template +constexpr auto sum_all(Args... args) { + return (... + args); // Unary right fold +} + +// A template function using a fold expression to compute the product of arguments +template +constexpr auto product_all(Args... args) { + return (args * ...); // Unary left fold +} + +// A template function using a fold expression with an initial value (binary fold) +template +constexpr auto add_with_init(int init, Args... args) { + return (init + ... + args); // Binary left fold +} + +// A template function using logical AND fold expression +template +constexpr bool all_true(Args... args) { + return (true && ... && args); // Unary right fold +} + +// A template function using logical OR fold expression +template +constexpr bool any_true(Args... args) { + return (false || ... || args); // Unary right fold +} + +int main() { + // Test sum_all (unary right fold) + static_assert(sum_all(1, 2, 3, 4) == 10, "sum_all failed"); + if (sum_all(1, 2, 3, 4) != 10) return 1; + + // Test product_all (unary left fold) + static_assert(product_all(1, 2, 3, 4) == 24, "product_all failed"); + if (product_all(1, 2, 3, 4) != 24) return 2; + + // Test add_with_init (binary left fold) + static_assert(add_with_init(10, 1, 2, 3) == 16, "add_with_init failed"); + if (add_with_init(10, 1, 2, 3) != 16) return 3; + + // Test all_true (logical AND fold) + static_assert(all_true(true, true, true), "all_true failed"); + static_assert(!all_true(true, false, true), "all_true failed with false"); + if (!all_true(true, true, true)) return 4; + if (all_true(true, false, true)) return 5; + + // Test any_true (logical OR fold) + static_assert(any_true(false, false, true), "any_true failed"); + static_assert(!any_true(false, false, false), "any_true failed with all false"); + if (!any_true(false, false, true)) return 6; + if (any_true(false, false, false)) return 7; + + return 0; // success +} diff --git a/C++/cxx17/guaranteed_copy_elision.cpp b/C++/cxx17/guaranteed_copy_elision.cpp new file mode 100644 index 0000000000..e21879fe9c --- /dev/null +++ b/C++/cxx17/guaranteed_copy_elision.cpp @@ -0,0 +1,45 @@ +/* + * This type explicitly deletes copy and move constructors. + * Under C++17 guaranteed copy elision rules, the program must + * still compile and run correctly when objects are initialized + * directly from prvalues. + */ +#include // for EXIT_SUCCESS / EXIT_FAILURE + +struct NoCopyNoMove { + int value; + + explicit NoCopyNoMove(int v) : value(v) {} + + NoCopyNoMove(const NoCopyNoMove&) = delete; + NoCopyNoMove(NoCopyNoMove&&) = delete; +}; + +/* + * Returning a prvalue of type NoCopyNoMove. + * In C++17, this must construct the result object directly + * without invoking copy or move constructors. + */ +NoCopyNoMove make_object() { + return NoCopyNoMove(42); +} + +int main() { + /* + * Direct initialization from a prvalue. + * Guaranteed copy elision ensures that no copy or move + * constructor is required here. + */ + NoCopyNoMove obj = make_object(); + + /* + * Runtime check to ensure the object was constructed + * with the expected value. + */ + if (obj.value != 42) { + return EXIT_FAILURE; // Test failed + } + + return EXIT_SUCCESS; // Test passed +} + diff --git a/C++/cxx17/has_include_preprocessor.cpp b/C++/cxx17/has_include_preprocessor.cpp new file mode 100644 index 0000000000..49e3850859 --- /dev/null +++ b/C++/cxx17/has_include_preprocessor.cpp @@ -0,0 +1,46 @@ +/* +FEATURE: __has_include in preprocessor conditionals +SPEC: WG21 N4659 (C++17) - Preprocessing; use of the __has_include operator in #if/#elif conditionals +PURPOSE: Verify that the preprocessor accepts and evaluates __has_include in #if/#elif conditionals and that conditional inclusion/branching behaves as expected. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror has_include_preprocessor.cpp +*/ + +#include + +#define _FAIL 1 + +// Check for a header that should exist in a C++17 standard library. +#if __has_include() +# include +# define HAS_OPTIONAL 1 +#else +# define HAS_OPTIONAL 0 +#endif + +// Check for a header that should *not* exist. Use an unlikely name to avoid false positives. +#if __has_include() +# define HAS_FOO 1 +#else +# define HAS_FOO 0 +#endif + +int main() +{ + // Expected: HAS_OPTIONAL == 1 (because is provided in C++17) + // HAS_FOO == 0 ( header must not be found) + + if (HAS_OPTIONAL != 1) { + std::cerr << "FAIL: expected to be found (HAS_OPTIONAL == 1), but it was not.\n"; + return _FAIL; + } + + if (HAS_FOO != 0) { + std::cerr << "FAIL: foo header was unexpectedly found (HAS_FOO == 1).\n"; + return _FAIL; + } + + // If we reach here, the preprocessor conditional evaluation of __has_include behaved as expected. + //std::cout << "PASS: __has_include evaluated in preprocessor conditionals as expected.\n"; + return 0; +} + diff --git a/C++/cxx17/hex_float_literal.cpp b/C++/cxx17/hex_float_literal.cpp new file mode 100644 index 0000000000..cb2b85b20c --- /dev/null +++ b/C++/cxx17/hex_float_literal.cpp @@ -0,0 +1,45 @@ +/* +FEATURE: Hexadecimal floating-point literals +SPEC: ISO/IEC 14882:2017 (C++17) §5.13.4 Floating literals +PURPOSE: Verify that hexadecimal floating-point literals are correctly parsed and evaluated by the compiler. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror hex_float_literal.cpp +*/ + +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +bool nearly_equal(double a, double b, double epsilon = 1e-12) +{ + return std::fabs(a - b) < epsilon; +} + +int main() +{ + // Basic hexadecimal floating-point literals + double a = 0x1.0p+0; // 1.0 + double b = 0x1.8p+1; // 1.5 * 2 = 3.0 + double c = 0x1p-1; // 0.5 + double d = 0xFp+0; // 15.0 + + if (!nearly_equal(a, 1.0)) return EXIT_FAILURE; + if (!nearly_equal(b, 3.0)) return EXIT_FAILURE; + if (!nearly_equal(c, 0.5)) return EXIT_FAILURE; + if (!nearly_equal(d, 15.0)) return EXIT_FAILURE; + + // Test with fractional part + double e = 0x1.999999999999ap-4; // Approximately 0.1 + if (!nearly_equal(e, 0.1)) return EXIT_FAILURE; + + // Test with float type + float f = 0x1.0p+2f; // 4.0f + if (!nearly_equal(f, 4.0f)) return EXIT_FAILURE; + + // Test with long double + long double g = 0x1.0p+3L; // 8.0 + if (std::fabs(g - 8.0L) > std::numeric_limits::epsilon()) return EXIT_FAILURE; + + // All tests passed + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/if_switch_init_statement.cpp b/C++/cxx17/if_switch_init_statement.cpp new file mode 100644 index 0000000000..a54268d73e --- /dev/null +++ b/C++/cxx17/if_switch_init_statement.cpp @@ -0,0 +1,55 @@ +/* +FEATURE: Separate variable and condition for if and switch +SPEC: ISO/IEC 14882:2017 (C++17) §8.5 [stmt.if], §8.6 [stmt.switch] +PURPOSE: Verify that if and switch statements can use a separate initialization statement + followed by a condition, and that the initialized variables are scoped to the + corresponding statements. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror if_switch_init_statement.cpp +*/ + +#include +#include // for std::fabs + +// Helper for floating-point comparison +bool almost_equal(double x, double y, double eps = 1e-12) { + return std::fabs(x - y) <= eps; +} + +int main() +{ + int result = 0; + + // Test 1: if statement with separate initialization and condition + if (int value = 10; value == 10) { + // Expected path + result += 1; + } else { + // Should not be reached + return EXIT_FAILURE; + } + if (double value = 10.5; almost_equal(value, 10.5)) { + // Expected path + result += 1; + } else { + // Should not be reached + return EXIT_FAILURE; + } + + // Test 2: switch statement with separate initialization and condition + switch (int selector = 2; selector) { + case 1: + // Should not be reached + return EXIT_FAILURE; + case 2: + // Expected path + result += 1; + break; + default: + // Should not be reached + return EXIT_FAILURE; + } + + // Both tests must succeed + return (result == 3) ? EXIT_SUCCESS : EXIT_FAILURE; +} + diff --git a/C++/cxx17/ignore_unknown_attributes.cpp b/C++/cxx17/ignore_unknown_attributes.cpp new file mode 100644 index 0000000000..342fb6ffbe --- /dev/null +++ b/C++/cxx17/ignore_unknown_attributes.cpp @@ -0,0 +1,41 @@ +/* +FEATURE: Requirement to ignore unknown attributes +SPEC: ISO/IEC 14882:2017, N4659 §10.6.1 [dcl.attr.grammar] +PURPOSE: Verify that unknown attributes with an attribute-namespace are ignored + by the compiler and do not affect translation or execution. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror ignore_unknown_attributes.cpp +*/ + +#include + +/* + * An attribute with an unknown attribute-namespace and attribute-name. + * According to C++17, such attributes must be ignored. + */ +[[unknown_vendor::completely_unknown_attribute]] +int add(int a, int b) +{ + return a + b; +} + +[[unknown_attr]] int add2(int a, int b) { return a + b; } +[[deprecated]] int add3(int a, int b) { return a + b; } + +int main() +{ + /* + * If the compiler incorrectly rejects or mishandles the unknown attribute, + * this program will fail to compile or behave unexpectedly. + */ + int result = add(2, 3); + result = add2(2, 3); + result = add3(2, 3); + + // Runtime check to ensure normal execution. + if (result != 5) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/inline_variables.cpp b/C++/cxx17/inline_variables.cpp new file mode 100644 index 0000000000..96c0781df5 --- /dev/null +++ b/C++/cxx17/inline_variables.cpp @@ -0,0 +1,44 @@ +/* +FEATURE: Inline variables +SPEC: ISO/IEC 14882:2017 (C++17) §10.1.6 [dcl.inline] +PURPOSE: Verify that inline variables can be defined in headers (or multiple + translation units conceptually) without violating the One Definition + Rule, and that inline static data members can be defined and initialized + inside a class definition. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror inline_variables.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +#include "inline_variables.hpp" + +int main() +{ + // Access and modify the inline namespace-scope variable. + if (global_counter != 42) { + return EXIT_FAILURE; + } + global_counter += 1; + if (global_counter != 43) { + return EXIT_FAILURE; + } + + // Access the inline static data member. + if (TestClass::static_value != 100) { + return EXIT_FAILURE; + } + TestClass::static_value = 200; + if (TestClass::static_value != 200) { + return EXIT_FAILURE; + } + + // Use the inline constexpr variable in a context requiring a constant expression. + int array[array_size] = {0, 1, 2, 3}; + if (array[3] != 3) { + return EXIT_FAILURE; + } + + // All checks passed. + return EXIT_SUCCESS; +} diff --git a/C++/cxx17/inline_variables.hpp b/C++/cxx17/inline_variables.hpp new file mode 100644 index 0000000000..ae82cb0300 --- /dev/null +++ b/C++/cxx17/inline_variables.hpp @@ -0,0 +1,12 @@ +// An inline variable at namespace scope. +// Multiple definitions across translation units are allowed by the standard. +inline int global_counter = 42; + +// A class using an inline static data member. +// No out-of-class definition is required in C++17. +struct TestClass { + inline static int static_value = 100; +}; + +// Another inline variable to check constant initialization. +inline constexpr std::size_t array_size = 4; diff --git a/C++/cxx17/lambda_capture_this_value.cpp b/C++/cxx17/lambda_capture_this_value.cpp new file mode 100644 index 0000000000..21512b8cd7 --- /dev/null +++ b/C++/cxx17/lambda_capture_this_value.cpp @@ -0,0 +1,59 @@ +/* +FEATURE: C++17 Lambda capture of *this +SPEC: N4659 §7.5.5 [expr.prim.lambda.capture] +PURPOSE: Verify that capturing *this copies the object by value and is independent + from later modifications of the original object. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror lambda_capture_this_value.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +class Sample { +private: + int value; + +public: + explicit Sample(int v) : value(v) {} + + auto make_lambda_with_this_ptr() { + return [this]() { + return value; + }; + } + + auto make_lambda_with_this_copy() { + return [*this]() { + return value; + }; + } + + void set(int v) { + value = v; + } +}; + +int main() { + Sample obj(10); + + auto lambda_ptr = obj.make_lambda_with_this_ptr(); // Captures this as a pointer + auto lambda_copy = obj.make_lambda_with_this_copy(); // Captures *this by value (C++17 feature) + + obj.set(20); + + int result_ptr = lambda_ptr(); // Should see updated value (20) + int result_copy = lambda_copy(); // Should see old value (10) + + if (result_ptr != 20) { + std::cerr << "Pointer capture test failed\n"; + return EXIT_FAILURE; + } + + if (result_copy != 10) { + std::cerr << "Value capture test failed\n"; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/maybe_unused_attr.cpp b/C++/cxx17/maybe_unused_attr.cpp new file mode 100644 index 0000000000..f98e56e6e3 --- /dev/null +++ b/C++/cxx17/maybe_unused_attr.cpp @@ -0,0 +1,45 @@ +/* +FEATURE: [[maybe_unused]] attribute +SPEC: C++17 standard, N4659 §10.6.8 +PURPOSE: Verify that the [[maybe_unused]] attribute suppresses unused warnings for variables, functions, and parameters in Clang/LLVM. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror maybe_unused_attr.cpp +*/ + +#include +#define _UNUSED_STATUS 123 +#define _UNUSED_VALUE 42 +#define _UNUSED_PARAM_VALUE 5 +#define _UNUSED_VARIABLE_INIT 10 + +// A function marked as maybe_unused; may legitimately remain unused +[[maybe_unused]] +int unused_function() { + return _UNUSED_STATUS; +} + +// A structure with a maybe_unused member +struct Example { + [[maybe_unused]] int x = _UNUSED_STATUS; +}; + +// A function with a maybe_unused parameter +int process([[maybe_unused]] int param) { + return 0; // param intentionally unused +} + +int main() { + // A local variable that is intentionally unused + [[maybe_unused]] int local_value = _UNUSED_VARIABLE_INIT; + + // If the program compiles (no unused warnings promoted to errors), + // the feature is considered supported. + Example e; // e.x may be unused + (void)e; // Use e to avoid unrelated warnings + + // Call process (param unused inside) + process(_UNUSED_PARAM_VALUE); + + // No runtime failures expected + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/nested_namespace_definition.cpp b/C++/cxx17/nested_namespace_definition.cpp new file mode 100644 index 0000000000..c9bec2dd13 --- /dev/null +++ b/C++/cxx17/nested_namespace_definition.cpp @@ -0,0 +1,81 @@ +/* +FEATURE: Nested namespace definition +SPEC: C++17 Standard (e.g., N4659 §10.3) +PURPOSE: To verify that the C++17 nested namespace definition syntax (e.g., `namespace A::B::C { ... }`) is correctly parsed and compiled by the compiler, and that members defined within such namespaces are accessible as expected. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror nested_namespace_definition.cpp +*/ + +#include // Required for std::cout, std::cerr, and std::endl + +// Define a nested namespace using the C++17 syntax. +// This is equivalent to: +// namespace A { +// namespace B { +// namespace C { +// // ... +// } +// } +// } +namespace A::B::C { + + // A constant integer variable defined within the innermost namespace. + const int value = 123; + + // A simple function defined within the innermost namespace + // that returns the value of value. + int get_value() { + return value; + } + + // Another function to demonstrate usage. + void print_message() { + //std::cout << "Message from C: " << value << std::endl; + } + +} // namespace A::B::C + +int main() { + bool overall_success = true; // Flag to track test results + + // Test 1: Direct access to a variable using the fully qualified name. + //std::cout << "Test 1: Accessing A::B::C::value" << std::endl; + if (A::B::C::value == 123) { + //std::cout << " Passed: value is " << A::B::C::value << std::endl; + } else { + std::cerr << " Failed: value is " << A::B::C::value << ", expected 123." << std::endl; + overall_success = false; + } + + // Test 2: Direct access to a function using the fully qualified name. + //std::cout << "Test 2: Calling A::B::C::get_value()" << std::endl; + if (A::B::C::get_value() == 123) { + //std::cout << " Passed: get_value() returned " << A::B::C::get_value() << std::endl; + } else { + std::cerr << " Failed: get_value() returned " << A::B::C::get_value() << ", expected 123." << std::endl; + overall_success = false; + } + + // Test 3: Using a namespace alias for shorter access. + // This demonstrates that the nested namespace structure is correctly formed + // and can be aliased. + //std::cout << "Test 3: Using a namespace alias 'omi'" << std::endl; + namespace omi = A::B::C; + if (omi::value == 123) { + //std::cout << " Passed: Access via alias 'omi::value' is " << omi::value << std::endl; + } else { + std::cerr << " Failed: Access via alias 'omi::value' is " << omi::value << ", expected 123." << std::endl; + overall_success = false; + } + // Call a function using the alias + omi::print_message(); + + // Final result based on all tests. + if (overall_success) { + //std::cout << "\nAll C++17 nested namespace definition tests passed successfully." << std::endl; + return 0; // Return 0 for success + } else { + std::cerr << "\nOne or more C++17 nested namespace definition tests failed." << std::endl; + return 1; // Return non-zero for failure + } +} + diff --git a/C++/cxx17/no_trigraphs.cpp b/C++/cxx17/no_trigraphs.cpp new file mode 100644 index 0000000000..c72e826431 --- /dev/null +++ b/C++/cxx17/no_trigraphs.cpp @@ -0,0 +1,40 @@ +/* FEATURE: Disabling trigraph expansion by default + * SPEC: ISO/IEC 14882:2017 (C++17) [lex.trigraph] (formerly 2.4/1 Trigraph sequences) + * PURPOSE: In C++17, verify that trigraphs are not processed by default and result in a warning or error. + * RUN: clang++ -std=c++17 -Wall -Wextra -Werror no_trigraphs.cpp + */ + +#include +#include + +int main() { + // In C++14/earlier, the trigraph sequence '??/' in a string literal is + // replaced by the corresponding single character, which is '\'. + // For example, "dir??/file" would become "dir\file". + // The sequence '\f' is a valid escape sequence (form feed), so this would + // typically result in a string of length 7 in C++14/earlier. + // + // In C++17, trigraph sequences are NOT processed by default. + // Therefore, "dir??/file" should remain as "dir??/file", + // resulting in a string of length 10. + std::string test_str = "dir??/file"; + std::string converted_str = "dir??/file"; + + std::cout << "Testing C++17 'Disabling trigraph expansion by default'..." << std::endl; + std::cout << "Source string literal: \"dir??/file\"" << std::endl; + + if (test_str == converted_str) { + // This branch is taken if '??/' was NOT expanded. + // This is the expected default behavior for C++17. + std::cout << "Test PASSED: Trigraph '??/' was NOT expanded in string literal." << std::endl; + std::cout << "Resulting string: \"" << test_str << "\"" << "; Length: " << test_str.length() << std::endl; + return 0; // Success for C++17 behavior + } else { + // This branch is taken if '??/' WAS expanded. + // This indicates C++14/earlier behavior (trigraphs were expanded). + std::cout << "Test FAILED: Trigraph '??/' WAS expanded in string literal." << std::endl; + std::cout << "Expected C++17 string: \"" << converted_str << "\"" << "; Length: " << converted_str.length() << std::endl; + std::cout << "Actual string (after potential expansion): \"" << test_str << "\"" << "; Length: " << test_str.length() << std::endl; + return 1; // Failure for C++17 behavior (trigraphs were expanded) + } +} diff --git a/C++/cxx17/nodiscard_attr.cpp b/C++/cxx17/nodiscard_attr.cpp new file mode 100644 index 0000000000..eb74ff3799 --- /dev/null +++ b/C++/cxx17/nodiscard_attr.cpp @@ -0,0 +1,51 @@ +/* +FEATURE: [[nodiscard]] attribute +SPEC: N4659 §7.6.5 +PURPOSE: Verify that ignoring the return value of an entity marked with [[nodiscard]] triggers a diagnostic. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror nodiscard_attr.cpp +*/ + +#include + +#define _FAIL 1 +#define _VALUE 1000 + +// Function marked as [[nodiscard]] +[[nodiscard]] int compute_value() { + return _VALUE; +} + +// Struct marked as [[nodiscard]] +struct [[nodiscard]] foo_struct { + int value; +} foo_obj; + +struct foo_struct get_value() { + return foo_obj; +} + +int main() { + // --- Expected warning (ignored return value) --- + // The following code must NOT be compiled in the final test run, + // because ignoring a [[nodiscard]] return value will cause an error + // under -Werror. Therefore, it is conditionally compiled. +#if 0 + compute_value(); // This should trigger a warning. + get_value(); // This should also trigger a warning. +#endif + + // --- Valid usage: result is stored and used --- + int v = compute_value(); + if (v != _VALUE) { + return _FAIL; + } + + foo_obj.value = _VALUE; + v = get_value().value; + if (v != _VALUE) { + return _FAIL; + } + + return 0; +} + diff --git a/C++/cxx17/non_type_template_consteval.cpp b/C++/cxx17/non_type_template_consteval.cpp new file mode 100644 index 0000000000..cb85928c06 --- /dev/null +++ b/C++/cxx17/non_type_template_consteval.cpp @@ -0,0 +1,65 @@ +// non_type_template_consteval.cpp +/* +FEATURE: Allow constant evaluation for all non-type template arguments +SPEC: ISO C++17 (ISO/IEC 14882:2017), non-type template argument constant-evaluation rules (see example reference: N4268 §14.3) +PURPOSE: Verify that values produced by constexpr (integral expressions, addresses of objects/functions with appropriate linkage) + can be used as non-type template arguments and that templates instantiate and behave as expected. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror non_type_template_consteval.cpp +*/ + +#include // for std::size_t + +#define TEST_INT_VALUE 7 +#define TEST_FUNC_RETVALUE 5 +#define TEST_OBJPTR_VALUE 10 + +// Test 1: integral value produced by a constexpr function used as a non-type template argument. +template +struct IntNTTP { + static constexpr int value = N; +}; + +constexpr int make_int() { return 3 + 4; } // constexpr evaluation -> TEST_INT_VALUE +using IntInst = IntNTTP; + +// Test 2: pointer-to-function used as a non-type template argument. +constexpr int fn() { return TEST_FUNC_RETVALUE; } + +template +struct FuncPtrNTTP { + static constexpr int call() { return F(); } +}; + +using FuncInst = FuncPtrNTTP<&fn>; + +// Test 3: pointer-to-object used as a non-type template argument. +// The object must have appropriate linkage to be a constant expression for an address. +// Declare with external linkage and define in the same translation unit. +extern const int obj; // declaration with external linkage +const int obj = TEST_OBJPTR_VALUE; // definition + +template +struct ObjPtrNTTP { + static constexpr int value = *P; +}; + +using ObjInst = ObjPtrNTTP<&obj>; + +// Fallback runtime checks: if compilation succeeds (feature supported by the compiler), +// the program will run and return 0 on success, non-zero on failure. +int main() { + // Perform runtime checks that mirror the compile-time expectations. + bool ok = true; + + // Check IntNTTP + if (IntInst::value != TEST_INT_VALUE) ok = false; + + // Check FuncPtrNTTP + if (FuncInst::call() != TEST_FUNC_RETVALUE) ok = false; + + // Check ObjPtrNTTP + if (ObjInst::value != TEST_OBJPTR_VALUE) ok = false; + + return ok ? 0 : 1; +} + diff --git a/C++/cxx17/overaligned_allocation.cpp b/C++/cxx17/overaligned_allocation.cpp new file mode 100644 index 0000000000..1c45fea653 --- /dev/null +++ b/C++/cxx17/overaligned_allocation.cpp @@ -0,0 +1,46 @@ +/* +FEATURE: Dynamic memory allocation for over-aligned data +SPEC: N4140 §3.7.4.1 / P0035R4 +PURPOSE: Verify that dynamic allocation using `new` preserves alignment for over-aligned types. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror overaligned_allocation.cpp +*/ + +#include +#include +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE +#define TEST_ALIGN 64 +#define CHECK_VALUE 56 + +struct alignas(TEST_ALIGN) OverAlignedType { + int value; +}; + +int main() { + // Dynamically allocate an over-aligned object + OverAlignedType* ptr = nullptr; + + try { + ptr = new OverAlignedType{CHECK_VALUE}; + } catch (const std::bad_alloc&) { + return EXIT_FAILURE; // Allocation failed → test failure + } + + // Check the alignment + std::uintptr_t addr = reinterpret_cast(ptr); + if (addr % alignof(OverAlignedType) != 0) { + delete ptr; + return EXIT_FAILURE; // Misaligned allocation → test failure + } + + // Check the stored value for sanity + if (ptr->value != CHECK_VALUE) { + delete ptr; + return EXIT_FAILURE; // Value corrupted → unexpected failure + } + + delete ptr; + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/pack_expansion_using_declaration.cpp b/C++/cxx17/pack_expansion_using_declaration.cpp new file mode 100644 index 0000000000..4efa33935d --- /dev/null +++ b/C++/cxx17/pack_expansion_using_declaration.cpp @@ -0,0 +1,46 @@ +/* +FEATURE: Pack expansions in using-declarations +SPEC: ISO/IEC 14882:2017 (C++17), N4659 §10.3 [namespace.udecl] +PURPOSE: Verify that parameter packs can be expanded inside using-declarations + to bring multiple base class members into the derived class scope. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror pack_expansion_using_declaration.cpp +*/ + +#include + +// First base class providing a member function +struct BaseA { + int value() const { return 1; } +}; + +// Second base class providing a member function with the same name +struct BaseB { + int value() const { return 2; } +}; + +// Variadic template inheriting from multiple base classes +template +struct Derived : Bases... { + // C++17 feature: pack expansion in using-declarations + using Bases::value...; +}; + +int main() +{ + Derived d; + + // Explicit qualification is required to select the correct base + int a = d.BaseA::value(); + int b = d.BaseB::value(); + + // Validate that both functions are correctly accessible + if (a != 1) { + return EXIT_FAILURE; + } + if (b != 2) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/range_for_sentinel.cpp b/C++/cxx17/range_for_sentinel.cpp new file mode 100644 index 0000000000..90449b34f5 --- /dev/null +++ b/C++/cxx17/range_for_sentinel.cpp @@ -0,0 +1,81 @@ +/* +FEATURE: Differing begin and end types in range-based for +SPEC: example working draft note (e.g. N4659 §6.5.4) - begin and end may have differing types if comparable +PURPOSE: Verify that a range with an iterator type returned by begin() and a distinct sentinel type returned by end() can be used in a range-based for loop under C++17. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror range_for_sentinel.cpp +*/ + +// A minimal test demonstrating an iterator + sentinel pair with different types +// used in a range-based for loop. The program returns 0 on success, non-zero on +// failure. Comments are in English as requested. + +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// Forward declaration of sentinel +//struct EndSentinel; + +// Iterator type +struct MyIterator { + int current; + + int operator*() const { return current; } + + MyIterator& operator++() { + ++current; + return *this; + } +}; + +// Sentinel type (different type from MyIterator) +struct EndSentinel { + int limit; +}; + +// Comparison between iterator and sentinel (iterator != sentinel) +bool operator!=(const MyIterator& it, const EndSentinel& s) { + return it.current != s.limit; +} + +// Also provide comparison in the other order for completeness (not required by range-for but harmless) +bool operator!=(const EndSentinel& s, const MyIterator& it) { + return it != s; +} + +// Range object that returns MyIterator from begin() and EndSentinel from end() +struct MyRange { + int start; + int finish; // exclusive + + MyIterator begin() const { return MyIterator{start}; } + EndSentinel end() const { return EndSentinel{finish}; } +}; + +int main() { + // Create a range generating 0,1,2,3,4 + MyRange r{0, 5}; + + std::vector collected; + for (int v : r) { + collected.push_back(v); + } + + // Expected sequence + std::vector expect{0,1,2,3,4}; + + if (collected == expect) { + // success + return EXIT_SUCCESS; + } else { + // print diagnostic for human debugging and return failure + std::cerr << "Collected sequence mismatch:\n"; + std::cerr << "Got: "; + for (int x : collected) std::cerr << x << ' '; + std::cerr << "\nExpected: "; + for (int x : expect) std::cerr << x << ' '; + std::cerr << '\n'; + return EXIT_FAILURE; + } +} + diff --git a/C++/cxx17/remove_register_storage_class.cpp b/C++/cxx17/remove_register_storage_class.cpp new file mode 100644 index 0000000000..3ab2eea1c0 --- /dev/null +++ b/C++/cxx17/remove_register_storage_class.cpp @@ -0,0 +1,15 @@ +/* +FEATURE: Remove deprecated register storage class +SPEC: ISO C++17, removal of the 'register' keyword (formerly deprecated) +PURPOSE: Verify that using the 'register' storage class specifier causes a compile-time error in C++17. +RUN: clang++ -std=c++17 -Wall -Wextra remove_register_storage_class.cpp +*/ + +int main() { + // Using 'register' should be rejected in C++17. + register int x = 0; // Expect compile error: 'register' is removed in C++17 + + // If the compiler incorrectly accepts the code, return non-zero. + return (x == 0) ? 1 : 1; +} + diff --git a/C++/cxx17/removed_dynamic_exception_spec.cpp b/C++/cxx17/removed_dynamic_exception_spec.cpp new file mode 100644 index 0000000000..6cab802580 --- /dev/null +++ b/C++/cxx17/removed_dynamic_exception_spec.cpp @@ -0,0 +1,49 @@ +/* +FEATURE: Removing deprecated dynamic exception specifications +SPEC: ISO/IEC 14882:2017 (C++17) §15.4 Exception specifications [except.spec] +PURPOSE: Verify that dynamic exception specifications are no longer supported + in C++17 and that noexcept is the only remaining exception specification. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror removed_dynamic_exception_spec.cpp +*/ + +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// In C++11 and C++14, the following declaration was allowed but deprecated: +// +// void legacy_function() throw(int); +// +// In C++17, dynamic exception specifications are completely removed. +// Uncommenting the declaration below must cause a compilation error. +// +// void legacy_function() throw(int); // expected to be ill-formed in C++17 + +// Correct C++17-style exception specification using noexcept +void safe_function() noexcept +{ + // This function guarantees not to throw. +} + +// A function without noexcept may throw exceptions +void unsafe_function() +{ +} + +// Compile-time checks using the noexcept operator +static_assert(noexcept(safe_function()), + "safe_function must be noexcept in C++17"); + +static_assert(!noexcept(unsafe_function()), + "unsafe_function must not be noexcept"); + +int main() +{ + // Call the functions to ensure they are odr-used + safe_function(); + unsafe_function(); + + // If compilation succeeds and static_asserts pass, + // the test is considered successful. + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/static_assert_no_message.cpp b/C++/cxx17/static_assert_no_message.cpp new file mode 100644 index 0000000000..6b79430e67 --- /dev/null +++ b/C++/cxx17/static_assert_no_message.cpp @@ -0,0 +1,17 @@ +/* FEATURE: C++17 static_assert with no message + * SPEC: C++17 Standard, [dcl.dcl]/p4 (or similar, exact location may vary slightly between drafts) + * PURPOSE: To verify that C++17 allows `static_assert` without a message string, + * and that older standards (e.g., C++14) correctly reject it. + * RUN: clang++ -std=c++17 -Wall -Wextra -Werror static_assert_no_message.cpp + */ + +int main() { + // This static_assert has no message. + // In C++17 and later, this should compile successfully. + // requiring a message string. + static_assert(true); + + // If we reach here, the static_assert succeeded. + return 0; // Success +} + diff --git a/C++/cxx17/stricter_expression_evaluation_order.cpp b/C++/cxx17/stricter_expression_evaluation_order.cpp new file mode 100644 index 0000000000..ed51c9ac4b --- /dev/null +++ b/C++/cxx17/stricter_expression_evaluation_order.cpp @@ -0,0 +1,138 @@ +/* +FEATURE: Stricter expression evaluation order +SPEC: ISO/IEC 14882:2017 (C++17) §8.18 [expr.ass], §15.4 [intro.execution] +PURPOSE: Verify that C++17 defines a strict sequencing rule for assignment + expressions, making previously undefined expressions well-defined. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror stricter_expression_evaluation_order.cpp +*/ + +#include + +// C++ Assignment Operator +int assign_op(void) +{ + /* + * Before C++17, the expression below had undefined behavior because + * the read and modification of 'i' were unsequenced. + * + * In C++17, the right-hand side of the assignment is sequenced + * before the actual assignment to the left-hand side. + * + * Therefore, the side effect of i++ is fully evaluated before + * the assignment to 'i' takes place. + */ + int i = 1; + i = i++; + + /* + * With C++17 rules, the result is well-defined: + * - i++ yields the old value (1) and increments i to 2 + * - the assignment then stores the old value (1) into i + * - final value of i is 1 + */ + // C++17: well-defined, final value must be 1 + return (i == 1) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +// C++ Compound Assignment Operator +int comp_assign_op(void) +{ + int i = 1; + int j = (i += i++); + + // C++17: + // i++ yields 1, increments i to 2 + // i += 1 -> i becomes 3 + // j receives 3 + return (i == 3 && j == 3) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +// C++ Function Call +int g = 0; + +int f(int) +{ + // All argument side effects must be complete before this runs + if (g != 2) { + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} + +int func_call(void) +{ + return f(g = 2); +} + +// C++ Conditional Operator +int cond_op(void) +{ + int i = 0; + + bool cond = true; + int result = cond ? ++i : (i += 10); + + // Only ++i must be evaluated + return (i == 1 && result == 1) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +// C++ Logical AND Operator +int log_and_op(void) +{ + int i = 0; + + false && (++i); + + // Right operand must not be evaluated + return (i == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +// C++ Logical OR Operator +int log_or_op(void) +{ + int i = 0; + + true || (++i); + + // Right operand must not be evaluated + return (i == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +// C++ Comma Operator +int comma_op(void) +{ + int i = 0; + int j = (i = 1, i = 2); + + // Left expression sequenced before right + return (i == 2 && j == 2) ? EXIT_SUCCESS : EXIT_FAILURE; +} + +int main() +{ + int ret_value = EXIT_SUCCESS; + + ret_value = assign_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = comp_assign_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = func_call(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = cond_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = log_and_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = log_or_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + ret_value = comma_op(); + if (ret_value == EXIT_FAILURE) return EXIT_FAILURE; + + return ret_value; +} + diff --git a/C++/cxx17/structured_bindings.cpp b/C++/cxx17/structured_bindings.cpp new file mode 100644 index 0000000000..1612a0a497 --- /dev/null +++ b/C++/cxx17/structured_bindings.cpp @@ -0,0 +1,68 @@ +/* +FEATURE: Structured bindings +SPEC: ISO/IEC 14882:2017 (C++17) §9.6 [dcl.struct.bind] +PURPOSE: Verify that structured bindings correctly decompose arrays, std::pair, + std::tuple, and aggregate structures when compiled with C++17. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror structured_bindings.cpp +*/ + +#include +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE +#include // for std::fabs + +struct Point { + int x; + int y; +}; + +// Helper for floating-point comparison +bool almost_equal(double x, double y, double eps = 1e-12) { + return std::fabs(x - y) <= eps; +} + +int main() +{ + // 1. Structured binding with a built-in array + int arr[2] = {1, 2}; + auto [a, b] = arr; + if (a != 1 || b != 2) { + return EXIT_FAILURE; + } + + // 2. Structured binding with std::pair + std::pair p{3, 4}; + auto [c, d] = p; + if (c != 3 || d != 4) { + return EXIT_FAILURE; + } + std::pair p2{3, 4.5}; + auto [cc, dd] = p2; + if (cc != 3 || !almost_equal(dd, 4.5)) { + return EXIT_FAILURE; + } + + // 3. Structured binding with std::tuple + std::tuple t{5, 6, 7}; + auto [e, f, g] = t; + if (e != 5 || f != 6 || g != 7) { + return EXIT_FAILURE; + } + std::tuple t2{5, 6.5, '7'}; + auto [ee, ff, gg] = t2; + if (ee != 5 || !almost_equal(ff, 6.5) || gg != '7') { + return EXIT_FAILURE; + } + + // 4. Structured binding with an aggregate type + Point pt{8, 9}; + auto [x, y] = pt; + if (x != 8 || y != 9) { + return EXIT_FAILURE; + } + + // All structured binding tests passed + return EXIT_SUCCESS; +} + diff --git a/C++/cxx17/template_template_compat.cpp b/C++/cxx17/template_template_compat.cpp new file mode 100644 index 0000000000..35391337fc --- /dev/null +++ b/C++/cxx17/template_template_compat.cpp @@ -0,0 +1,32 @@ +/* +FEATURE: Matching template template parameters to compatible arguments +SPEC: ISO/IEC 14882:2017 (C++17), based on CWG/P0522R0 +PURPOSE: Verify that a template template parameter can accept a compatible + class template that has additional defaulted template parameters. +RUN: clang++ -std=c++17 -Wall -Wextra -Werror template_template_compat.cpp +*/ + +#include +#include +#include // for EXIT_SUCCESS / EXIT_FAILURE + +// A template that expects a template with at least one type parameter. +template