mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 21:21:48 +03:00

* Document template instance duplication status as part of its field documentation. (#16643) * Fix Bugzilla 24599 - Wrongly elided TypeInfo emission (#15868) Reverting #14844, which caused such missing TypeInfos, *and* making sure the special TypeInfo members are fully analyzed and ready for codegen (otherwise hitting an assertion for the real-world project). * Reorganize backend build files to match target and make more similar per line (#16672) * Remove redundant suggestions on linker errors (#16711) * Fix bugzilla 24337 - Segfault when printing an int[] cast from a string (#16729) * Add BitFieldStyle.Gcc_Clang_ARM Required for 32-bit ARM, and non-Apple 64-bit ARM targets. The only difference to `Gcc_Clang` is that anonymous and 0-length bit-fields do contribute to the aggregate alignment. Caught by existing proper C interop tests in runnable_cxx/testbitfields.d on such targets. The hardcoded bad tests in runnable/{bitfieldsposix64.c,dbitfieldsposix64.d} however now fail after the fix, on such targets again. * [refactor to `TargetC.contributesToAggregateAlignment(BitFieldDeclaration)` hook] * Fix Bugzilla Issue 24687 - [REG2.110] Cannot cast string-imports to select overload anymore * Also make deprecationSupplemental adhere to error limit (#16779) Co-authored-by: Dennis Korpel <dennis@sarc.nl> * Fix bugzilla 24699 - [REG2.108] No short-circuit evaluation of mixing template bool argument * Fix bugzilla 24731 - IFTI cannot handle integer expressions (#16822) * Fix Bugzilla Issue 24760 - ICE on variadic after default argument * Fix bugzilla 24790 - -vcg-ast ICE on lowered assign exp (#16914) Co-authored-by: Dennis Korpel <dennis@sarc.nl> * Fix bugzilla 24764 - ICE when -vcg-ast prints imported invariant (#16917) Co-authored-by: Dennis Korpel <dennis@sarc.nl> * Fix bugzilla 24431 - dmd -vcg-ast crashes printing failed template in… (#16916) --------- Co-authored-by: Richard (Rikki) Andrew Cattermole <richard@cattermole.co.nz> Co-authored-by: Martin Kinkelin <kinke@users.noreply.github.com> Co-authored-by: Dennis <dkorpel@users.noreply.github.com> Co-authored-by: Martin Kinkelin <mkinkelin@symmetryinvestments.com> Co-authored-by: Martin Kinkelin <noone@nowhere.com> Co-authored-by: RazvanN7 <razvan.nitu1305@gmail.com> Co-authored-by: Dennis Korpel <dennis@sarc.nl> Co-authored-by: Dennis Korpel <dkorpel@gmail.com>
880 lines
18 KiB
D
880 lines
18 KiB
D
// REQUIRED_ARGS: -o-
|
|
// EXTRA_FILES: imports/imp12242a1.d imports/imp12242a2.d
|
|
// PERMUTE_ARGS:
|
|
/*
|
|
TEST_OUTPUT:
|
|
---
|
|
9
|
|
8
|
|
7
|
|
6
|
|
5
|
|
4
|
|
3
|
|
2
|
|
1
|
|
0
|
|
S(1, 2, 3, [0, 1, 2])
|
|
x0: 1
|
|
x1: 2
|
|
x2: 3
|
|
a: [0, 1, 2]
|
|
(int[], char[], bool[], Object[])
|
|
[0, 0]
|
|
x0: int
|
|
x1: double
|
|
x2: char
|
|
test(0)→ 0
|
|
test(1)→ 1
|
|
test(2)→ 2
|
|
test(3)→ 3
|
|
test(4)→ 4
|
|
test(5)→ 5
|
|
test(6)→ 6
|
|
test(7)→ 7
|
|
test(8)→ 8
|
|
test(9)→ 9
|
|
test(10)→ -1
|
|
test(11)→ -1
|
|
test(12)→ -1
|
|
test(13)→ -1
|
|
test(14)→ -1
|
|
1
|
|
[1, 2, 3]
|
|
2
|
|
[1, 2, 3]
|
|
3
|
|
[1, 2, 3]
|
|
0 1
|
|
1 2
|
|
2 3
|
|
1
|
|
3
|
|
4
|
|
object
|
|
Tuple
|
|
tuple
|
|
main
|
|
front
|
|
popFront
|
|
empty
|
|
back
|
|
popBack
|
|
Iota
|
|
iota
|
|
map
|
|
to
|
|
text
|
|
all
|
|
any
|
|
join
|
|
S
|
|
s
|
|
Seq
|
|
Overloads
|
|
Parameters
|
|
forward
|
|
foo
|
|
A
|
|
B
|
|
C
|
|
D
|
|
E
|
|
Types
|
|
Visitor
|
|
testVisitor
|
|
staticMap
|
|
arrayOf
|
|
StaticForeachLoopVariable
|
|
StaticForeachScopeExit
|
|
StaticForeachReverseHiding
|
|
UnrolledForeachReverse
|
|
StaticForeachReverse
|
|
StaticForeachByAliasDefault
|
|
NestedStaticForeach
|
|
TestAliasOutsideFunctionScope
|
|
OpApplyMultipleStaticForeach
|
|
OpApplyMultipleStaticForeachLowered
|
|
RangeStaticForeach
|
|
OpApplySingleStaticForeach
|
|
TypeStaticForeach
|
|
AliasForeach
|
|
EnumForeach
|
|
TestUninterpretable
|
|
SeqForeachConstant
|
|
SeqForeachBreakContinue
|
|
TestStaticForeach
|
|
testtest
|
|
fun
|
|
testEmpty
|
|
bug17660
|
|
breakContinueBan
|
|
MixinTemplate
|
|
testToStatement
|
|
bug17688
|
|
T
|
|
foo2
|
|
T2
|
|
TestStaticForeach2
|
|
issue22007
|
|
1 2 3
|
|
2 3 4
|
|
0 1
|
|
1 2
|
|
2 3
|
|
---
|
|
*/
|
|
|
|
module staticforeach;
|
|
|
|
struct Tuple(T...){
|
|
T expand;
|
|
alias expand this;
|
|
}
|
|
auto tuple(T...)(T t){ return Tuple!T(t); }
|
|
|
|
/+struct TupleStaticForeach{ // should work, but is not the fault of the static foreach implementation.
|
|
//pragma(msg, [tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x));
|
|
static foreach(a,b,c;[tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x)){
|
|
pragma(msg,a," ",b," ",c);
|
|
}
|
|
}+/
|
|
|
|
void main(){
|
|
static foreach(a,b,c;[tuple(1,"2",'3'),tuple(2,"3",'4')].map!((x)=>x)){
|
|
pragma(msg, a," ",b," ",c);
|
|
}
|
|
static struct S{
|
|
// (aggregate scope, forward referencing possible)
|
|
static assert(stripA("123")==1);
|
|
static assert(stripA([1],2)==2);
|
|
static foreach(i;0..2){
|
|
mixin(`import imports.imp12242a`~text(i+1)~`;`);
|
|
static assert(stripA("123")==1);
|
|
static assert(stripA([1],2)==2);
|
|
}
|
|
static assert(stripA("123")==1);
|
|
static assert(stripA([1],2)==2);
|
|
}
|
|
static foreach(i;0..2){
|
|
// (function scope, no forward referencing)
|
|
mixin(`import imports.imp12242a`~text(i+1)~`;`);
|
|
static assert(stripA("123")==1);
|
|
static if(i) static assert(stripA([1],2)==2);
|
|
}
|
|
static assert(stripA("123")==1);
|
|
static assert(stripA([1],2)==2);
|
|
}
|
|
|
|
auto front(T)(T[] a){ return a[0]; }
|
|
auto popFront(T)(ref T[] a){ a=a[1..$]; }
|
|
auto empty(T)(T[] a){ return !a.length; }
|
|
auto back(T)(T[] a){ return a[$-1]; }
|
|
auto popBack(T)(ref T[] a){ a=a[0..$-1]; }
|
|
|
|
struct Iota(T){
|
|
T s,e;
|
|
@property bool empty(){ return s>=e; }
|
|
@property T front(){ return s; }
|
|
@property T back(){ return cast(T)(e-1); }
|
|
void popFront(){ s++; }
|
|
void popBack(){ e--; }
|
|
}
|
|
auto iota(T)(T s, T e){ return Iota!T(s,e); }
|
|
|
|
template map(alias a){
|
|
struct Map(R){
|
|
R r;
|
|
@property front(){ return a(r.front); }
|
|
@property back(){ return a(r.back); }
|
|
@property bool empty(){ return r.empty; }
|
|
void popFront(){ r.popFront(); }
|
|
void popBack(){ r.popBack(); }
|
|
}
|
|
auto map(R)(R r){ return Map!R(r); }
|
|
}
|
|
|
|
template to(T:string){
|
|
string to(S)(S x)if(is(S:int)||is(S:size_t)||is(S:char)){
|
|
static if(is(S==char)) return cast(string)[x];
|
|
if(x<0) return "-"~to(-1 * x);
|
|
if(x==0) return "0";
|
|
return (x>=10?to(x/10):"")~cast(char)(x%10+'0');
|
|
}
|
|
}
|
|
auto text(T)(T arg){ return to!string(arg); };
|
|
|
|
template all(alias a){
|
|
bool all(R)(R r){
|
|
foreach(x;r) if(!a(x)) return false;
|
|
return true;
|
|
}
|
|
}
|
|
template any(alias a){
|
|
bool any(R)(R r){
|
|
foreach(x;r) if(a(x)) return true;
|
|
return false;
|
|
}
|
|
}
|
|
auto join(R)(R r,string sep=""){
|
|
string a;
|
|
int first=0;
|
|
foreach(x;r){
|
|
if(first++) a~=sep;
|
|
a~=x;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
static foreach_reverse(x;iota(0,10).map!(to!string)){
|
|
pragma(msg, x);
|
|
}
|
|
|
|
// create struct members iteratively
|
|
struct S{
|
|
static foreach(i;a){
|
|
mixin("int x"~to!string(i)~";");
|
|
}
|
|
immutable int[] a = [0,1,2];
|
|
}
|
|
enum s=S(1,2,3);
|
|
pragma(msg, s);
|
|
|
|
// loop over struct members
|
|
static foreach(member;__traits(allMembers,S)){
|
|
pragma(msg, member,": ",mixin("s."~member));
|
|
}
|
|
|
|
// print prime numbers using overload sets as state variables.
|
|
/+
|
|
static assert(is(typeof(bad57)));
|
|
static assert(!is(typeof(bad53)));
|
|
|
|
static foreach(x;iota(2,100)){
|
|
static foreach(y;iota(2,x)){
|
|
static if(!(x%y)){
|
|
mixin("void bad"~to!string(x)~"();");
|
|
}
|
|
}
|
|
static if(!is(typeof(mixin("bad"~to!string(x))))){
|
|
static assert(iota(2,x).all!(y=>!!(x%y)));
|
|
pragma(msg, x);
|
|
}else{
|
|
static assert(iota(2,x).any!(y=>!(x%y)));
|
|
}
|
|
}
|
|
+/
|
|
|
|
|
|
alias Seq(T...)=T;
|
|
|
|
alias Overloads(alias a) = Seq!(__traits(getOverloads, __traits(parent, a), __traits(identifier, a)));
|
|
|
|
template Parameters(alias f){
|
|
static if(is(typeof(f) P == function)) alias Parameters=P;
|
|
}
|
|
|
|
template forward(alias a){
|
|
enum x=2;
|
|
static foreach(f;Overloads!a){
|
|
auto ref forward(Parameters!f args){
|
|
return f(args);
|
|
}
|
|
}
|
|
enum y=3;
|
|
}
|
|
|
|
int foo(int x){ return x; }
|
|
string foo(string x){ return x; }
|
|
|
|
static assert(forward!foo(2)==2 && forward!foo("hi") == "hi");
|
|
|
|
|
|
// simple boilerplate-free visitor pattern
|
|
static foreach(char T;'A'..'F'){
|
|
mixin("class "~T~q{{
|
|
void accept(Visitor v){
|
|
return v.visit(this);
|
|
}
|
|
}});
|
|
}
|
|
alias Types = Seq!(mixin("Seq!("~iota('A','F').map!(to!string).join(", ")~")"));
|
|
abstract class Visitor{
|
|
static foreach(T;Types){
|
|
abstract void visit(T);
|
|
}
|
|
}
|
|
|
|
string testVisitor(){
|
|
string r;
|
|
void writeln(T...)(T args){
|
|
static foreach(x;args) r~=x;
|
|
r~='\n';
|
|
}
|
|
class Visitor: .Visitor{
|
|
static foreach(T;Types){
|
|
override void visit(T){
|
|
writeln("visited: ",T.stringof);
|
|
}
|
|
}
|
|
}
|
|
void main(){
|
|
auto v=new Visitor;
|
|
static foreach(T;Types){
|
|
v.visit(new T);
|
|
}
|
|
}
|
|
main();
|
|
return r;
|
|
}
|
|
static assert(testVisitor()=="visited: A
|
|
visited: B
|
|
visited: C
|
|
visited: D
|
|
visited: E
|
|
");
|
|
|
|
// iterative computation over AliasSeq:
|
|
template staticMap(alias F,T...){
|
|
alias state0=Seq!();
|
|
static foreach(i,A;T){
|
|
mixin("alias state"~to!string(i+1)~" = Seq!(state"~to!string(i)~",F!A);");
|
|
}
|
|
alias staticMap = Seq!(mixin("state"~to!string(T.length)));
|
|
}
|
|
|
|
alias arrayOf(T)=T[];
|
|
static assert(is(staticMap!(arrayOf,int,char,bool,Object)==Seq!(int[], char[], bool[], Object[])));
|
|
pragma(msg, staticMap!(arrayOf,int,char,bool,Object));
|
|
|
|
|
|
struct StaticForeachLoopVariable{
|
|
int x;
|
|
static foreach(i;0..1){
|
|
mixin("enum x"~text(i)~" = i;");
|
|
}
|
|
int y;
|
|
static assert(__traits(allMembers, StaticForeachLoopVariable).length==3);
|
|
static assert(!is(typeof(StaticForeachLoopVariable.i)));
|
|
static assert(!is(typeof(__traits(getMember, StaticForeachLoopVariable, "i"))));
|
|
}
|
|
|
|
struct StaticForeachScopeExit{
|
|
static:
|
|
int[] test(){
|
|
int[] r;
|
|
scope(exit) r ~= 1234;
|
|
{
|
|
static foreach(i;0..5){
|
|
scope(exit) r ~= i;
|
|
}
|
|
r ~= 5;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test()==[5,4,3,2,1,0]);
|
|
}
|
|
|
|
struct StaticForeachReverseHiding{
|
|
static foreach(i;[0]){
|
|
enum i = 1; // TODO: disallow?
|
|
static assert(i==0);
|
|
}
|
|
}
|
|
|
|
struct UnrolledForeachReverse{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int[] test(){
|
|
int[] r;
|
|
foreach_reverse(i;Seq!(0,1,2,3)){
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test()==[3,2,1,0]);
|
|
}
|
|
|
|
struct StaticForeachReverse{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int[] test(){
|
|
int[] r;
|
|
static foreach_reverse(i;0..4){
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test()==[3,2,1,0]);
|
|
|
|
int[] test2(){
|
|
int[] r;
|
|
static foreach_reverse(i;[0,1,2,3]){
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test2()==[3,2,1,0]);
|
|
|
|
int[] test3(){
|
|
static struct S{
|
|
int opApplyReverse(scope int delegate(int) dg){
|
|
foreach_reverse(i;0..4) if(auto r=dg(i)) return r;
|
|
return 0;
|
|
}
|
|
}
|
|
int[] r;
|
|
static foreach_reverse(i;S()){
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test3()==[3,2,1,0]);
|
|
|
|
int[] test4(){
|
|
int[] r;
|
|
static foreach_reverse(i;Seq!(0,1,2,3)){
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test()==[3,2,1,0]);
|
|
}
|
|
|
|
struct StaticForeachByAliasDefault{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
|
|
int[] test(){
|
|
int a,b,c;
|
|
static foreach(i,x;Seq!(a,b,c)) x=i;
|
|
return [a,b,c];
|
|
}
|
|
static assert(test()==[0,1,2]);
|
|
|
|
int[] test2(){
|
|
int x=0;
|
|
int foo(){ return ++x; }
|
|
static foreach(y;Seq!foo)
|
|
return [y,y,y];
|
|
}
|
|
static assert(test2()==[1,2,3]);
|
|
|
|
void test3(){
|
|
int x=0;
|
|
int foo(){ return ++x; }
|
|
static assert(!is(typeof({
|
|
static foreach(enum y;Seq!foo)
|
|
return [y,y,y];
|
|
})));
|
|
}
|
|
}
|
|
|
|
struct NestedStaticForeach{
|
|
static:
|
|
static foreach(i,name;["a"]){
|
|
static foreach(j,name2;["d"]){
|
|
mixin("enum int[] "~name~name2~"=[i, j];");
|
|
}
|
|
}
|
|
pragma(msg, ad);
|
|
}
|
|
|
|
struct TestAliasOutsideFunctionScope{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int a;
|
|
static foreach(alias x;Seq!(a)){
|
|
}
|
|
}
|
|
|
|
struct OpApplyMultipleStaticForeach{
|
|
static:
|
|
struct OpApply{
|
|
int opApply(scope int delegate(int,int) dg){
|
|
foreach(i;0..10) if(auto r=dg(i,i*i)) return r;
|
|
return 0;
|
|
}
|
|
}
|
|
static foreach(a,b;OpApply()){
|
|
mixin(`enum x`~cast(char)('0'+a)~"=b;");
|
|
}
|
|
static foreach(i;0..10){
|
|
static assert(mixin(`x`~cast(char)('0'+i))==i*i);
|
|
}
|
|
}
|
|
|
|
|
|
struct OpApplyMultipleStaticForeachLowered{
|
|
static:
|
|
struct OpApply{
|
|
int opApply(scope int delegate(int,int) dg){
|
|
foreach(i;0..10) if(auto r=dg(i,i*i)) return r;
|
|
return 0;
|
|
}
|
|
}
|
|
static foreach(x;{
|
|
static struct S(T...){ this(T k){ this.x=k; } T x; }
|
|
static s(T...)(T a){ return S!T(a); }
|
|
typeof({ foreach(a,b;OpApply()){ return s(a,b); } assert(0);}())[] r;
|
|
foreach(a,b;OpApply()) r~=s(a,b);
|
|
return r;
|
|
}()){
|
|
mixin(`enum x`~cast(char)('0'+x.x[0])~"=x.x[1];");
|
|
}
|
|
static foreach(i;0..10){
|
|
static assert(mixin(`x`~cast(char)('0'+i))==i*i);
|
|
}
|
|
}
|
|
|
|
struct RangeStaticForeach{
|
|
static:
|
|
struct Range{
|
|
int x=0;
|
|
this(int x){ this.x=x; }
|
|
@property int front(){ return x; }
|
|
void popFront(){ x += 2; }
|
|
@property bool empty(){ return x>=10; }
|
|
}
|
|
static foreach(i;Range()){
|
|
mixin(`enum x`~cast(char)('0'+i)~"=i;");
|
|
}
|
|
static foreach(i;0..5){
|
|
static assert(mixin(`x`~cast(char)('0'+2*i))==2*i);
|
|
}
|
|
static assert(!is(typeof({
|
|
struct S{
|
|
static foreach(i,k;Range()){}
|
|
}
|
|
})));
|
|
static foreach(k;Range()){} // ok
|
|
}
|
|
|
|
struct OpApplySingleStaticForeach{
|
|
static:
|
|
struct OpApply{
|
|
int opApply(scope int delegate(int) dg){
|
|
foreach(i;0..10) if(auto r=dg(i)) return r;
|
|
return 0;
|
|
}
|
|
}
|
|
static foreach(b;OpApply()){
|
|
mixin(`enum x`~cast(char)('0'+b)~"=b;");
|
|
}
|
|
static foreach(i;0..10){
|
|
static assert(mixin(`x`~cast(char)('0'+i))==i);
|
|
}
|
|
}
|
|
|
|
struct TypeStaticForeach{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
static foreach(i,alias T;Seq!(int,double,char)){
|
|
mixin(`T x`~cast(char)('0'+i)~";");
|
|
}
|
|
pragma(msg, "x0: ",typeof(x0));
|
|
pragma(msg, "x1: ",typeof(x1));
|
|
pragma(msg, "x2: ",typeof(x2));
|
|
static assert(is(typeof(x0)==int));
|
|
static assert(is(typeof(x1)==double));
|
|
static assert(is(typeof(x2)==char));
|
|
}
|
|
|
|
struct AliasForeach{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int[] test(){
|
|
int a,b,c;
|
|
static foreach(x;Seq!(a,b,c,2)){
|
|
static if(is(typeof({x=2;}))) x=2;
|
|
}
|
|
int x,y,z;
|
|
static foreach(alias k;Seq!(x,y,z,2)){
|
|
static if(is(typeof({k=2;}))) k=2;
|
|
}
|
|
int j,k,l;
|
|
static assert(!is(typeof({
|
|
static foreach(ref x;Seq!(j,k,l,2)){
|
|
static if(is(typeof({x=2;}))) x=2;
|
|
}
|
|
})));
|
|
return [x,y,z];
|
|
}
|
|
static assert(test()==[2,2,2]);
|
|
}
|
|
|
|
struct EnumForeach{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int a=1;
|
|
int fun(){ return 1; }
|
|
int gun(){ return 2; }
|
|
int hun(){ return 3;}
|
|
auto test(){
|
|
static foreach(i,enum x;Seq!(fun,gun,hun)){
|
|
static assert(i+1==x);
|
|
}
|
|
foreach(i,enum x;Seq!(fun,gun,hun)){
|
|
static assert(i+1==x);
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TestUninterpretable{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
auto test(){
|
|
int k;
|
|
static assert(!is(typeof({
|
|
static foreach(x;[k]){}
|
|
})));
|
|
static assert(!is(typeof({
|
|
foreach(enum x;[1,2,3]){}
|
|
})));
|
|
static assert(!is(typeof({
|
|
foreach(alias x;[1,2,3]){}
|
|
})));
|
|
foreach(enum x;Seq!(1,2,3)){} // ok
|
|
foreach(alias x;Seq!(1,2,3)){} // ok
|
|
static foreach(enum x;[1,2,3]){} // ok
|
|
static foreach(alias x;[1,2,3]){} // ok
|
|
static assert(!is(typeof({
|
|
static foreach(enum alias x;[1,2,3]){}
|
|
})));
|
|
int x;
|
|
static foreach(i;Seq!x){ } // ok
|
|
static foreach(i,j;Seq!(1,2,x)){ } // ok
|
|
static assert(!is(typeof({
|
|
static foreach(ref x;[1,2,3]){}
|
|
})));
|
|
}
|
|
}
|
|
|
|
struct SeqForeachConstant{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
static assert(!is(typeof({
|
|
foreach(x;Seq!1) x=2;
|
|
})));
|
|
int test2(){
|
|
int r=0;
|
|
foreach(x;Seq!(1,2,3)){
|
|
enum k=x;
|
|
r+=k;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test2()==6);
|
|
}
|
|
|
|
struct SeqForeachBreakContinue{
|
|
static:
|
|
alias Seq(T...)=T;
|
|
int[] test(){
|
|
int[] r;
|
|
foreach(i;Seq!(0,1,2,3,4,5)){
|
|
if(i==2) continue;
|
|
if(i==4) break;
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
static assert(test()==[0,1,3]);
|
|
}
|
|
|
|
struct TestStaticForeach{
|
|
static:
|
|
int test(int x){
|
|
int r=0;
|
|
label: switch(x){
|
|
static foreach(i;0..10){
|
|
case i: r=i; break label; // TODO: remove label when restriction is lifted
|
|
}
|
|
default: r=-1; break label;
|
|
}
|
|
return r;
|
|
}
|
|
static foreach(i;0..15){
|
|
pragma(msg, "test(",i,")→ ",test(i));
|
|
static assert(test(i)==(i<10?i:-1));
|
|
}
|
|
|
|
enum x=[1,2,3];
|
|
|
|
static foreach(i;x){
|
|
mixin("enum x"~cast(char)('0'+i)~"="~cast(char)('0'+i)~";");
|
|
}
|
|
|
|
static foreach(i;x){
|
|
pragma(msg, mixin("x"~cast(char)('0'+i)));
|
|
pragma(msg,x);
|
|
}
|
|
|
|
int[] noBreakNoContinue(){
|
|
int[] r;
|
|
static foreach(i;0..1){
|
|
// if(i==3) continue; // TODO: error?
|
|
// if(i==7) break; // TODO: error?
|
|
r~=i;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
mixin("enum k=3;");
|
|
}
|
|
|
|
static foreach(i,j;[1,2,3]){
|
|
pragma(msg, int(i)," ",j);
|
|
}
|
|
|
|
void testtest(){
|
|
static foreach(i,v;[1,2,3]){
|
|
pragma(msg, int(i)," ",v);
|
|
static assert(i+1 == v);
|
|
}
|
|
}
|
|
|
|
|
|
static foreach(i;Seq!(1,2,3,4,int)){
|
|
static if(!is(i) && i!=2){
|
|
pragma(msg, i);
|
|
}
|
|
}
|
|
|
|
int fun(int x){
|
|
int r=0;
|
|
label: switch(x){
|
|
static foreach(i;Seq!(0,1,2,3,4,5,6)){
|
|
static if (i < 5)
|
|
case i: r=i; break label; // TODO: remove label when restriction is lifted
|
|
}
|
|
default: r=-1; break label;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
static foreach(i;0..10) static assert(fun(i)==(i<5?i:-1));
|
|
|
|
static foreach(i;0..0) { }
|
|
void testEmpty(){
|
|
static foreach(i;0..0) { }
|
|
}
|
|
|
|
auto bug17660(){
|
|
int x;
|
|
static foreach (i; 0 .. 1) { return 3; }
|
|
return x;
|
|
}
|
|
static assert(bug17660()==3);
|
|
|
|
int breakContinueBan(){
|
|
static assert(!is(typeof({
|
|
for(;;){
|
|
static foreach(i;0..1){
|
|
break;
|
|
}
|
|
}
|
|
})));
|
|
static assert(!is(typeof({
|
|
for(;;){
|
|
static foreach(i;0..1){
|
|
continue;
|
|
}
|
|
}
|
|
})));
|
|
Louter1: for(;;){
|
|
static foreach(i;0..1){
|
|
break Louter1;
|
|
}
|
|
}
|
|
Louter2: foreach(i;0..10){
|
|
static foreach(j;0..1){
|
|
continue Louter2;
|
|
}
|
|
return 0;
|
|
}
|
|
static foreach(i;0..1){
|
|
for(;;){ break; } // ok
|
|
}
|
|
return 1;
|
|
}
|
|
static assert(breakContinueBan()==1);
|
|
|
|
mixin template MixinTemplate(){
|
|
static foreach(i;0..2){
|
|
mixin(`enum x`~cast(char)('0'+i)~"=i;");
|
|
}
|
|
static foreach(i;[0,1]){
|
|
mixin(`enum y`~cast(char)('0'+i)~"=i;");
|
|
}
|
|
}
|
|
void testToStatement(){
|
|
mixin MixinTemplate;
|
|
static assert(x0==0 && x1==1);
|
|
static assert(y0==0 && y1==1);
|
|
}
|
|
|
|
void bug17688(){
|
|
final switch(1) static foreach(x;0..1){ int y=3; case 1: return; }
|
|
static assert(!is(typeof(y)));
|
|
}
|
|
|
|
struct T{ enum n = 1; }
|
|
T foo(T v)@nogc{
|
|
static foreach(x;0..v.n){ }
|
|
return T.init;
|
|
}
|
|
T foo2(T v)@nogc{
|
|
static foreach(_;0..typeof(return).n){ }
|
|
return T.init;
|
|
}
|
|
|
|
//https://issues.dlang.org/show_bug.cgi?id=18698
|
|
|
|
static foreach(m; __traits(allMembers, staticforeach))
|
|
{
|
|
pragma(msg, m);
|
|
}
|
|
|
|
//https://issues.dlang.org/show_bug.cgi?id=20072
|
|
struct T2{
|
|
static foreach(i;0..1)
|
|
struct S{}
|
|
}
|
|
static assert(is(__traits(parent,T2.S)==T2));
|
|
|
|
struct TestStaticForeach2
|
|
{
|
|
static:
|
|
// StringExp
|
|
char[] test(string str)()
|
|
{
|
|
char[] s;
|
|
static foreach (c; str)
|
|
{
|
|
s ~= c;
|
|
}
|
|
return s;
|
|
}
|
|
static assert(test!"tёstñ" == ['t', '\xd1', '\x91', 's', 't', '\xc3', '\xb1']);
|
|
|
|
static foreach (c; "")
|
|
{
|
|
static assert(0);
|
|
}
|
|
|
|
// NullExp
|
|
enum int[] a = null;
|
|
static foreach (c; a)
|
|
{
|
|
static assert(0);
|
|
}
|
|
}
|
|
|
|
//https://issues.dlang.org/show_bug.cgi?id=22007
|
|
void issue22007()
|
|
{
|
|
immutable int[32] array = 1;
|
|
foreach (size_t a, int b; array) {}
|
|
static foreach (size_t a, int b; array) { }
|
|
}
|