In this testcase, the problem is that const variables are implicitly
static, and static variables get DECL_INTERFACE_KNOWN set. Then when
instantiating the variable we set DECL_EXTERNAL, with the effect that we
are saying that we know that we aren't defining the variable in the
current translation unit. We ought to set DECL_NOT_REALLY_EXTERN at the
same time, as we do various other places.
Tested x86_64-pc-linux-gnu, applying to trunk and 5.
commit ce66414682d1e895700ae8cc96bad49d876db23a
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Jun 12 11:41:24 2015 -0400
PR c++/65719
* pt.c (tsubst_decl) [VAR_DECL]: Mark namespace-scope
variables as DECL_NOT_REALLY_EXTERN.
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7f04fe6..ea8c8b6 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -11306,8 +11306,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
{
/* T is a static data member or namespace-scope entity.
We have to substitute into namespace-scope variables
- (even though such entities are never templates) because
- of cases like:
+ (not just variable templates) because of cases like:
template <class T> void f() { extern T t; }
@@ -11468,6 +11467,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
initializer is present. We mimic the non-template
processing here. */
DECL_EXTERNAL (r) = 1;
+ if (DECL_NAMESPACE_SCOPE_P (t))
+ DECL_NOT_REALLY_EXTERN (r) = 1;
DECL_TEMPLATE_INFO (r) = build_template_info (tmpl, argvec);
SET_DECL_IMPLICIT_INSTANTIATION (r);
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ29.C b/gcc/testsuite/g++.dg/cpp1y/var-templ29.C
new file mode 100644
index 0000000..22f5b0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ29.C
@@ -0,0 +1,13 @@
+// PR c++/65719
+// { dg-do link { target c++14 } }
+
+struct FunctionObject {
+ void operator()() const { }
+};
+
+template <typename T>
+constexpr FunctionObject f{};
+
+int main() {
+ f<int>();
+}