2016-04-15 07:47:07 +08:00
// RUN: %clang_cc1 -std=c++98 -verify -fsyntax-only %s -Wno-c++11-extensions -Wno-c++1y-extensions -DPRECXX11
2013-08-06 09:03:05 +08:00
// RUN: %clang_cc1 -std=c++11 -verify -fsyntax-only -Wno-c++1y-extensions %s
2016-02-22 10:24:29 +08:00
// RUN: %clang_cc1 -std=c++1y -verify -fsyntax-only %s -DCPP1Y
2013-08-06 09:03:05 +08:00
2013-08-22 08:59:14 +08:00
# define CONST const
2013-09-18 09:35:26 +08:00
# ifdef PRECXX11
# define static_assert(expr, msg) typedef int static_assert[(expr) ? 1 : -1];
# endif
2013-08-06 09:03:05 +08:00
class A {
2013-08-22 08:59:14 +08:00
template < typename T > CONST T wrong ; // expected-error {{member 'wrong' declared as a template}}
template < typename T > CONST T wrong_init = 5 ; // expected-error {{member 'wrong_init' declared as a template}}
template < typename T , typename T0 > static CONST T right = T ( 100 ) ;
template < typename T > static CONST T right < T , int > = 5 ;
template < typename T > CONST int right < int , T > ; // expected-error {{member 'right' declared as a template}}
template < typename T > CONST float right < float , T > = 5 ; // expected-error {{member 'right' declared as a template}}
2018-03-16 21:36:56 +08:00
template < > static CONST int right < int , int > = 7 ;
template < > static CONST float right < float , int > ;
2017-02-10 06:14:25 +08:00
template static CONST int right < int , int > ; // expected-error {{expected '<' after 'template'}}
2013-08-06 09:03:05 +08:00
} ;
namespace out_of_line {
class B0 {
2013-08-22 08:59:14 +08:00
template < typename T , typename T0 > static CONST T right = T ( 100 ) ;
template < typename T > static CONST T right < T , int > = T ( 5 ) ;
2013-08-06 09:03:05 +08:00
} ;
2016-09-01 07:23:25 +08:00
template < > CONST int B0 : : right < int , int > = 7 ; // expected-note {{previous}}
template CONST int B0 : : right < int , int > ; // expected-warning {{has no effect}}
template < > CONST int B0 : : right < int , float > ; // expected-note {{previous}}
template CONST int B0 : : right < int , float > ; // expected-warning {{has no effect}}
2013-08-06 09:03:05 +08:00
class B1 {
2013-08-22 08:59:14 +08:00
template < typename T , typename T0 > static CONST T right ;
template < typename T > static CONST T right < T , int > ;
2013-08-06 09:03:05 +08:00
} ;
2013-08-22 08:59:14 +08:00
template < typename T , typename T0 > CONST T B1 : : right = T ( 100 ) ;
template < typename T > CONST T B1 : : right < T , int > = T ( 5 ) ;
2013-08-06 09:03:05 +08:00
class B2 {
2013-11-21 11:17:44 +08:00
template < typename T , typename T0 > static CONST T right = T ( 100 ) ; // expected-note {{previous initialization is here}}
template < typename T > static CONST T right < T , int > = T ( 5 ) ; // expected-note {{previous initialization is here}}
2013-08-06 09:03:05 +08:00
} ;
2013-11-21 11:17:44 +08:00
template < typename T , typename T0 > CONST T B2 : : right = T ( 100 ) ; // expected-error {{static data member 'right' already has an initializer}}
template < typename T > CONST T B2 : : right < T , int > = T ( 5 ) ; // expected-error {{static data member 'right' already has an initializer}}
2013-08-06 09:03:05 +08:00
class B3 {
2013-08-22 08:59:14 +08:00
template < typename T , typename T0 > static CONST T right = T ( 100 ) ;
template < typename T > static CONST T right < T , int > = T ( 5 ) ;
2013-08-06 09:03:05 +08:00
} ;
2013-09-19 07:09:24 +08:00
template < typename T , typename T0 > CONST T B3 : : right ;
template < typename T > CONST T B3 : : right < T , int > ;
2013-08-06 09:03:05 +08:00
class B4 {
2013-09-28 04:14:12 +08:00
template < typename T , typename T0 > static CONST T a ;
template < typename T > static CONST T a < T , int > = T ( 100 ) ;
template < typename T , typename T0 > static CONST T b = T ( 100 ) ;
template < typename T > static CONST T b < T , int > ;
2013-08-06 09:03:05 +08:00
} ;
Move fixit for const init from note to diag, weaken to warning in MS mode.
r235046 turned "extern __declspec(selectany) int a;" from a declaration into
a definition to fix PR23242 (required for compatibility with mc.exe output).
However, this broke parsing Windows headers: A d3d11 headers contain something
like
struct SomeStruct {};
extern const __declspec(selectany) SomeStruct some_struct;
This is now a definition, and const objects either need an explicit default
ctor or an initializer so this errors out with
d3d11.h(1065,48) :
error: default initialization of an object of const type
'const CD3D11_DEFAULT' without a user-provided default constructor
(cl.exe just doesn't implement this rule, independent of selectany.)
To work around this, weaken this error into a warning for selectany decls
in microsoft mode, and recover with zero-initialization.
Doing this is a bit hairy since it adds a fixit on an error emitted
by InitializationSequence – this means it needs to build a correct AST, which
in turn means InitializationSequence::Failed() cannot return true when this
fixit is applied. As a workaround, the patch adds a fixit member to
InitializationSequence, and InitializationSequence::Perform() prints the
diagnostic if the fixit member is set right after its call to Diagnose.
That function is usually called when InitializationSequences are used –
InitListChecker::PerformEmptyInit() doesn't call it, but the InitListChecker
case never performs default-initialization, so this is technically OK.
This is the alternative, original fix for PR20208 that got reviewed in the
thread "[patch] Improve diagnostic on default-initializing const variables
(PR20208)". This change basically reverts r213725, adds the original fix for
PR20208, and makes the error a warning in Microsoft mode.
llvm-svn: 235166
2015-04-17 16:32:38 +08:00
template < typename T , typename T0 > CONST T B4 : : a ; // expected-error {{default initialization of an object of const type 'const int'}}
2013-09-28 04:14:12 +08:00
template < typename T > CONST T B4 : : a < T , int > ;
template CONST int B4 : : a < int , char > ; // expected-note {{in instantiation of}}
template CONST int B4 : : a < int , int > ;
template < typename T , typename T0 > CONST T B4 : : b ;
Move fixit for const init from note to diag, weaken to warning in MS mode.
r235046 turned "extern __declspec(selectany) int a;" from a declaration into
a definition to fix PR23242 (required for compatibility with mc.exe output).
However, this broke parsing Windows headers: A d3d11 headers contain something
like
struct SomeStruct {};
extern const __declspec(selectany) SomeStruct some_struct;
This is now a definition, and const objects either need an explicit default
ctor or an initializer so this errors out with
d3d11.h(1065,48) :
error: default initialization of an object of const type
'const CD3D11_DEFAULT' without a user-provided default constructor
(cl.exe just doesn't implement this rule, independent of selectany.)
To work around this, weaken this error into a warning for selectany decls
in microsoft mode, and recover with zero-initialization.
Doing this is a bit hairy since it adds a fixit on an error emitted
by InitializationSequence – this means it needs to build a correct AST, which
in turn means InitializationSequence::Failed() cannot return true when this
fixit is applied. As a workaround, the patch adds a fixit member to
InitializationSequence, and InitializationSequence::Perform() prints the
diagnostic if the fixit member is set right after its call to Diagnose.
That function is usually called when InitializationSequences are used –
InitListChecker::PerformEmptyInit() doesn't call it, but the InitListChecker
case never performs default-initialization, so this is technically OK.
This is the alternative, original fix for PR20208 that got reviewed in the
thread "[patch] Improve diagnostic on default-initializing const variables
(PR20208)". This change basically reverts r213725, adds the original fix for
PR20208, and makes the error a warning in Microsoft mode.
llvm-svn: 235166
2015-04-17 16:32:38 +08:00
template < typename T > CONST T B4 : : b < T , int > ; // expected-error {{default initialization of an object of const type 'const int'}}
2013-09-28 04:14:12 +08:00
template CONST int B4 : : b < int , char > ;
template CONST int B4 : : b < int , int > ; // expected-note {{in instantiation of}}
2013-08-06 09:03:05 +08:00
}
namespace non_const_init {
class A {
2013-09-28 04:14:12 +08:00
template < typename T > static T wrong_inst_undefined = T ( 10 ) ; // expected-note {{refers here}}
template < typename T > static T wrong_inst_defined = T ( 10 ) ; // expected-error {{non-const static data member must be initialized out of line}}
template < typename T > static T wrong_inst_out_of_line ;
2013-08-06 09:03:05 +08:00
} ;
2013-09-28 04:14:12 +08:00
template const int A : : wrong_inst_undefined < const int > ; // expected-error {{undefined}}
template < typename T > T A : : wrong_inst_defined ;
template const int A : : wrong_inst_defined < const int > ;
template int A : : wrong_inst_defined < int > ; // expected-note {{in instantiation of static data member 'non_const_init::A::wrong_inst_defined<int>' requested here}}
template < typename T > T A : : wrong_inst_out_of_line = T ( 10 ) ;
template int A : : wrong_inst_out_of_line < int > ;
2013-08-06 09:03:05 +08:00
class B {
2013-09-28 04:14:12 +08:00
template < typename T > static T wrong_inst ; // expected-note {{refers here}}
template < typename T > static T wrong_inst < T * > = T ( 100 ) ; // expected-error {{non-const static data member must be initialized out of line}} expected-note {{refers here}}
2013-08-06 09:03:05 +08:00
template < typename T > static T wrong_inst_fixed ;
template < typename T > static T wrong_inst_fixed < T * > ;
} ;
2013-09-28 04:14:12 +08:00
template int B : : wrong_inst < int > ; // expected-error {{undefined}}
// FIXME: It'd be better to produce the 'explicit instantiation of undefined
// template' diagnostic here, not the 'must be initialized out of line'
// diagnostic.
template int B : : wrong_inst < int * > ; // expected-note {{in instantiation of static data member 'non_const_init::B::wrong_inst<int *>' requested here}}
template const int B : : wrong_inst < const int * > ; // expected-error {{undefined}}
2013-08-06 09:03:05 +08:00
template < typename T > T B : : wrong_inst_fixed = T ( 100 ) ;
template int B : : wrong_inst_fixed < int > ;
2013-09-28 04:14:12 +08:00
2013-08-06 09:03:05 +08:00
class C {
2013-09-28 04:14:12 +08:00
template < typename T > static CONST T right_inst = T ( 10 ) ; // expected-note {{here}}
template < typename T > static CONST T right_inst < T * > = T ( 100 ) ; // expected-note {{here}}
2013-08-06 09:03:05 +08:00
} ;
2013-09-28 04:14:12 +08:00
template CONST int C : : right_inst < int > ; // expected-error {{undefined variable template}}
template CONST int C : : right_inst < int * > ; // expected-error {{undefined variable template}}
2013-08-06 09:03:05 +08:00
namespace pointers {
2013-09-28 04:14:12 +08:00
2013-08-06 09:03:05 +08:00
struct C0 {
template < typename U > static U Data ;
2013-09-28 04:14:12 +08:00
template < typename U > static CONST U Data < U * > = U ( ) ; // expected-note {{here}}
template < typename U > static U Data2 ;
template < typename U > static CONST U Data2 < U * > = U ( ) ;
2013-08-06 09:03:05 +08:00
} ;
2013-09-28 04:14:12 +08:00
const int c0_test = C0 : : Data < int * > ;
static_assert ( c0_test = = 0 , " " ) ;
template const int C0 : : Data < int * > ; // expected-error {{undefined}}
template < typename U > const U C0 : : Data2 < U * > ;
template const int C0 : : Data2 < int * > ;
2013-08-06 09:03:05 +08:00
struct C1a {
template < typename U > static U Data ;
2013-09-24 12:49:23 +08:00
template < typename U > static U * Data < U * > ; // Okay, with out-of-line definition
2013-08-06 09:03:05 +08:00
} ;
2013-09-24 12:49:23 +08:00
template < typename T > T * C1a : : Data < T * > = new T ( ) ;
template int * C1a : : Data < int * > ;
2013-09-28 04:14:12 +08:00
2013-08-06 09:03:05 +08:00
struct C1b {
template < typename U > static U Data ;
2013-09-24 12:49:23 +08:00
template < typename U > static CONST U * Data < U * > ; // Okay, with out-of-line definition
2013-08-06 09:03:05 +08:00
} ;
2013-09-24 12:49:23 +08:00
template < typename T > CONST T * C1b : : Data < T * > = ( T * ) ( 0 ) ;
template CONST int * C1b : : Data < int * > ;
2013-08-06 09:03:05 +08:00
struct C2a {
2013-09-24 12:49:23 +08:00
template < typename U > static int Data ;
template < typename U > static U * Data < U * > = new U ( ) ; // expected-error {{non-const static data member must be initialized out of line}}
2013-08-06 09:03:05 +08:00
} ;
2013-09-24 12:49:23 +08:00
template int * C2a : : Data < int * > ; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
2013-09-28 04:14:12 +08:00
struct C2b {
2013-09-24 12:49:23 +08:00
template < typename U > static int Data ;
2013-09-28 04:14:12 +08:00
template < typename U > static U * const Data < U * > = ( U * ) ( 0 ) ; // expected-error {{static data member of type 'int *const'}}
2013-08-06 09:03:05 +08:00
} ;
2013-09-28 04:14:12 +08:00
template < typename U > U * const C2b : : Data < U * > ;
template int * const C2b : : Data < int * > ; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
2013-08-06 09:03:05 +08:00
}
}
2013-08-22 09:05:27 +08:00
# ifndef PRECXX11
namespace constexpred {
class A {
template < typename T > constexpr T wrong ; / / expected - error { { member ' wrong ' declared as a template } } \
// expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
template < typename T > constexpr T wrong_init = 5 ; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
template < typename T , typename T0 > static constexpr T right = T ( 100 ) ;
template < typename T > static constexpr T right < T , int > = 5 ;
template < typename T > constexpr int right < int , T > ; / / expected - error { { member ' right ' declared as a template } } \
// expected-error {{non-static data member cannot be constexpr; did you intend to make it const?}}
template < typename T > constexpr float right < float , T > = 5 ; // expected-error {{non-static data member cannot be constexpr; did you intend to make it static?}}
2018-03-16 21:36:56 +08:00
template < > static constexpr int right < int , int > = 7 ;
template < > static constexpr float right < float , int > ; // expected-error {{requires an initializer}}
2017-02-10 06:14:25 +08:00
template static constexpr int right < int , int > ; // expected-error {{expected '<' after 'template'}}
2013-08-22 09:05:27 +08:00
} ;
}
# endif
2013-08-06 09:03:05 +08:00
namespace in_class_template {
template < typename T >
class D0 {
2013-09-28 04:14:12 +08:00
template < typename U > static U Data ; // expected-note {{here}}
2013-08-22 08:59:14 +08:00
template < typename U > static CONST U Data < U * > = U ( ) ;
2013-08-06 09:03:05 +08:00
} ;
2013-08-22 08:59:14 +08:00
template CONST int D0 < float > : : Data < int * > ;
2013-09-28 04:14:12 +08:00
template int D0 < float > : : Data < int > ; // expected-error {{undefined}}
template < typename T > template < typename U > const U D0 < T > : : Data < U * > ;
2013-08-06 09:03:05 +08:00
template < typename T >
class D1 {
template < typename U > static U Data ;
template < typename U > static U * Data < U * > ;
} ;
template < typename T >
template < typename U > U * D1 < T > : : Data < U * > = ( U * ) ( 0 ) ;
2013-09-28 04:14:12 +08:00
template int * D1 < float > : : Data < int * > ; // expected-note {{previous}}
template int * D1 < float > : : Data < int * > ; // expected-error {{duplicate explicit instantiation}}
2013-08-22 08:28:27 +08:00
template < typename T >
class D2 {
template < typename U > static U Data ;
template < typename U > static U * Data < U * > ;
} ;
template < >
template < typename U > U * D2 < float > : : Data < U * > = ( U * ) ( 0 ) + 1 ;
2013-09-28 04:14:12 +08:00
template int * D2 < float > : : Data < int * > ; // expected-note {{previous}}
template int * D2 < float > : : Data < int * > ; // expected-error {{duplicate explicit instantiation}}
2013-08-22 08:59:14 +08:00
2013-08-22 08:28:27 +08:00
template < typename T >
struct D3 {
2013-09-28 04:14:12 +08:00
template < typename U > static CONST U Data = U ( 100 ) ; // expected-note {{here}}
2013-08-22 08:28:27 +08:00
} ;
static_assert ( D3 < float > : : Data < int > = = 100 , " " ) ;
2013-09-28 04:14:12 +08:00
template const char D3 < float > : : Data < char > ; // expected-error {{undefined}}
2013-08-06 09:03:05 +08:00
2013-08-22 08:28:27 +08:00
namespace bug_files {
template < typename T >
2013-09-28 04:14:12 +08:00
class D0a {
2013-08-22 08:28:27 +08:00
template < typename U > static U Data ;
2015-07-15 04:08:49 +08:00
template < typename U > static CONST U Data < U * > = U ( 10 ) ; // expected-note {{previous declaration is here}}
2013-08-22 08:28:27 +08:00
} ;
template < >
2013-09-28 04:14:12 +08:00
template < typename U > U D0a < float > : : Data < U * > = U ( 100 ) ; // expected-error {{redefinition of 'Data'}}
2013-08-22 08:28:27 +08:00
2013-09-28 04:14:12 +08:00
// FIXME: We should accept this, and the corresponding case for class
// templates.
//
// [temp.class.spec.mfunc]/2: If the primary member template is explicitly
// specialized for a given specialization of the enclosing class template,
// the partial specializations of the member template are ignored
2013-08-22 08:28:27 +08:00
template < typename T >
class D1 {
template < typename U > static U Data ;
2015-07-15 04:08:49 +08:00
template < typename U > static CONST U Data < U * > = U ( 10 ) ; // expected-note {{previous declaration is here}}
2013-09-28 04:14:12 +08:00
} ;
2013-08-22 08:28:27 +08:00
template < >
2013-09-28 04:14:12 +08:00
template < typename U > U D1 < float > : : Data = U ( 10 ) ;
template < >
template < typename U > U D1 < float > : : Data < U * > = U ( 100 ) ; // expected-error{{redefinition of 'Data'}}
2013-08-22 08:28:27 +08:00
}
2013-09-24 12:49:23 +08:00
2013-09-28 04:14:12 +08:00
namespace definition_after_outer_instantiation {
template < typename A > struct S {
template < typename B > static const int V1 ;
template < typename B > static const int V2 ;
2013-08-22 08:28:27 +08:00
} ;
template struct S < int > ;
2013-09-28 04:14:12 +08:00
template < typename A > template < typename B > const int S < A > : : V1 = 123 ;
template < typename A > template < typename B > const int S < A > : : V2 < B * > = 456 ;
static_assert ( S < int > : : V1 < int > = = 123 , " " ) ;
// FIXME: The first and third case below possibly should be accepted. We're
// not picking up partial specializations added after the primary template
// is instantiated. This is kind of implied by [temp.class.spec.mfunc]/2,
// and matches our behavior for member class templates, but it's not clear
// that this is intentional. See PR17294 and core-24030.
static_assert ( S < int > : : V2 < int * > = = 456 , " " ) ; // FIXME expected-error {{}}
static_assert ( S < int > : : V2 < int & > = = 789 , " " ) ; // expected-error {{}}
template < typename A > template < typename B > const int S < A > : : V2 < B & > = 789 ;
static_assert ( S < int > : : V2 < int & > = = 789 , " " ) ; // FIXME expected-error {{}}
// All is OK if the partial specialization is declared before the implicit
// instantiation of the class template specialization.
static_assert ( S < char > : : V1 < int > = = 123 , " " ) ;
static_assert ( S < char > : : V2 < int * > = = 456 , " " ) ;
static_assert ( S < char > : : V2 < int & > = = 789 , " " ) ;
2013-08-06 09:03:05 +08:00
}
2013-09-18 09:35:26 +08:00
namespace incomplete_array {
template < typename T > extern T var [ ] ;
template < typename T > T var [ ] = { 1 , 2 , 3 } ;
template < > char var < char > [ ] = " hello " ;
template < typename T > char var < T * > [ ] = " pointer " ;
static_assert ( sizeof ( var < int > ) = = 12 , " " ) ;
static_assert ( sizeof ( var < char > ) = = 6 , " " ) ;
static_assert ( sizeof ( var < void * > ) = = 8 , " " ) ;
template < typename . . . > struct tuple ;
template < typename T > struct A {
template < typename U > static T x [ ] ;
template < typename U > static T y [ ] ;
template < typename . . . U > static T y < tuple < U . . . > > [ ] ;
} ;
int * use_before_definition = A < int > : : x < char > ;
2013-09-24 12:49:23 +08:00
template < typename T > template < typename U > T A < T > : : x [ sizeof ( U ) ] ;
2013-09-28 04:14:12 +08:00
static_assert ( sizeof ( A < int > : : x < char > ) = = 4 , " " ) ;
2013-09-18 09:35:26 +08:00
template < typename T > template < typename . . . U > T A < T > : : y < tuple < U . . . > > [ ] = { U ( ) . . . } ;
2013-09-28 04:14:12 +08:00
static_assert ( sizeof ( A < int > : : y < tuple < char , char , char > > ) = = 12 , " " ) ;
2013-09-18 09:35:26 +08:00
}
2013-12-04 08:56:29 +08:00
namespace bad_reference {
struct S {
template < typename T > static int A ; // expected-note 4{{here}}
} ;
template < typename T > void f ( ) {
2018-05-11 10:43:08 +08:00
typename T : : template A < int > a ; // expected-error {{template name refers to non-type template 'S::template A'}}
2013-12-04 08:56:29 +08:00
}
template < typename T > void g ( ) {
2018-05-11 10:43:08 +08:00
T : : template A < int > : : B = 0 ; // expected-error {{template name refers to non-type template 'S::template A'}}
2013-12-04 08:56:29 +08:00
}
template < typename T > void h ( ) {
2018-05-11 10:43:08 +08:00
class T : : template A < int > c ; // expected-error {{template name refers to non-type template 'S::template A'}}
2013-12-04 08:56:29 +08:00
}
template < typename T >
2018-05-11 10:43:08 +08:00
struct X : T : : template A < int > { } ; // expected-error {{template name refers to non-type template 'S::template A'}}
2013-12-04 08:56:29 +08:00
template void f < S > ( ) ; // expected-note {{in instantiation of}}
template void g < S > ( ) ; // expected-note {{in instantiation of}}
template void h < S > ( ) ; // expected-note {{in instantiation of}}
template struct X < S > ; // expected-note {{in instantiation of}}
}
2013-08-06 09:03:05 +08:00
}
namespace in_nested_classes {
// TODO:
}
2014-12-29 06:51:45 +08:00
namespace bitfield {
struct S {
template < int I >
static int f : I ; // expected-error {{static member 'f' cannot be a bit-field}}
} ;
}
2015-08-11 05:54:08 +08:00
namespace b20896909 {
// This used to crash.
template < typename T > struct helper { } ;
template < typename T > class A {
template < typename > static helper < typename T : : error > x ; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
} ;
void test ( ) {
A < int > ai ; // expected-note {{in instantiation of}}
}
}
2016-02-22 10:24:29 +08:00
namespace member_access_is_ok {
# ifdef CPP1Y
namespace ns1 {
struct A {
template < class T , T N > constexpr static T Var = N ;
} ;
static_assert ( A { } . Var < int , 5 > = = 5 , " " ) ;
} // end ns1
# endif // CPP1Y
namespace ns2 {
template < class T > struct A {
template < class U , T N , U M > static T & & Var ;
} ;
template < class T > template < class U , T N , U M > T & & A < T > : : Var = T ( N + M ) ;
int * AV = & A < int > ( ) . Var < char , 5 , ' A ' > ;
} //end ns2
} // end ns member_access_is_ok
# ifdef CPP1Y
namespace PR24473 {
struct Value
{
template < class T >
static constexpr T value = 0 ;
} ;
template < typename TValue >
struct Something
{
void foo ( ) {
static_assert ( TValue : : template value < int > = = 0 , " " ) ; // error
}
} ;
int main ( ) {
Something < Value > { } . foo ( ) ;
return 0 ;
}
} // end ns PR24473
# endif // CPP1Y
2018-04-26 10:10:22 +08:00
namespace dependent_static_var_template {
struct A {
2018-04-27 10:00:13 +08:00
template < int = 0 > static int n ; // expected-note 2{{here}}
2018-04-26 10:10:22 +08:00
} ;
2018-04-27 10:00:13 +08:00
int & r = A : : template n ; // expected-error {{use of variable template 'n' requires template arguments}}
2018-04-26 10:10:22 +08:00
template < typename T >
int & f ( ) { return T : : template n ; } // expected-error {{use of variable template 'n' requires template arguments}}
int & s = f < A > ( ) ; // expected-note {{instantiation of}}
namespace B {
2018-04-27 10:00:13 +08:00
template < int = 0 > static int n ; // expected-note {{here}}
2018-04-26 10:10:22 +08:00
}
2018-04-27 10:00:13 +08:00
int & t = B : : template n ; // expected-error {{use of variable template 'n' requires template arguments}}
2018-04-26 10:10:22 +08:00
}