From patchwork Sat Jul 19 06:42:23 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Braden Obrzut X-Patchwork-Id: 371773 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 62477140132 for ; Sat, 19 Jul 2014 16:42:40 +1000 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=GA+FGglc+bhsesPo9 5fZOvrPXSDr8t4fjZ5FagG/5oBRDNkUzG/94a3oEBaf8VwmNpbziaNkeXd6zzqjr 489p+ecJFmJX9CnBfb3lfnZzos9f6trsz+q2PacNCu1wIiBp19gp0r0hXsdX5RxC 3bqj4fRgS7KY6rggo/GsObPojA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=fmRZUWfAhcvde24UljIGjR4 Yxts=; b=oLVDGRVcKUTfeeSLTvGy5hZipFTRpl/yxRf03n9uTro/VtTPeOMrjnI agvC5G7ePRv/8rLk6pEqd5IQMD7HdbarlhTyE9ykmpBqDlCbi5NEVkU1lVU0dBD6 fdzYCWW7KpmTAV2tO0LTjWV25nuA9ANDxXmlO12Xud/rrhj6eeIA= Received: (qmail 13473 invoked by alias); 19 Jul 2014 06:42:28 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 13457 invoked by uid 89); 19 Jul 2014 06:42:27 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.5 required=5.0 tests=AWL, BAYES_40, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-ie0-f177.google.com Received: from mail-ie0-f177.google.com (HELO mail-ie0-f177.google.com) (209.85.223.177) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Sat, 19 Jul 2014 06:42:25 +0000 Received: by mail-ie0-f177.google.com with SMTP id at20so5097300iec.8 for ; Fri, 18 Jul 2014 23:42:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type; bh=Me7cmZb+sUMQJKgJDn/9SuuKD13cHB6p8lAmwfyuF9w=; b=INWIVnsQwyvlHSxBw55pRFOlc3i/gH3UUrHGsZRef7P6ShdzRY+f695IhjvaGmeOfb 9E/NgWy2zAMV17OKJrIoGazZ0L5ZsLrTpoi116VyDyUDt23JnnrlJfrt3esEIh95mKPm Z8RFyl19rvXsd0JIzUweie8AA4I2xkY1Clwoe5P+84eO8WwTVUsK/Ik7tKihw3iTi4c1 5YCK6vFC1RejVTcmT18g1wZwT7i+XXWMWCXCs57Jy0bnPRVy7SUzrcW/N+BmWk+TCo73 MdoR4TcWBMHNRIx7Hrd20fMdQShB9PSZn0q0cfshym+OZ1llrHgYlTWiRmu4D/+7qvA2 zvSg== X-Gm-Message-State: ALoCoQmy87vjucNrVuste9p1LNuhYueqaAWr+MVlGP+3UUM4QqamzLEw0vH0ODYs5r6E3l1VM5T0 X-Received: by 10.50.129.104 with SMTP id nv8mr16632920igb.45.1405752142819; Fri, 18 Jul 2014 23:42:22 -0700 (PDT) Received: from [192.168.2.199] (dynamic-acs-24-101-71-96.zoominternet.net. [24.101.71.96]) by mx.google.com with ESMTPSA id qd8sm1694453igb.1.2014.07.18.23.42.21 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 18 Jul 2014 23:42:22 -0700 (PDT) Message-ID: <53CA134F.4090608@maniacsvault.net> Date: Sat, 19 Jul 2014 02:42:23 -0400 From: Braden Obrzut User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: Andrew Sutton Subject: Re: Patch for constexpr variable templates References: <53C205E0.6070907@maniacsvault.net> In-Reply-To: <53C205E0.6070907@maniacsvault.net> While working on variable concepts, I noticed that one of the added blocks of code was no longer needed due to a previous simplification and caused problems. Also included a new test case which triggered the problem, and fixed a minor formatting issue. As before, if the plan is to revive the existing variable template branch, I can redo the patch without Gabriel's changes. 2014-07-19 Braden Obrzut * decl.c (grokvardecl): Handle specializations of variable templates. (grokdeclarator): Handle variable template id expressions. * decl2.c (check_member_template): Allow declaration of template member variables. (grokfield): Assign class context to template member variables in order that variable_template_p to detect them properly. * parser.c (cp_parser_postfix_expression): Resolve VAR_DECLs from TEMPLATE_ID_EXPRs. (cp_parser_template_id): Build a TEMPLATE_ID_EXPR for variable templates. * pt.c (register_specialization): Accept variable templates. (determine_specialization): Accept variable templates. (check_template_variable): Fixed wanted template header count. (lookup_template_variable): New. (do_decl_instantiation): Handle templat variables. (instantiate_decl): Handle template variables. * semantics.c (finish_template_variable): New. 2014-07-19 Braden Obrzut * g++.dg/template/var-templ1.C: New. * g++.dg/template/var-templ2.C: New. * g++.dg/template/var-templ3.C: New. * g++.dg/template/var-templ4.C: New. * g++.dg/template/var-templ5.C: New. 2013-03-29 Gabriel Dos Reis * cp-tree.h (variable_template_p): Do not check scope. * pt.c (check_template_variable): Fix thinko from previous change. (push_template_decl_real): Fix formatting. 2013-03-29 Gabriel Dos Reis * cp-tree.h (variable_template_p): New. * pt.c (check_template_variable): Accept variable temploids at non-class scope. (push_template_decl_real): The current instantiation of a template can be a VAR_DECL. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4a5cb98..caaaa6c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5027,6 +5027,17 @@ class_of_this_parm (const_tree fntype) return TREE_TYPE (type_of_this_parm (fntype)); } +/* True if T designates a variable template declaration. */ +inline bool +variable_template_p (tree t) +{ + if (TREE_CODE (t) != TEMPLATE_DECL) + return false; + if (tree r = DECL_TEMPLATE_RESULT (t)) + return VAR_P (r); + return false; +} + /* A parameter list indicating for a function with no parameters, e.g "int f(void)". */ extern cp_parameter_declarator *no_parameters; @@ -5554,6 +5565,7 @@ extern bool redeclare_class_template (tree, tree); extern tree lookup_template_class (tree, tree, tree, tree, int, tsubst_flags_t); extern tree lookup_template_function (tree, tree); +extern tree lookup_template_variable (tree, tree); extern int uses_template_parms (tree); extern int uses_template_parms_level (tree, int); extern bool in_template_function (void); @@ -5816,6 +5828,7 @@ extern tree perform_koenig_lookup (tree, vec *, tsubst_flags_t); extern tree finish_call_expr (tree, vec **, bool, bool, tsubst_flags_t); +extern tree finish_template_variable (tree); extern tree finish_increment_expr (tree, enum tree_code); extern tree finish_this_expr (void); extern tree finish_pseudo_destructor_expr (tree, tree, tree, location_t); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index dae85c2..0b6fa54 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -80,8 +80,8 @@ static int ambi_op_p (enum tree_code); static int unary_op_p (enum tree_code); static void push_local_name (tree); static tree grok_reference_init (tree, tree, tree, int); -static tree grokvardecl (tree, tree, const cp_decl_specifier_seq *, - int, int, tree); +static tree grokvardecl (tree, tree, tree, const cp_decl_specifier_seq *, + int, int, int, tree); static int check_static_variable_definition (tree, tree); static void record_unknown_type (tree, const char *); static tree builtin_function_1 (tree, tree, bool); @@ -7943,9 +7943,11 @@ set_linkage_for_static_data_member (tree decl) static tree grokvardecl (tree type, tree name, + tree orig_declarator, const cp_decl_specifier_seq *declspecs, int initialized, int constp, + int template_count, tree scope) { tree decl; @@ -7975,7 +7977,9 @@ grokvardecl (tree type, || (TREE_CODE (scope) == NAMESPACE_DECL && current_lang_name != lang_name_cplusplus) /* Similarly for static data members. */ - || TYPE_P (scope))) + || TYPE_P (scope) + /* Similarly for explicit specializations. */ + || TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)) decl = build_lang_decl (VAR_DECL, name, type); else decl = build_decl (input_location, VAR_DECL, name, type); @@ -8043,6 +8047,14 @@ grokvardecl (tree type, else DECL_INTERFACE_KNOWN (decl) = 1; + // Handle explicit specializations and instantiations of variable templates. + if (orig_declarator && (processing_template_decl + || TREE_CODE (orig_declarator) == TEMPLATE_ID_EXPR)) + { + decl = check_explicit_specialization (orig_declarator, decl, + template_count, 0); + } + return decl; } @@ -8944,8 +8956,13 @@ grokdeclarator (const cp_declarator *declarator, dname = fns; if (!identifier_p (dname)) { - gcc_assert (is_overloaded_fn (dname)); - dname = DECL_NAME (get_first_fn (dname)); + if (variable_template_p (dname)) + dname = DECL_NAME (dname); + else + { + gcc_assert (is_overloaded_fn (dname)); + dname = DECL_NAME (get_first_fn (dname)); + } } } /* Fall through. */ @@ -9986,7 +10003,8 @@ grokdeclarator (const cp_declarator *declarator, if (unqualified_id && TREE_CODE (unqualified_id) == TEMPLATE_ID_EXPR && TREE_CODE (type) != FUNCTION_TYPE - && TREE_CODE (type) != METHOD_TYPE) + && TREE_CODE (type) != METHOD_TYPE + && !variable_template_p (TREE_OPERAND (unqualified_id, 0))) { error ("template-id %qD used as a declarator", unqualified_id); @@ -10876,10 +10894,11 @@ grokdeclarator (const cp_declarator *declarator, /* It's a variable. */ /* An uninitialized decl with `extern' is a reference. */ - decl = grokvardecl (type, unqualified_id, + decl = grokvardecl (type, dname, unqualified_id, declspecs, initialized, (type_quals & TYPE_QUAL_CONST) != 0, + template_count, ctype ? ctype : in_namespace); bad_specifiers (decl, BSP_VAR, virtualp, memfn_quals != TYPE_UNQUALIFIED, diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 0926dbc..cd0c68e 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -529,6 +529,8 @@ check_member_template (tree tmpl) with member templates. */ DECL_IGNORED_P (tmpl) = 1; } + else if (variable_template_p (tmpl)) + /* OK */; else error ("template declaration of %q#D", decl); } @@ -987,6 +989,10 @@ grokfield (const cp_declarator *declarator, if (processing_template_decl && VAR_OR_FUNCTION_DECL_P (value)) { + /* Variable templates will need to have the class context. */ + if (VAR_P (value)) + DECL_CONTEXT (value) = current_class_type; + value = push_template_decl (value); if (error_operand_p (value)) return error_mark_node; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 72f987e..e076a6c 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6256,6 +6256,14 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p, break; default: + /* Convert variable template into VAR_DECL. */ + if (TREE_CODE (postfix_expression) == TEMPLATE_ID_EXPR + && variable_template_p (TREE_OPERAND (postfix_expression, 0))) + { + postfix_expression = finish_template_variable (postfix_expression); + } + + if (pidk_return != NULL) * pidk_return = idk; if (member_access_only_p) @@ -13558,6 +13566,10 @@ cp_parser_template_id (cp_parser *parser, template_id = finish_template_type (templ, arguments, entering_scope); } + else if (variable_template_p (templ)) + { + template_id = lookup_template_variable (templ, arguments); + } else { /* If it's not a class-template or a template-template, it should be diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7b79280..d2a12b7 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1353,7 +1353,7 @@ register_specialization (tree spec, tree tmpl, tree args, bool is_friend, || (TREE_CODE (tmpl) == FIELD_DECL && TREE_CODE (spec) == NONTYPE_ARGUMENT_PACK)); - if (TREE_CODE (spec) == FUNCTION_DECL + if ((TREE_CODE (spec) == FUNCTION_DECL || TREE_CODE (spec) == VAR_DECL) && uses_template_parms (DECL_TI_ARGS (spec))) /* This is the FUNCTION_DECL for a partial instantiation. Don't register it; we want the corresponding TEMPLATE_DECL instead. @@ -1878,7 +1878,8 @@ determine_specialization (tree template_id, if (BASELINK_P (fns)) fns = BASELINK_FUNCTIONS (fns); - if (!is_overloaded_fn (fns)) + bool var_templ = variable_template_p (fns); + if (!is_overloaded_fn (fns) && !var_templ) { error ("%qD is not a function template", fns); return error_mark_node; @@ -1892,7 +1893,12 @@ determine_specialization (tree template_id, b = b->level_chain) ++header_count; - for (; fns; fns = OVL_NEXT (fns)) + if (var_templ) + { + templates = tree_cons (explicit_targs, fns, templates); + } + else + for (; fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); @@ -2308,9 +2314,15 @@ check_template_variable (tree decl) tree ctx = CP_DECL_CONTEXT (decl); int wanted = num_template_headers_for_class (ctx); if (!TYPE_P (ctx) || !CLASSTYPE_TEMPLATE_INFO (ctx)) - permerror (DECL_SOURCE_LOCATION (decl), - "%qD is not a static data member of a class template", decl); - else if (template_header_count > wanted) + { + if (cxx_dialect < cxx1y) + permerror (DECL_SOURCE_LOCATION (decl), + "%qD is not a static data member of a class template", decl); + + // Namespace scope variable templates should have a template header. + ++wanted; + } + if (template_header_count > wanted) { bool warned = pedwarn (DECL_SOURCE_LOCATION (decl), 0, "too many template headers for %D (should be %d)", @@ -2481,7 +2493,10 @@ check_explicit_specialization (tree declarator, gcc_unreachable (); } - if (specialization || member_specialization) + if ((specialization || member_specialization) + /* Variable templates don't apply. */ + && (TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)) { tree t = TYPE_ARG_TYPES (TREE_TYPE (decl)); for (; t; t = TREE_CHAIN (t)) @@ -2691,7 +2706,8 @@ check_explicit_specialization (tree declarator, /* If we thought that the DECL was a member function, but it turns out to be specializing a static member function, make DECL a static member function as well. */ - if (DECL_STATIC_FUNCTION_P (tmpl) + if (!variable_template_p (tmpl) + && DECL_STATIC_FUNCTION_P (tmpl) && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) revert_static_member_fn (decl); @@ -2725,7 +2741,8 @@ check_explicit_specialization (tree declarator, /* Inherit default function arguments from the template DECL is specializing. */ - copy_default_args_to_explicit_spec (decl); + if (!variable_template_p (tmpl)) + copy_default_args_to_explicit_spec (decl); /* This specialization has the same protection as the template it specializes. */ @@ -2794,6 +2811,7 @@ check_explicit_specialization (tree declarator, /* A 'structor should already have clones. */ gcc_assert (decl == error_mark_node + || variable_template_p (tmpl) || !(DECL_CONSTRUCTOR_P (decl) || DECL_DESTRUCTOR_P (decl)) || DECL_CLONED_FUNCTION_P (DECL_CHAIN (decl))); @@ -4738,6 +4756,11 @@ push_template_decl_real (tree decl, bool is_friend) && TYPE_DECL_ALIAS_P (decl)) /* alias-declaration */ gcc_assert (!DECL_ARTIFICIAL (decl)); + else if (VAR_P (decl)) + { + if (!DECL_DECLARED_CONSTEXPR_P (decl)) + error ("template declaration of non-constexpr variable %qD", decl); + } else { error ("template declaration of %q#D", decl); @@ -7899,6 +7922,14 @@ lookup_template_class (tree d1, tree arglist, tree in_decl, tree context, timevar_pop (TV_TEMPLATE_INST); return ret; } + +/* Return a TEMPLATE_ID_EXPR for the given variable template and ARGLIST. */ + +tree +lookup_template_variable (tree templ, tree arglist) +{ + return build2 (TEMPLATE_ID_EXPR, TREE_TYPE (templ), templ, arglist); +} struct pair_fn_data { @@ -19146,7 +19177,11 @@ do_decl_instantiation (tree decl, tree storage) error ("explicit instantiation of non-template %q#D", decl); return; } - else if (VAR_P (decl)) + + bool var_templ = DECL_TEMPLATE_INFO (decl) + && variable_template_p (DECL_TI_TEMPLATE (decl)); + + if (VAR_P (decl) && !var_templ) { /* There is an asymmetry here in the way VAR_DECLs and FUNCTION_DECLs are handled by grokdeclarator. In the case of @@ -19175,7 +19210,7 @@ do_decl_instantiation (tree decl, tree storage) return; } } - else if (TREE_CODE (decl) != FUNCTION_DECL) + else if (TREE_CODE (decl) != FUNCTION_DECL && !var_templ) { error ("explicit instantiation of %q#D", decl); return; @@ -19885,10 +19920,12 @@ instantiate_decl (tree d, int defer_ok, tree ns; tree init; bool const_init = false; + bool enter_context = CLASS_TYPE_P (DECL_CONTEXT (d)); ns = decl_namespace_context (d); push_nested_namespace (ns); - push_nested_class (DECL_CONTEXT (d)); + if (enter_context) + push_nested_class (DECL_CONTEXT (d)); init = tsubst_expr (DECL_INITIAL (code_pattern), args, tf_warning_or_error, NULL_TREE, @@ -19900,7 +19937,8 @@ instantiate_decl (tree d, int defer_ok, cp_finish_decl (d, init, /*init_const_expr_p=*/const_init, /*asmspec_tree=*/NULL_TREE, LOOKUP_ONLYCONVERTING); - pop_nested_class (); + if (enter_context) + pop_nested_class (); pop_nested_namespace (ns); } @@ -19996,11 +20034,16 @@ instantiate_decl (tree d, int defer_ok, we have a chance to determine linkage. */ DECL_EXTERNAL (d) = 0; - /* Enter the scope of D so that access-checking works correctly. */ - push_nested_class (DECL_CONTEXT (d)); + /* Enter the scope of D so that access-checking works correctly. */ + bool enter_context = CLASS_TYPE_P (DECL_CONTEXT (d)); + if (enter_context) + push_nested_class (DECL_CONTEXT (d)); + const_init = DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (code_pattern); cp_finish_decl (d, init, const_init, NULL_TREE, 0); - pop_nested_class (); + + if (enter_context) + pop_nested_class (); } else if (TREE_CODE (d) == FUNCTION_DECL && DECL_DEFAULTED_FN (code_pattern)) synthesize_method (d); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a6d941b..da8766a 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2418,6 +2418,14 @@ finish_call_expr (tree fn, vec **args, bool disallow_virtual, return result; } +/* Instantiate a variable declaration from a TEMPLATE_ID_EXPR for use. */ + +tree +finish_template_variable (tree var) +{ + return instantiate_template (TREE_OPERAND (var, 0), TREE_OPERAND (var, 1), tf_error); +} + /* Finish a call to a postfix increment or decrement or EXPR. (Which is indicated by CODE, which should be POSTINCREMENT_EXPR or POSTDECREMENT_EXPR.) */ diff --git a/gcc/testsuite/g++.dg/template/var-templ1.C b/gcc/testsuite/g++.dg/template/var-templ1.C new file mode 100644 index 0000000..9219303 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/var-templ1.C @@ -0,0 +1,22 @@ +// { dg-do run } +// { dg-options "-std=c++1y" } + +template + struct S1 + { + static constexpr int a = A; + static constexpr int b = B; + }; + +template + constexpr int var = T::a + T::b; + +int main () +{ + int v = var>/2; + return !( + var> == v + && var> == var>>> + && var> != 222 + ); +} diff --git a/gcc/testsuite/g++.dg/template/var-templ2.C b/gcc/testsuite/g++.dg/template/var-templ2.C new file mode 100644 index 0000000..315ac3e --- /dev/null +++ b/gcc/testsuite/g++.dg/template/var-templ2.C @@ -0,0 +1,34 @@ +// { dg-do compile } +// { dg-options "-std=c++1y" } + +// Template variables and static member variables of template classes are +// often confused. + +template + struct S1 + { + static int n; + static int arr[]; + }; + +template + constexpr int var = sizeof (T); + +template + int S1::n = sizeof (T); + +template + int S1::arr[sizeof (T)]; + +template<> + int S1::n = 8; + +template<> + int S1::arr[8]; + +int main () +{ + S1 v1; + var>; + return 0; +} diff --git a/gcc/testsuite/g++.dg/template/var-templ3.C b/gcc/testsuite/g++.dg/template/var-templ3.C new file mode 100644 index 0000000..d3fbad4 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/var-templ3.C @@ -0,0 +1,19 @@ +// { dg-do run } +// { dg-options "-std=c++1y" } + +template + constexpr int var = sizeof (T); + +template + struct S1 + { + template + static constexpr int a = sizeof (U) + sizeof (T); + }; + +int main () +{ + return !( + var + var == S1::a + ); +} diff --git a/gcc/testsuite/g++.dg/template/var-templ4.C b/gcc/testsuite/g++.dg/template/var-templ4.C new file mode 100644 index 0000000..1d6cf1d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/var-templ4.C @@ -0,0 +1,16 @@ +// { dg-do run } +// { dg-options "-std=c++1y" } + +template + constexpr int var = sizeof (T); + +template<> + constexpr int var = 100000; + +int main () +{ + return !( + var == 100000 + && var == sizeof(char) + ); +} diff --git a/gcc/testsuite/g++.dg/template/var-templ5.C b/gcc/testsuite/g++.dg/template/var-templ5.C new file mode 100644 index 0000000..32d0ee1 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/var-templ5.C @@ -0,0 +1,23 @@ +// { dg-do run } +// { dg-options "-std=c++1y" } + +template + struct S1 + { + static constexpr int a = A; + static constexpr int b = B; + }; + +template + constexpr int var = T::a + T::b; + +template class T, int A> + constexpr int var2 = var> + A; + +int main () +{ + return !( + var2 == 120 + ); +} +