}
}
+/* Perform type checking in explicit instantiation of variable templates
+ as per CWG 1704. That is, detect
+ template<typename T> T var = {};
+ template int *var<int>;
+ where there's a mismatch 'int' x 'int *'. INST is the instantiation
+ of the variable template, DECL is the VAR_DECL from the template-id
+ used in the explicit instantiation. */
+
+static bool
+check_explicit_inst_of_var_template (tree inst, tree decl)
+{
+ if (!inst || inst == error_mark_node)
+ return true;
+
+ tree type1 = TREE_TYPE (inst);
+ tree type2 = TREE_TYPE (decl);
+
+ /* Redeclaration with type auto is OK. */
+ if (is_auto (type1) || is_auto (type2))
+ return true;
+
+ /* Absence of major array bound is permitted. */
+ if (TREE_CODE (type1) == ARRAY_TYPE
+ && TREE_CODE (type2) == ARRAY_TYPE
+ && (!TYPE_DOMAIN (type1) || !TYPE_DOMAIN (type2)))
+ {
+ type1 = TREE_TYPE (type1);
+ type2 = TREE_TYPE (type2);
+ }
+
+ if (same_type_p (type1, type2))
+ /* All good. */
+ return true;
+
+ error ("type %qT for explicit instantiation %qD does not match declared "
+ "type %qT", type2, decl, type1);
+ inform (DECL_SOURCE_LOCATION (inst), "variable template declared here");
+ return false;
+}
+
/* Check to see if the function just declared, as indicated in
DECLARATOR, and in DECL, is a specialization of a function
template. We may also discover that the declaration is an explicit
targs = new_targs;
}
- return instantiate_template (tmpl, targs, tf_error);
+ tree inst = instantiate_template (tmpl, targs, tf_error);
+ if (variable_template_p (tmpl)
+ && !check_explicit_inst_of_var_template (inst, decl))
+ return error_mark_node;
+ return inst;
}
/* If we thought that the DECL was a member function, but it
--- /dev/null
+// PR c++/125575
+// { dg-do compile { target c++14 } }
+
+template<typename T>
+constexpr T v1 = 42;
+template const int v1<int>;
+
+template<typename T>
+constexpr T v2 = 42;
+template int v2<int>; // { dg-error "type .int. for explicit instantiation .v2. does not match declared type .const int." }
+
+template<typename T>
+constexpr T v3 = 42;
+template int *v3<int>; // { dg-error "type .int\\*. for explicit instantiation .v3. does not match declared type .const int." }
+
+template<typename T>
+constexpr const T *const *v4 = nullptr;
+template int *const *v4<int>; // { dg-error "type .int\\* const\\*. for explicit instantiation .v4. does not match declared type .const int\\* const\\* const." }
+
+template<typename T>
+constexpr T v5 = 42;
+template float v5<int>; // { dg-error "type .float. for explicit instantiation .v5. does not match declared type .const int." }
+
+template<typename T>
+T v6 = 42;
+template volatile int v6<int>; // { dg-error "type .volatile int. for explicit instantiation .v6. does not match declared type .int." }
+
+template<typename>
+constexpr auto v7 = 42;
+template int v7<int>; // { dg-error "type .int. for explicit instantiation .v7. does not match declared type .const int." }
+
+template<typename>
+auto v8 = 42;
+template const int v8<int>; // { dg-error "type .const int. for explicit instantiation .v8. does not match declared type .int." }
+
+template<typename T>
+T v9{};
+template int v9<int[10]>[5]; // { dg-error "type .int \\\[5\\\]. for explicit instantiation .v9. does not match declared type .int \\\[10\\\]." }
+
+template<typename T>
+T v10{};
+template int v10<int[10]>[10];
+
+template<typename T>
+T v11{};
+template int v11<int[10][10]>[10][10];
+
+template<typename T>
+T v12{};
+template int v12<int[10][10]>[][10];
+
+template<typename T> int arr[sizeof(T)] = {};
+template int arr<int>[];
--- /dev/null
+// PR c++/125575
+// CWG 1704, Type checking in explicit instantiation of variable templates
+// { dg-do compile { target c++14 } }
+// Test from [temp.explicit].
+
+template<typename T> T var = {};
+template float var<float>; // OK, instantiated variable has type float
+template int var<int[16]>[]; // OK, absence of major array bound is permitted
+template int *var<int>; // error: instantiated variable has type int
+// { dg-error "type .int\\*. for explicit instantiation .var. does not match declared type .int." "" { target *-*-* } .-1 }
+
+template<typename T> auto av = T();
+template int av<int>; // OK, variable with type auto can be redeclared with type int
+
+template<typename T> auto f() {}
+template void f<int>(); // error: function with deduced return type
+ // redeclared with non-deduced return type ([dcl.spec.auto])
+// { dg-error "does not match any template declaration" "" { target *-*-* } .-2 }
--- /dev/null
+// PR c++/98524
+// { dg-do compile { target c++14 } }
+
+template<typename T> void (*f1)();
+template void (*f1<int>)(int); // { dg-error "type .void \\(\\*\\)\\(int\\). for explicit instantiation .f1. does not match declared type .void \\(\\*\\)\\(\\)." }
+
+template<typename T> void (*f2)(int) noexcept;
+template void (*f2<int>)(int); // { dg-error "type .void \\(\\*\\)\\(int\\). for explicit instantiation .f2. does not match declared type .void \\(\\*\\)\\(int\\) noexcept." "" { target c++17 } }
+
+template<typename T> void (*f3)(int) ;
+template void (*f3<int>)(int) noexcept; // { dg-error "type .void \\(\\*\\)\\(int\\) noexcept. for explicit instantiation .f3. does not match declared type .void \\(\\*\\)\\(int\\)." "" { target c++17 } }
+
+template<typename T> void (*f4)(int) noexcept;
+template void (*f4<int>)(int) noexcept;
+
+template<typename T> void (*f5)(int);
+template void (*f5<int>)(int);
+
+template<typename T> void (*f6)(int);
+template int (*f6<int>)(int); // { dg-error "type .int \\(\\*\\)\\(int\\). for explicit instantiation .f6. does not match declared type .void \\(\\*\\)\\(int\\)." }
--- /dev/null
+// PR c++/125575
+// CWG 1728, Type of an explicit instantiation of a variable template
+// { dg-do compile { target c++14 } }
+
+template<typename T> T var = T();
+template float var<float>;
+template int* var<int>; // { dg-error "type .int\\*. for explicit instantiation .var. does not match declared type .int." }
+template auto var<char>; // { dg-error "has no initializer" }