From patchwork Sun Jul 13 04:06:56 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Braden Obrzut X-Patchwork-Id: 369380 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 69702140097 for ; Sun, 13 Jul 2014 14:07:20 +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:content-type; q=dns; s=default; b=FIj1lTJ48X/tHMr29cgw5cBnghdUjCYHNtkftfjc66f WpdIUao3VVnrLW1ZrAoYE+LPVDsga4MY1MlqCRE9AZMJtzPtFbMhQAFo4Ac8l3+r 4QBw9g+ESrk6xBVDB5xqXQaMUlvzZDYCLcE1R++4q5VQ0GHWZ4/K9dpE7otv6EKs = 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:content-type; s=default; bh=Apb5GYYmbE/A9Kl5+hBPcoxRogY=; b=tPNt9RjJzUDBAKI8S okD3wX4XTrzDYA+kgWRqgXYmtAiLUXxbm7yKXLGj9twdRyiBO616hr4Nh/9aYC2v HiXMb1M+YjQoTBMiQZyQLOGNcuAfJXkgy5inSXmrU/ZA9cOdDEYvqLCVXMQDsJVt +eG+UWGAYr5VgCbw3Buu5iLQU0= Received: (qmail 27047 invoked by alias); 13 Jul 2014 04:07:11 -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 27010 invoked by uid 89); 13 Jul 2014 04:07:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.2 X-HELO: mail-pd0-f172.google.com Received: from mail-pd0-f172.google.com (HELO mail-pd0-f172.google.com) (209.85.192.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Sun, 13 Jul 2014 04:07:01 +0000 Received: by mail-pd0-f172.google.com with SMTP id w10so3465344pde.31 for ; Sat, 12 Jul 2014 21:06:59 -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:content-type; bh=UCebsW6xN2j+7ZYvnSYIETJme4JWZR/amWJ83OgDA7o=; b=WjB84r1TCppj2VKhxHqLLiWtKbpbD11C4UgeJm+7BiHhtgnwbgTpOBUqoCW1tIDSm5 haah/N4cojdsq2opLkO3vBD5E1rUQiLCHZsf+dj7ExX9FOwR3p0w0Pgtntu8Xc1/okgc 1v1FwmAYhUTnpiR5YzfSh6VBGoZRVrX7n7ula4+TB+LOJkxqiC9YFmL3mM5t8KGSpsd0 CAyTw1AsO3oqbdkVFXnhLQz4aC+K358wKCSxa/KJEkzgOVXKNYnRZm7fSzK+jDuXO0XZ /Y/0+m/eQYm4x7B+igQiusvJbpcH510pdVcPsDSFFTsuhFkrx2XFHBVBe9Fc0lyres4h Y5Cg== X-Gm-Message-State: ALoCoQnMUHz/octww7E7PD3nLobHcQl2wS9RrL/IocjLjy8yxSaNg9En7OTOosg0sPDAo5gtH1UN X-Received: by 10.66.136.131 with SMTP id qa3mr8474063pab.77.1405224419633; Sat, 12 Jul 2014 21:06:59 -0700 (PDT) Received: from [192.168.1.7] (ip68-110-178-44.cl.ri.cox.net. [68.110.178.44]) by mx.google.com with ESMTPSA id fu12sm28572819pad.42.2014.07.12.21.06.57 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Sat, 12 Jul 2014 21:06:58 -0700 (PDT) Message-ID: <53C205E0.6070907@maniacsvault.net> Date: Sun, 13 Jul 2014 00:06:56 -0400 From: Braden Obrzut User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.5.0 MIME-Version: 1.0 To: gcc-patches@gcc.gnu.org CC: andrew.n.sutton@gmail.com Subject: Patch for constexpr variable templates Here is a patch that expands on Gabriel Dos Reis's initial var-template patch ( https://gcc.gnu.org/ml/gcc-patches/2013-03/msg01295.html ). I just noticed now that those patches were committed to a branch, so if need be I can resubmit the patch with Gaby's changes not included. The purpose of the patch is to implement the subset of variable templates that is a prerequisite for concept variables in the c++-concepts branch. With that said, only constexpr variables are supported (both in namespace and class scopes). There is no handling for generating symbols for these variables so they are only supported in contexts where they can be evaluated at compile time (I believe that would be only as an rvalue). On that note, explicit instantiations of variable templates do work, but will generate duplicate symbol errors if more than one exists in the file. Other than those issues, the should work as expected. I would like to call attention to the changes in parser.c. Andrew pointed out to me that it may be a good idea to have cp_parser_template_id return the instantiated VAR_DECL directly instead of deferring it to cp_parser_postfix_expression like function templates. Since this would produce a new possible return type for the function, I've found that would require more widespread changes (although I can't accurately say by how much). By deferring the instantiation, some code can be shared between function templates and variable templates. 2014-07-12 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. (instantiate_template_1): Evaluate initializer for variable templates. (do_decl_instantiation): Handle templat variables. (instantiate_decl): Handle template variables. * semantics.c (finish_template_variable): New. 2014-07-12 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. 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..62cc256 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..1744375 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 { @@ -15692,6 +15723,19 @@ instantiate_template_1 (tree tmpl, tree orig_args, tsubst_flags_t complain) template, not the most general template. */ DECL_TI_TEMPLATE (fndecl) = tmpl; + // For variable templates we need to check out the initializer + if (VAR_P (fndecl)) + { + tree init = tsubst_expr ( + DECL_INITIAL (DECL_TEMPLATE_RESULT (gen_tmpl)), + targ_ptr, complain, gen_tmpl, true); + + // Evaluate the initializer and store it. + vec *cleanups = NULL; + store_init_value (fndecl, init, &cleanups, LOOKUP_ALREADY_DIGESTED); + gcc_assert (!cleanups); + } + /* Now we know the specialization, compute access previously deferred. */ push_access_scope (fndecl); @@ -19146,7 +19190,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 +19223,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 +19933,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 +19950,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 +20047,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) + ); +}