diff --git a/AUTHORS b/AUTHORS index 6c3ac3db61..8001484e12 100644 --- a/AUTHORS +++ b/AUTHORS @@ -2,6 +2,10 @@ # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. +# Since Go 1.11, this file is not actively maintained. +# To be included, send a change adding the individual or +# company who owns a contribution's copyright. + # Names should be added to this file as one of # Organization's name # Individual's name @@ -10,26 +14,35 @@ # Please keep the list sorted. +10x Genomics, Inc. A Medium Corporation Aamir Khan Aaron France +Aaron Stein Aaron Torres +Aarti Parikh Abe Haskins Abhinav Gupta Adam Eijdenberg +Adam Harvey Adam Kisala +Adam Medzinski +Adam Shannon Adam Thomason +Adam Woodbeck Aditya Mukerjee Adrian Hesketh Adrian Nos Adrian O'Grady Adrien Bustany +Adrien Petel Aécio Júnior Aeneas Rekkas (arekkas) Afanasev Stanislav Agis Anastasopoulos Agniva De Sarker Ahmed Wahed +Ahmet Soormally Ahmy Yulrizka Aiden Scandella Ainar Garipov @@ -45,6 +58,8 @@ Alberto Bertogli Alberto Donizetti Alberto García Hierro Aleksandar Dezelin +Aleksandr Lukinykh +Alekseev Artem Alessandro Arzilli Alessandro Baffa Alex A Skinner @@ -52,11 +67,13 @@ Alex Brainman Alex Browne Alex Carol Alex Jin +Alex Myasoedov Alex Plugaru Alex Schroeder Alex Sergeyev Alexander Demakin Alexander Döring +Alexander F Rødseth Alexander Guz Alexander Kauer Alexander Kucherenko @@ -74,11 +91,13 @@ Alexandre Cesaro Alexandre Fiori Alexandre Normand Alexandre Parentea +Alexandre Viau Alexei Sholik Alexey Borzenkov Alexey Neganov Alexey Palazhchenko Alexis Hildebrandt +Ali Rizvi-Santiago Aliaksandr Valialkin Alif Rachmawadi Allan Simon @@ -86,6 +105,7 @@ Alok Menghrajani Aman Gupta Amazon.com, Inc Amir Mohammad Saied +Amr Mohammed Amrut Joshi Anand K. Mistry Anders Pearson @@ -94,11 +114,13 @@ Andre Nathan Andreas Auernhammer Andreas Litt Andrei Korzhevskii +Andrei Tudor Călin Andrei Vieru Andrew Austin Andrew Balholm Andrew Benton Andrew Bonventre +Andrew Braunstein Andrew Bursavich Andrew Ekstedt Andrew Etter @@ -120,11 +142,13 @@ Andrzej Żeżel Andy Balholm Andy Davis Andy Finkenstadt +Andy Lindeman Andy Maloney Andy Walker Anfernee Yongkun Gui Angelo Bulfone Anh Hai Trinh +Anit Gandhi Anmol Sethi Anschel Schaffer-Cohen Anthony Alves @@ -136,6 +160,8 @@ Anthony Starks Anthony Voutas Anthony Woods Antoine Martin +Antonin Amand +Antonio Antelo Antonio Bibiano Antonio Troina Apisak Darakananda @@ -149,19 +175,25 @@ Arnaud Ysmal Arne Hormann Arnout Engelen Aron Nopanen +Arthur Khashaev Artyom Pervukhin Arvindh Rajesh Tamilmani +Ashish Gandhi Atin Malaviya Ato Araki Audrey Lim +Audrius Butkevicius Augusto Roman Aulus Egnatius Varialus +Aurélien Rainone awaw fumin Awn Umar Axel Wagner Ayanamist Yang Aymerick Jéhanne +Azat Kaumov Baiju Muthukadan +Baokun Lee Bartosz Grzybowski Bastian Ike Ben Burkert @@ -170,9 +202,12 @@ Ben Lubar Ben Olive Ben Shi Benjamin Black +Benjamin Cable +Benjamin Hsieh Benny Siegert Benoit Sigoure Berengar Lehr +Bill Zissimopoulos Billie Harold Cleek Bjorn Tillenius Bjorn Tipling @@ -181,10 +216,14 @@ Blake Gentry Blake Mesdag Blake Mizerany Blixt +Bob Briski +Bob Potter Bobby Powers Bolt Borja Clemente Brad Burch +Brad Morgan +Bradley Falzon Brady Catherman Brady Sullivan Brendan Daniel Tracey @@ -200,11 +239,14 @@ Brian Ketelsen Brian Smith Brian Starke Bryan Alexander +Bryan Chan Bryan Ford Bulat Gaifullin Burak Guven Caine Tighe +Caleb Martinez Caleb Spare +Canonical Limited Carl Chatfield Carl Henrik Lunde Carl Johnson @@ -214,14 +256,17 @@ Carlos Castillo Carlos Cirello Carolyn Van Slyck Case Nelson +Casey Callendrello Casey Marshall Cezar Sá Espinola ChaiShushan Charles Fenwick Elliott Charles L. Dorian Charles Lee +Chef Software, Inc. Chew Choon Keat Cholerae Hu +Chotepud Teo Chris Ball Chris Biscardi Chris Dollin @@ -231,14 +276,18 @@ Chris Howey Chris Jones Chris Kastorff Chris Lennert +Chris Liles Chris McGee Chris Roche +Chris Smith Chris Stockton Christian Alexander Christian Couder Christian Himpel +Christian Pellegrin Christine Hansmann Christoffer Buchholz +Christoph Blecker Christoph Hack Christopher Cahoon Christopher Guiney @@ -256,6 +305,8 @@ Colin Edwards Colin Kennedy Conrad Irwin Conrad Meyer +Conrado Gouvea +Constantin Konstantinidis CoreOS, Inc. Corey Thomasson Cristian Staretu @@ -264,6 +315,7 @@ Cyrill Schumacher Daisuke Fujita Damian Gryski Damien Lespiau +Damien Mathieu <42@dmathieu.com> Dan Ballard Dan Caddigan Dan Callahan @@ -276,6 +328,7 @@ Daniel Krech Daniel Lidén Daniel Martí Daniel Morsing +Daniel Nephin Daniel Ortiz Pereira da Silva Daniel Skinner Daniel Speichert @@ -284,12 +337,15 @@ Daniel Upton Daniela Petruzalek Danny Rosseau Darren Elwood +Darshan Parajuli Datong Sun Dave Cheney Dave MacFarlane +Dave Russell David Brophy David Bürgin <676c7473@gmail.com> David Calavera +David Carlier David du Colombier <0intro@gmail.com> David Forsythe David G. Andersen @@ -302,31 +358,41 @@ David Sansome David Stainton David Thomas David Titarenco +David Url David Volquartz Lebech +David Wimmer Davies Liu Davor Kapsa Dean Prichard Deepak Jois Denis Bernard Denis Brandolini +Dennis Kuhnert Denys Honsiorovskyi Derek Buitenhuis Derek McGowan Derek Parker Derek Shockey +Dev Ojha +Dev Zhoujun Develer SRL Devon H. O'Dell Dhaivat Pandit Dhiru Kholia +Dhruvdutt Jadhav Didier Spezia +Dimitri Sokolyuk Dimitri Tcaciuc +Diogo Pinela Dirk Gadsden Diwaker Gupta Dmitri Popov -Dmitri Shuralyov +Dmitri Shuralyov +Dmitriy Cherchenko Dmitriy Dudkin Dmitriy Shelenin Dmitry Chestnykh +Dmitry Doroginin Dmitry Savintsev Dmitry Yakunin Dominic Green @@ -343,35 +409,43 @@ Dvir Volk Dylan Waits Edan Bedrik <3d4nb3@gmail.com> Eden Li +Eduardo Ramalho Edward Muller Egon Elbre Ehren Kret Eitan Adler Eivind Uggedal Elbert Fliek +Eldar Rakhimberdin Elena Grahovac Elias Naur Elliot Morrison-Reed Emerson Lin Emil Hessman +Emil Mursalimov Emilien Kenler Emmanuel Odeke Empirical Interfaces Inc. Eoghan Sherry Eric Chiang Eric Clark +Eric Daniels Eric Engestrom Eric Lagergren Eric Milliken +Eric Pauley Eric Rescorla Eric Roshan-Eisner +Eric Rykwalder Erik Aigner Erik Dubbelboer Erik St. Martin Erik Westrup Ernest Chiang +Erwin Oegema Esko Luontola Euan Kemp +Eugene Kalinin Evan Hicks Evan Jones Evan Phoenix @@ -392,21 +466,27 @@ Fazlul Shahriar Fedor Indutny Felipe Oliveira Felix Geisendörfer +Felix Kollmann Filip Gruszczyński +Filip Haglund Filippo Valsorda Firmansyah Adiputra Florian Uekermann Florian Weimer Florin Patan Ford Hurley +Francesc Campoy Francisco Claude Francisco Rojas Francisco Souza +Frank Schroeder Frank Somers Frederic Guillot Frederick Kelly Mayle III +Frederik Ring Fredrik Enestad Fredrik Forsmo +Fredrik Wallgren Frithjof Schulze Frits van Bommel Gabríel Arthúr Pétursson @@ -417,13 +497,16 @@ Gareth Paul Jones Gary Burd Gaurish Sharma Gautham Thambidorai +Gauthier Jolly Geert-Johan Riemer Gengliang Wang Geoffroy Lorieux +Geon Kim Georg Reinke George Gkirtsou George Shammas Gerasimos Dimitriadis +Getulio Sánchez Gideon Jan-Wessel Redelinghuys Giles Lean Giulio Iotti @@ -435,8 +518,10 @@ Graham Miller Grant Griffiths Greg Poirier Greg Ward +Grégoire Delattre Gregory Man Guilherme Garnier +Guilherme Goncalves Guilherme Rezende Guillaume J. Charmes Guobiao Mei @@ -447,8 +532,10 @@ Gwenael Treguier Gyu-Ho Lee H. İbrahim Güngör Hajime Hoshi +HAMANO Tsukasa Hang Qian Hanjun Kim +Harald Nordgren Hari haran Hariharan Srinath Harley Laue @@ -464,6 +551,7 @@ Henrik Hodne Henry Adi Sumarto Henry Bubert Henry Chang +Henry Clifford Herbert Georg Fischer Hilko Bengen Hiroaki Nakamura @@ -488,18 +576,27 @@ Igor Dolzhikov Igor Vashyst INADA Naoki Inanc Gumus +Infobaleen AB +Ingo Gottwald Ingo Krabbe Ingo Oeser Intel Corporation +Ioannis Georgoulas +Irfan Sharif Irieda Noboru +Isaac Ardis Isaac Wagner Ivan Babrou Ivan Bertona +Ivan Markin Ivan Moscoso Ivan Ukhov +Jack Britton +Jacob H. Haven Jacob Hoffman-Andrews Jae Kwon Jakob Borg +Jakob Weisblat Jakub Ryszard Czarnowicz James Bardin James Clarke @@ -525,12 +622,15 @@ Jamie Stackhouse Jamil Djadala Jan Berktold Jan H. Hosang +Jan Lehnardt Jan Mercl <0xjnml@gmail.com> Jan Newmarch +Jan Pilzer Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Jani Monoses Jared Culp Jaroslavas Počepko +Jason A. Donenfeld Jason Barnett Jason Chu Jason Del Ponte @@ -539,9 +639,12 @@ Jason Travis Jason Wangsadinata Javier Segura Jay Weisskopf +Jean-André Santoni Jean-Francois Cantin Jean-Nicolas Moal Jeet Parekh +Jeevanandam M +Jeff Dupont Jeff Hodges Jeff R. Allen Jeff Sickel @@ -551,8 +654,10 @@ Jelte Fennema Jens Frederich Jeremy Jackins Jeroen Bobbeldijk +Jerrin Shaji George Jess Frazelle Jesse Szwedko +Jesús Espino Jihyun Yu Jim McGrath Jimmy Frasche @@ -564,6 +669,7 @@ Jiong Du Jirka Daněk Jiulong Wang Joakim Sernbrant +Joe Cortopassi Joe Farrell Joe Harrison Joe Henke @@ -572,25 +678,31 @@ Joe Poirier Joe Shaw Joe Sylve Joe Tsai +Joel Sing Joel Stemmer Joey Geiger Johan Brandhorst Johan Sageryd John Asmuth John C Barstow +John Gibb John Graham-Cumming John Howard Palevich John Jeffery John Jenkins +John Leidegren John Potocny John R. Lenton John Schnake John Shahid John Tuley Johnny Luo +Jonas Bernoulli Jonathan Boulle +Jonathan Chen Jonathan Gold Jonathan Mark +Jonathan Pentecost Jonathan Rudenberg Jonathan Stacks Jonathan Wills @@ -607,6 +719,7 @@ Josh Deprez Josh Goebel Josh Holland Josh Roppo +Josh Varga Joshua Chase Joshua Rubin Josselin Costanzi @@ -618,8 +731,11 @@ Jude Pereira Jukka-Pekka Kekkonen Julian Kornberger Julian Phillips +Julien Salleyron Julien Schmidt +Junda Liu Junya Hayashi +Justin Gracenin Justin Nuß Justyn Temme Kai Backman @@ -628,6 +744,7 @@ Kale Blankenship Kaleb Elwert Kamil Chmielewski Kamil Kisiel +Kamil Rytarowski Kang Hu Karel Pazdera Karoly Negyesi @@ -658,6 +775,7 @@ Kevin Ruffin Kevin Vu Kieran Colford Kim Yongbin +Kir Kolyshkin Kirk Han Klaus Post Kodie Goodwin @@ -670,6 +788,7 @@ Kris Nova Kristopher Watts Kun Li Kunpei Sakai +Kuntal Majumder Kyle Consalus Kyle Isom Kyle Jones @@ -680,7 +799,10 @@ Kyrylo Silin L Campbell Lai Jiangshan Lakshay Garg +Lanre Adelowo +Larry Hosken Lars Jeppesen +Lars Lehtonen Lars Wiegman Larz Conwell Laurent Voisin @@ -688,8 +810,11 @@ Laurie Clark-Michalek LE Manh Cuong Lee Hinman Lee Packham +Lehner Florian Leigh McCulloch +Leo Antunes Leon Klingele +Leonel Quinteros Lev Shamardin Lewin Bormann Liberty Fund Inc @@ -699,6 +824,7 @@ Lloyd Dewolf Lorenzo Masini Lorenzo Stoakes Luan Santos +Lubomir I. Ivanov Luca Greco Lucas Bremgartner Lucien Stuker @@ -715,19 +841,23 @@ Maicon Costa Maksym Trykur Mal Curtis Manfred Touron +Manigandan Dharmalingam Manish Goregaokar Mansour Rahimi Manu S Ajith Manuel Mendez Marc Weistroff Marcel Edmund Franke +Marcelo Cantos Marcelo E. Magallon Marco Hennings Marin Bašić +Mario Arranz Mark Adams Mark Bucciarelli Mark Percival Mark Pulford +Mark Rushakoff Mark Severson Mark Theunissen Mark Wolfe @@ -742,12 +872,14 @@ Martin Bertschler Martin Garton Martin Hamrle Martin Hoefling +Martin Kunc Martin Lindhe Martin Möhrmann Martin Neubauer Martin Olsen Martin Olsson Martin Probst +Martin Sucha Martins Sipenko Marvin Stenger Marwan Sulaiman @@ -756,6 +888,7 @@ Masahiro Furudate Masahiro Wakame Masaki Yoshida Mat Byczkowski +Mat Ryer Máté Gulyás Matej Baćo Mateus Amin @@ -773,6 +906,7 @@ Matt Drollette Matt Harden Matt Jibson Matt Joiner +Matt Juran Matt Layher Matt Reiferson Matt Robenolt @@ -803,15 +937,18 @@ Mhd Sulhan Micah Stetson Michael Brandenburg Michael Chaten +Michael Dorner Michael Edwards Michael Elkins Michael Fraenkel Michael Gehring Michael Hendricks Michael Hoisie +Michael Kasch Michael Käufl Michael Lewis Michael MacInnis +Michael Marineau Michael McConville Michael McLoughlin Michael Pearson @@ -823,6 +960,7 @@ Michael Teichgräber Michael Vetter Michal Bohuslávek Michał Derkacz +Michal Franc Michal Pristas Miek Gieben Miguel Mendez @@ -833,16 +971,22 @@ Mikael Tillenius Mike Andrews Mike Appleby Mike Houston +Mike Kabischev Mike Rosset +Mike Tsao Mikhail Gusarov Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz +Milan Knezevic Milutin Jovanović +MinJae Kwon Miquel Sabaté Solà Miroslav Genov +Misty De Meo Mohit Agarwal +Mohit kumar Bajoria Momchil Velikov Monty Taylor Moov Corporation @@ -855,6 +999,8 @@ Muhammed Uluyol Mura Li Nan Deng Naoki Kanatani +Nate Wilkinson +Nathan Cantelmo Nathan Caza Nathan Humphreys Nathan John Youngman @@ -863,10 +1009,12 @@ Nathan P Finch Nathan VanBenschoten Nathan Youngman Nathaniel Cook +Naveen Kumar Sangi Neelesh Chandola Neil Lyons Netflix, Inc. Neuman Vong +Neven Sajko Nevins Bartolomeo Nexedi ngmoco, LLC @@ -883,20 +1031,25 @@ Nick Miyake Nick Patavalis Nick Petroni Nick Robinson +Nick Smolin Nicolas BRULEZ Nicolas Kaiser Nicolas Owens Nicolas S. Dade +Niek Sanders Niels Widger Nigel Kerr Nik Nyby +Nikhil Benesch Niklas Schnelle Niko Dziemba Nikolay Turpitko Nils Larsgård Niranjan Godbole +Nishanth Shanmugham Noah Campbell Noble Johnson +Noel Georgi Norberto Lopes Odin Ugedal Oleg Bulatov @@ -911,10 +1064,13 @@ Olivier Poitrey Olivier Saingre Oracle Orange +Orijtech, Inc. Özgür Kesim Pablo Lalloni +Pablo Rozas Larraondo Pablo Santiago Blum de Aguiar Padraig Kitterick +Pallat Anchaleechamaikorn Palm Stone Games Paolo Giarrusso Paolo Martini @@ -941,6 +1097,7 @@ Paul Rosania Paul Ruest Paul Sbarra Paul Smith +Paul Tyng Paul van Brouwershaven Paulo Casaretto Pavel Paulau @@ -952,6 +1109,7 @@ Perry Abbott Petar Maymounkov Peter Armitage Peter Bourgon +Peter Conerly Peter Froehlich Peter Kleiweg Peter Moody @@ -960,18 +1118,26 @@ Peter Mundy Peter Nguyen Péter Surányi Péter Szilágyi +Peter Teichman Peter Waldschmidt Peter Waller Peter Williams +Peter Zhang Petrica Voicu +Phil Pearl Philip Børgesen +Philip Brown Philip Hofer Philip K. Warren +Philip Nelson Pierre Durand +Pierre Prinetti Pierre Roullon Piers Pieter Droogendijk Pietro Gagliardi +Piyush Mishra +Platform.sh Pontus Leitzler Prashant Varanasi Pravendra Singh @@ -995,6 +1161,7 @@ Rajender Reddy Kompally Ralph Corderoy Ramazan AYYILDIZ Raphael Geronimi +Ravil Bikbulatov RaviTeja Pothana Ray Tung Raymond Kazlauskas @@ -1003,6 +1170,7 @@ Reilly Watson Reinaldo de Souza Jr Remi Gillig Rémy Oudompheng +Rens Rikkerink Ricardo Padilha Richard Barnes Richard Crowley @@ -1016,13 +1184,16 @@ Rick Sayre Risto Jaakko Saarelma Rob Norman Rob Phoenix -Robert Daniel Kortschak +Robert Daniel Kortschak Robert Dinu Robert Figueiredo Robert Hencke Robert Obryk Robert Stepanek +Robert-André Mauchin +Roberto Clapis Robin Eklind +Rodolfo Carvalho Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné @@ -1033,24 +1204,31 @@ Ron Hashimoto Ron Minnich Ross Chater Ross Light +Rowan Marshall Rowan Worth Rudi Kramer Russell Haering Ryan Bagwell Ryan Boehning +Ryan Canty Ryan Hitchman Ryan Lower +Ryan Roden-Corrent Ryan Seys Ryan Slade +Ryan Zhang Ryoichi KATO Ryuji Iwata +Ryuma Yoshida Ryuzo Yamamoto S.Çağlar Onur +Sabin Mihai Rapan Sakeven Jiang Salmān Aljammāz Sam Boyer Sam Hug Sam Whited +Sami Pönkänen Samuele Pedroni Sanjay Menakuru Sascha Brawer @@ -1066,17 +1244,22 @@ Sébastien Paolacci Seiji Takahashi Sergei Skorobogatov Sergey 'SnakE' Gromov +Sergey Lukjanov Sergey Mishin +Sergey Mudrik Sergey Semin Sergio Luis O. B. Correia Sergiusz Bazanski Seth Hoenig Seth Vargo Shahar Kohanim +Shamil Garatuev Shane Hansen Shaozhen Ding +Shaun Dunning Shawn Smith Shenghou Ma +Shengyu Zhang Shi Han Ng Shinji Tanaka Shintaro Kaneko @@ -1097,8 +1280,10 @@ Sridhar Venkatakrishnan StalkR Stan Schwertly Stanislav Afanasev +Steeve Morin Stefan Nilsson Stéphane Travostino +Stephen Lewis Stephen McQuay Stephen Searles Stephen Weinberg @@ -1113,6 +1298,7 @@ Steven Wilkin Stripe, Inc. Sukrit Handa Sunny +Suriyaa Sundararuban Suyash Sven Almgren Sylvain Zimmer @@ -1121,6 +1307,7 @@ Szabolcs Nagy Tad Fisher Tad Glines Taj Khattra +Takayoshi Nishida Takeshi YAMANASHI <9.nashi@gmail.com> Takuya Ueda Tal Shprecher @@ -1130,22 +1317,28 @@ Tarmigan Casebolt Taro Aoki Taru Karttunen Tatsuhiro Tsujikawa +Teague Cole Ted Kornish +Tejasvi Nareddy Teleport Inc. Terin Stock Terrel Shumway Tetsuo Kiso +Thanabodee Charoenpiriyakij Thanatat Tamtan Thiago Avelino Thiago Fransosi Farina Thomas Alan Copeland Thomas Bonfort +Thomas Bruyelle Thomas de Zeeuw Thomas Desrosiers Thomas Kappler +Thomas Meson Thomas Wanielista Thorben Krueger Thordur Bjornsson +Tiago Queiroz Tilman Dilo Tim Cooijmans Tim Cooper @@ -1162,20 +1355,26 @@ Tobias Klauser Todd Neal Tom Heng Tom Levy +Tom Limoncelli Tom Linford +Tom Payne +Tom Thorogood Tommy Schaefer +Tomoya Ishizaki Tonis Tiigi Tony Walker Tor Andersson Tormod Erevik Lea Toshiki Shima Totoro W +Travis Bischel Travis Cline Trey Lawrence Trey Roessig Trey Tacon Tristan Colgate Tristan Ooohry +Tristan Rice Troels Thomsen Trung Nguyen Tudor Golubenco @@ -1183,6 +1382,7 @@ Tugdual Saunier Tuo Shan Tyler Bunnell Tyler Treat +Uber Technologies Ugorji Nwoke Ulf Holm Nielsen Ulrich Kunitz @@ -1191,7 +1391,9 @@ Uriel Mangado Vadim Grek Vadim Vygonets Vendasta +Veselkov Konstantin Victor Vrantchan +Vignesh Ramachandra Vincent Ambo Vincent Batts Vincent Vanackere @@ -1202,17 +1404,22 @@ Vladimir Mihailenco Vladimir Nikishenko Vladimir Stefanovic Vladimir Varankin +VMware, Inc. Volker Dobler +W. Trevor King Wade Simmons Wander Lairson Costa +Wayne Ashley Berry Weaveworks Wèi Cōngruì +Wei Fu Wei Guangjing Weichao Tang Wembley G. Leach, Jr Will Faught Will Storey Willem van der Schyff +William Chang William Josephson William Orr Wisdom Omuya @@ -1222,34 +1429,44 @@ Xia Bin Xing Xing Xu Fei Xudong Zhang +Xudong Zheng <7pkvm5aw@slicealias.com> Xuyang Kang Yahoo Inc. +Yamagishi Kazutoshi Yann Kerhervé Yann Salaün Yao Zhang Yasha Bubnov Yasuharu Goto Yasuhiro Matsumoto +Yasuyuki Oka +Yazen Shunnar Yestin Sun Yissakhar Z. Beck Yo-An Lin Yongjian Xu Yorman Arias Yoshiyuki Kanno +Yoshiyuki Mineo Yosuke Akatsuka +Yuji Yaginuma Yukihiro Nishinaka <6elpinal@gmail.com> +Yury Smolsky Yusuke Kagiwada Yuusei Kuwana Yuval Pavel Zholkover Zac Bergquist Zach Bintliff Zach Gershman +Zachary Gershman Zak Zakatell Kanda Zellyn Hunter Zemanta d.o.o. Zev Goldstein +Zheng Dayu Zhongtao Chen +Zhou Peng Ziad Hatahet Zorion Arrizabalaga Максим Федосеев diff --git a/CONTRIBUTORS b/CONTRIBUTORS index f76e5156de..305f6d8d80 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -4,9 +4,6 @@ # lists people. For example, Google employees are listed here # but not in AUTHORS, because Google holds the copyright. # -# The submission process automatically checks to make sure -# that people submitting code are listed in this file (by email address). -# # Names should be added to this file only after verifying that # the individual or the individual's organization has agreed to # the appropriate Contributor License Agreement, found here: @@ -15,11 +12,6 @@ # http://code.google.com/legal/corporate-cla-v1.0.html # # The agreement for individuals can be filled out on the web. -# -# When adding J Random Contributor's name to this file, -# either J's name or J's organization's name should be -# added to the AUTHORS file, depending on whether the -# individual or corporate CLA was used. # Names should be added to this file like so: # Individual's name @@ -36,20 +28,29 @@ Aamir Khan Aaron France Aaron Jacobs Aaron Kemp +Aaron Stein Aaron Torres Aaron Zinman +Aarti Parikh Abe Haskins Abhinav Gupta +Adam Azarchs Adam Bender Adam Eijdenberg +Adam Harvey Adam Kisala Adam Langley +Adam Medzinski +Adam Shannon +Adam Sindelar Adam Thomason +Adam Woodbeck Aditya Mukerjee Adrian Hesketh Adrian Nos Adrian O'Grady Adrien Bustany +Adrien Petel Aécio Júnior Aeneas Rekkas (arekkas) Afanasev Stanislav @@ -57,6 +58,7 @@ Agis Anastasopoulos Agniva De Sarker Ahmed Wahed Ahmet Alp Balkan +Ahmet Soormally Ahmy Yulrizka Aiden Scandella Ainar Garipov @@ -73,6 +75,8 @@ Alberto Bertogli Alberto Donizetti Alberto García Hierro Aleksandar Dezelin +Aleksandr Lukinykh +Alekseev Artem Alessandro Arzilli Alessandro Baffa Alex A Skinner @@ -81,12 +85,14 @@ Alex Bramley Alex Browne Alex Carol Alex Jin +Alex Myasoedov Alex Plugaru Alex Schroeder Alex Sergeyev Alex Vaghin Alexander Demakin Alexander Döring +Alexander F Rødseth Alexander Guz Alexander Kauer Alexander Kucherenko @@ -105,6 +111,7 @@ Alexandre Cesaro Alexandre Fiori Alexandre Normand Alexandre Parentea +Alexandre Viau Alexandru Moșoi Alexei Sholik Alexey Borzenkov @@ -113,12 +120,14 @@ Alexey Palazhchenko Alexis Hildebrandt Alexis Hunt Alexis Imperial-Legrand +Ali Rizvi-Santiago Aliaksandr Valialkin Alif Rachmawadi Allan Simon Alok Menghrajani Aman Gupta Amir Mohammad Saied +Amr Mohammed Amrut Joshi Anand K. Mistry Anders Pearson @@ -129,12 +138,14 @@ Andreas Auernhammer Andreas Jellinghaus Andreas Litt Andrei Korzhevskii +Andrei Tudor Călin Andrei Vieru Andres Erbsen Andrew Austin Andrew Balholm Andrew Benton Andrew Bonventre +Andrew Braunstein Andrew Bursavich Andrew Ekstedt Andrew Etter @@ -160,11 +171,13 @@ Andrzej Żeżel Andy Balholm Andy Davis Andy Finkenstadt +Andy Lindeman Andy Maloney Andy Walker Anfernee Yongkun Gui Angelo Bulfone Anh Hai Trinh +Anit Gandhi Anmol Sethi Anschel Schaffer-Cohen Anthony Alves @@ -176,6 +189,8 @@ Anthony Starks Anthony Voutas Anthony Woods Antoine Martin +Antonin Amand +Antonio Antelo Antonio Bibiano Antonio Murdaca Antonio Troina @@ -189,23 +204,30 @@ Arnaud Ysmal Arne Hormann Arnout Engelen Aron Nopanen +Arthur Khashaev Artyom Pervukhin Arvindh Rajesh Tamilmani +Ashish Gandhi Asim Shankar Atin Malaviya Ato Araki Audrey Lim +Audrius Butkevicius Augusto Roman Aulus Egnatius Varialus +Aurélien Rainone Austin Clements awaw fumin Awn Umar Axel Wagner Ayanamist Yang Aymerick Jéhanne +Azat Kaumov Baiju Muthukadan Balazs Lecz +Baokun Lee Bartosz Grzybowski +Bartosz Oler Bastian Ike Ben Burkert Ben Eitzen @@ -218,6 +240,8 @@ Ben Olive Ben Schwartz Ben Shi Benjamin Black +Benjamin Cable +Benjamin Hsieh Benjamin Prosnitz Benjamin Wester Benny Siegert @@ -227,6 +251,7 @@ Bill Neubauer Bill O'Farrell Bill Prin Bill Thiede +Bill Zissimopoulos Billie Harold Cleek Billy Lynch Bjorn Tillenius @@ -236,6 +261,8 @@ Blake Gentry Blake Mesdag Blake Mizerany Blixt +Bob Briski +Bob Potter Bobby Powers Boris Nagaev Borja Clemente @@ -243,8 +270,10 @@ Brad Burch Brad Fitzpatrick Brad Garcia Brad Jones +Brad Morgan Brad Whitaker Braden Bassingthwaite +Bradley Falzon Brady Catherman Brady Sullivan Brandon Bennett @@ -271,6 +300,7 @@ Bulat Gaifullin Burak Guven Caine Tighe Caio Marcelo de Oliveira Filho +Caleb Martinez Caleb Spare Carl Chatfield Carl Henrik Lunde @@ -286,11 +316,13 @@ Carlos Eduardo Seo Carolyn Van Slyck Cary Hull Case Nelson +Casey Callendrello Casey Marshall Catalin Nicutar Catalin Patulea Cedric Staub Cezar Sá Espinola +Chad Rosier ChaiShushan Charles Fenwick Elliott Charles L. Dorian @@ -299,6 +331,7 @@ Charles Weill Cherry Zhang Chew Choon Keat Cholerae Hu +Chotepud Teo Chris Ball Chris Biscardi Chris Broadfoot @@ -310,17 +343,21 @@ Chris Hundt Chris Jones Chris Kastorff Chris Lennert +Chris Liles Chris Manghane Chris McGee Chris Raynor Chris Roche +Chris Smith Chris Stockton Chris Zou Christian Alexander Christian Couder Christian Himpel +Christian Pellegrin Christine Hansmann Christoffer Buchholz +Christoph Blecker Christoph Hack Christopher Cahoon Christopher Guiney @@ -340,11 +377,15 @@ Colby Ranger Colin Cross Colin Edwards Colin Kennedy +Colin Rice Conrad Irwin Conrad Meyer +Conrado Gouvea +Constantin Konstantinidis Corey Thomasson Cosmos Nicolaou Costin Chirvasuta +Craig Citro Cristian Staretu Cuihtlauac ALVARADO Cyrill Schumacher @@ -352,7 +393,9 @@ Daisuke Fujita Daker Fernandes Pinheiro Damian Gryski Damien Lespiau +Damien Mathieu <42@dmathieu.com> Damien Neil +Damien Tournoud Dan Ballard Dan Caddigan Dan Callahan @@ -369,6 +412,7 @@ Daniel Lidén Daniel Martí Daniel Morsing Daniel Nadasi +Daniel Nephin Daniel Ortiz Pereira da Silva Daniel Skinner Daniel Speichert @@ -378,6 +422,7 @@ Daniela Petruzalek Danny Rosseau Daria Kolistratova Darren Elwood +Darshan Parajuli Datong Sun Dave Borowitz Dave Bort @@ -385,12 +430,14 @@ Dave Cheney Dave Day Dave Grijalva Dave MacFarlane +Dave Russell David Anderson David Barnett David Benjamin David Brophy David Bürgin <676c7473@gmail.com> David Calavera +David Carlier David Chase David Covert David Crawshaw @@ -412,7 +459,9 @@ David Stainton David Symonds David Thomas David Titarenco +David Url David Volquartz Lebech +David Wimmer Davies Liu Davor Kapsa Dean Prichard @@ -420,28 +469,36 @@ Deepak Jois Denis Bernard Denis Brandolini Denis Nagorny +Dennis Kuhnert Denys Honsiorovskyi Derek Buitenhuis Derek Che Derek McGowan Derek Parker Derek Shockey +Dev Ojha +Dev Zhoujun Devon H. O'Dell Dhaivat Pandit Dhananjay Nakrani Dhiru Kholia +Dhruvdutt Jadhav Di Xiao Didier Spezia Dieter Plaetinck +Dimitri Sokolyuk Dimitri Tcaciuc +Diogo Pinela Dirk Gadsden Diwaker Gupta Dmitri Popov -Dmitri Shuralyov +Dmitri Shuralyov +Dmitriy Cherchenko Dmitriy Dudkin Dmitriy Shelenin Dmitriy Vyukov Dmitry Chestnykh +Dmitry Doroginin Dmitry Savintsev Dmitry Yakunin Dominic Green @@ -463,39 +520,48 @@ Dvir Volk Dylan Waits Edan Bedrik <3d4nb3@gmail.com> Eden Li +Eduardo Ramalho Edward Muller Egon Elbre Ehren Kret Eitan Adler Eivind Uggedal Elbert Fliek +Eldar Rakhimberdin Elena Grahovac Elias Naur Elliot Morrison-Reed Emerson Lin Emil Hessman +Emil Mursalimov Emilien Kenler Emmanuel Odeke +Eno Compton Eoghan Sherry Eric Chiang Eric Clark +Eric Daniels Eric Engestrom Eric Garrido Eric Koleda Eric Lagergren Eric Milliken +Eric Pauley Eric Rescorla Eric Roshan-Eisner +Eric Rykwalder Erik Aigner Erik Dubbelboer Erik St. Martin Erik Staab Erik Westrup Ernest Chiang +Erwin Oegema Esko Luontola Ethan Burns Ethan Miller Euan Kemp +Eugene Kalinin Evan Broder Evan Brown Evan Hicks @@ -522,7 +588,9 @@ Federico Simoncelli Fedor Indutny Felipe Oliveira Felix Geisendörfer +Felix Kollmann Filip Gruszczyński +Filip Haglund Filippo Valsorda Firmansyah Adiputra Florian Uekermann @@ -534,11 +602,14 @@ Francesc Campoy Francisco Claude Francisco Rojas Francisco Souza +Frank Schroeder Frank Somers Frederic Guillot Frederick Kelly Mayle III +Frederik Ring Fredrik Enestad Fredrik Forsmo +Fredrik Wallgren Frithjof Schulze Frits van Bommel Fumitoshi Ukai @@ -554,17 +625,32 @@ Gary Burd Gary Elliott Gaurish Sharma Gautham Thambidorai +Gauthier Jolly Geert-Johan Riemer Gengliang Wang Geoff Berry Geoffroy Lorieux +Geon Kim Georg Reinke George Gkirtsou George Shammas Gerasimos Dimitriadis +Getulio Sánchez Gideon Jan-Wessel Redelinghuys Giles Lean Giovanni Bajo +GitHub User @ajnirp (1688456) +GitHub User @as (8127015) +GitHub User @bgadrian (830001) +GitHub User @bontequero (2674999) +GitHub User @cch123 (384546) +GitHub User @chanxuehong (3416908) +GitHub User @erifan (31343225) +GitHub User @Kropekk (13366453) +GitHub User @madiganz (18340029) +GitHub User @pityonline (438222) +GitHub User @pytimer (17105586) +GitHub User @shogo-ma (9860598) Giulio Iotti Gleb Stepanov Glenn Brown @@ -575,8 +661,10 @@ Graham Miller Grant Griffiths Greg Poirier Greg Ward +Grégoire Delattre Gregory Man Guilherme Garnier +Guilherme Goncalves Guilherme Rezende Guillaume J. Charmes Guobiao Mei @@ -589,9 +677,11 @@ Gyu-Ho Lee H. İbrahim Güngör Hajime Hoshi Hallgrimur Gunnarsson +HAMANO Tsukasa Han-Wen Nienhuys Hang Qian Hanjun Kim +Harald Nordgren Hari haran Hariharan Srinath Harley Laue @@ -599,6 +689,7 @@ Harry Moreno Harshavardhana Hauke Löffler Håvard Haugen +He Liu Hector Chu Hector Martin Cantero Henning Schmiedehausen @@ -607,6 +698,7 @@ Henrik Hodne Henry Adi Sumarto Henry Bubert Henry Chang +Henry Clifford Herbert Georg Fischer Herbie Ong Heschi Kreinick @@ -624,6 +716,7 @@ Hsin-Ho Yeh Hu Keping Hugues Bruant Hyang-Ah Hana Kim +Ian Cottrell Ian Gudger Ian Kent Ian Lance Taylor @@ -637,23 +730,31 @@ Igor Vashyst Ilya Tocar INADA Naoki Inanc Gumus +Ingo Gottwald Ingo Krabbe Ingo Oeser +Ioannis Georgoulas +Irfan Sharif Irieda Noboru +Isaac Ardis Isaac Wagner Iskander Sharipov +Issac Trotts Ivan Babrou Ivan Bertona Ivan Krasin +Ivan Markin Ivan Moscoso Ivan Ukhov Jaana Burcu Dogan +Jack Britton Jack Lindamood Jacob Baskin Jacob H. Haven Jacob Hoffman-Andrews Jae Kwon Jakob Borg +Jakob Weisblat Jakub Čajka Jakub Ryszard Czarnowicz James Aguilar @@ -689,12 +790,15 @@ Jamil Djadala Jan Berktold Jan H. Hosang Jan Kratochvil +Jan Lehnardt Jan Mercl <0xjnml@gmail.com> Jan Newmarch +Jan Pilzer Jan Ziak <0xe2.0x9a.0x9b@gmail.com> Jani Monoses Jared Culp Jaroslavas Počepko +Jason A. Donenfeld Jason Barnett Jason Buberel Jason Chu @@ -703,16 +807,21 @@ Jason Hall Jason Smale Jason Travis Jason Wangsadinata +Javier Kohen Javier Segura Jay Conrod Jay Weisskopf +Jean de Klerk +Jean-André Santoni Jean-Francois Cantin Jean-Marc Eurin Jean-Nicolas Moal Jed Denlea Jeet Parekh +Jeevanandam M Jeff (Zhefu) Jiang Jeff Craig +Jeff Dupont Jeff Hodges Jeff Johnson Jeff R. Allen @@ -725,14 +834,17 @@ Jeremiah Harmsen Jeremy Jackins Jeremy Schlatter Jeroen Bobbeldijk +Jerrin Shaji George Jess Frazelle Jesse Szwedko +Jesús Espino Jianing Yu Jianqiao Li Jihyun Yu Jim Cote Jim Kingdon Jim McGrath +Jim Minter Jimmy Frasche Jimmy Zelinskie Jin-wook Jeong @@ -742,16 +854,17 @@ Jiong Du Jirka Daněk Jiulong Wang Joakim Sernbrant +Joe Cortopassi Joe Farrell Joe Harrison Joe Henke Joe Kyo Joe Poirier -Joe Richey joerichey@google.com +Joe Richey Joe Shaw Joe Sylve Joe Tsai -Joel Sing +Joel Sing Joël Stemmer Joel Stemmer Joey Geiger @@ -763,10 +876,12 @@ John Beisley John C Barstow John DeNero John Dethridge +John Gibb John Graham-Cumming John Howard Palevich John Jeffery John Jenkins +John Leidegren John Newlin John Potocny John R. Lenton @@ -775,14 +890,17 @@ John Shahid John Tuley Johnny Luo Jon Chen +Jonas Bernoulli Jonathan Allie Jonathan Amsterdam Jonathan Boulle +Jonathan Chen Jonathan Feinberg Jonathan Gold Jonathan Hseu Jonathan Mark Jonathan Nieder +Jonathan Pentecost Jonathan Pittman Jonathan Rudenberg Jonathan Stacks @@ -803,6 +921,7 @@ Josh Goebel Josh Hoak Josh Holland Josh Roppo +Josh Varga Joshua Boelter Joshua Chase Joshua Rubin @@ -817,11 +936,14 @@ Julia Hansbrough Julian Kornberger Julian Pastarmov Julian Phillips +Julien Salleyron Julien Schmidt Julio Montes +Junda Liu Jungho Ahn Junya Hayashi Jure Ham +Justin Gracenin Justin Nuß Justyn Temme Kai Backman @@ -831,6 +953,7 @@ Kaleb Elwert Kamal Aboul-Hosn Kamil Chmielewski Kamil Kisiel +Kamil Rytarowski Kang Hu Karan Dhiman Karel Pazdera @@ -869,6 +992,7 @@ Kevin Vu Kieran Colford Kim Shrier Kim Yongbin +Kir Kolyshkin Kirill Smelkov Kirk Han Kirklin McDonald @@ -878,24 +1002,29 @@ Koichi Shiraishi Koki Ide Konstantin Konstantin Shaposhnikov +Kris Kwiatkowski Kris Nova Kris Rousey Kristopher Watts Kun Li Kunpei Sakai +Kuntal Majumder Kyle Consalus Kyle Isom Kyle Jones Kyle Lemons Kyle Shannon +Kyle Spiers Kyohei Kadota Kyrylo Silin L Campbell Lai Jiangshan Lakshay Garg Lann Martin +Lanre Adelowo Larry Hosken Lars Jeppesen +Lars Lehtonen Lars Wiegman Larz Conwell Laurent Voisin @@ -903,9 +1032,12 @@ Laurie Clark-Michalek LE Manh Cuong Lee Hinman Lee Packham +Lehner Florian Leigh McCulloch +Leo Antunes Leo Rudberg Leon Klingele +Leonel Quinteros Lev Shamardin Lewin Bormann Lion Yang @@ -915,6 +1047,7 @@ Lorenzo Masini Lorenzo Stoakes Louis Kruger Luan Santos +Lubomir I. Ivanov Luca Bruno Luca Greco Lucas Bremgartner @@ -933,11 +1066,13 @@ Luuk van Dijk Lyle Franklin Lynn Boger Ma Peiqi +Maciej Dębski Magnus Hiie Maicon Costa Maksym Trykur Mal Curtis Manfred Touron +Manigandan Dharmalingam Manish Goregaokar Manoj Dayaram Mansour Rahimi @@ -948,16 +1083,19 @@ Marc Weistroff Marc-Antoine Ruel Marcel Edmund Franke Marcel van Lohuizen +Marcelo Cantos Marcelo E. Magallon Marco Hennings Marga Manterola Marin Bašić +Mario Arranz Marius Nuennerich Mark Adams Mark Bucciarelli Mark Harrison Mark Percival Mark Pulford +Mark Rushakoff Mark Ryan Mark Severson Mark Theunissen @@ -976,12 +1114,14 @@ Martin Habbecke Martin Hamrle Martin Hoefling Martin Kreichgauer +Martin Kunc Martin Lindhe Martin Möhrmann Martin Neubauer Martin Olsen Martin Olsson Martin Probst +Martin Sucha Martins Sipenko Martynas Budriūnas Marvin Stenger @@ -991,6 +1131,7 @@ Masahiro Furudate Masahiro Wakame Masaki Yoshida Mat Byczkowski +Mat Ryer Máté Gulyás Matej Baćo Mateus Amin @@ -1010,6 +1151,7 @@ Matt Harden Matt Jibson Matt Joiner Matt Jones +Matt Juran Matt Layher Matt Reiferson Matt Robenolt @@ -1042,13 +1184,16 @@ Micah Stetson Michael Brandenburg Michael Chaten Michael Darakananda +Michael Dorner Michael Edwards Michael Elkins Michael Fraenkel +Michael Fromberger Michael Gehring Michael Hendricks Michael Hoisie Michael Hudson-Doyle +Michael Kasch Michael Käufl Michael Kelly Michael Lewis @@ -1058,7 +1203,7 @@ Michael Matloob Michael McConville Michael McGreevy Michael McLoughlin -Michael Munday +Michael Munday Michael Pearson Michael Piatek Michael Pratt @@ -1073,6 +1218,7 @@ Michael Vetter Michal Bohuslávek Michal Cierniak Michał Derkacz +Michal Franc Michal Pristas Michalis Kargakis Michel Lespinasse @@ -1086,20 +1232,26 @@ Mike Andrews Mike Appleby Mike Danese Mike Houston +Mike Kabischev Mike Rosset Mike Samuel Mike Solomon Mike Strosaker +Mike Tsao Mike Wiacek Mikhail Gusarov Mikhail Panchenko Miki Tebeka Mikio Hara Mikkel Krautz +Milan Knezevic Milutin Jovanović +MinJae Kwon Miquel Sabaté Solà Miroslav Genov +Misty De Meo Mohit Agarwal +Mohit kumar Bajoria Momchil Velikov Monis Khan Monty Taylor @@ -1113,6 +1265,8 @@ Muhammed Uluyol Mura Li Nan Deng Naoki Kanatani +Nate Wilkinson +Nathan Cantelmo Nathan Caza Nathan Humphreys Nathan John Youngman @@ -1122,9 +1276,11 @@ Nathan VanBenschoten Nathan Youngman Nathan(yinian) Hu Nathaniel Cook +Naveen Kumar Sangi Neelesh Chandola Neil Lyons Neuman Vong +Neven Sajko Nevins Bartolomeo Niall Sheridan Nic Day @@ -1142,22 +1298,27 @@ Nick Miyake Nick Patavalis Nick Petroni Nick Robinson +Nick Smolin Nicolas BRULEZ Nicolas Kaiser Nicolas Owens Nicolas S. Dade +Niek Sanders Niels Widger Nigel Kerr Nigel Tao Nik Nyby +Nikhil Benesch Niklas Schnelle Niko Dziemba Nikolay Turpitko Nils Larsgård Niranjan Godbole +Nishanth Shanmugham Noah Campbell Noble Johnson Nodir Turakulov +Noel Georgi Norberto Lopes Odin Ugedal Oleg Bulatov @@ -1173,8 +1334,10 @@ Olivier Saingre Omar Jarjur Özgür Kesim Pablo Lalloni +Pablo Rozas Larraondo Pablo Santiago Blum de Aguiar Padraig Kitterick +Pallat Anchaleechamaikorn Paolo Giarrusso Paolo Martini Parker Moore @@ -1206,6 +1369,7 @@ Paul Rosania Paul Ruest Paul Sbarra Paul Smith +Paul Tyng Paul van Brouwershaven Paul Wankadia Paulo Casaretto @@ -1221,6 +1385,7 @@ Petar Maymounkov Peter Armitage Peter Bourgon Peter Collingbourne +Peter Conerly Peter Froehlich Peter Gonda Peter Kleiweg @@ -1232,22 +1397,30 @@ Peter Nguyen Péter Surányi Péter Szabó Péter Szilágyi +Peter Teichman Peter Tseng Peter Waldschmidt Peter Waller Peter Weinberger Peter Williams Peter Wu +Peter Zhang Petrica Voicu +Phil Pearl Phil Pennock Philip Børgesen +Philip Brown Philip Hofer Philip K. Warren +Philip Nelson +Philipp Stephani Pierre Durand +Pierre Prinetti Pierre Roullon Piers Pieter Droogendijk Pietro Gagliardi +Piyush Mishra Pontus Leitzler Prasanna Swaminathan Prashant Varanasi @@ -1275,6 +1448,7 @@ Ramesh Dharan Raph Levien Raphael Geronimi Raul Silvera +Ravil Bikbulatov RaviTeja Pothana Ray Tung Raymond Kazlauskas @@ -1283,6 +1457,7 @@ Reilly Watson Reinaldo de Souza Jr Remi Gillig Rémy Oudompheng +Rens Rikkerink Rhys Hiltner Ricardo Padilha Richard Barnes @@ -1301,7 +1476,7 @@ Rob Earhart Rob Norman Rob Phoenix Rob Pike -Robert Daniel Kortschak +Robert Daniel Kortschak Robert Dinu Robert Figueiredo Robert Griesemer @@ -1311,7 +1486,10 @@ Robert Obryk Robert Sesek Robert Snedegar Robert Stepanek +Robert-André Mauchin +Roberto Clapis Robin Eklind +Rodolfo Carvalho Rodrigo Moraes de Oliveira Rodrigo Rafael Monti Kochenburger Roger Pau Monné @@ -1322,6 +1500,7 @@ Ron Hashimoto Ron Minnich Ross Chater Ross Light +Rowan Marshall Rowan Worth Rudi Kramer Rui Ueyama @@ -1331,14 +1510,19 @@ Ryan Bagwell Ryan Barrett Ryan Boehning Ryan Brown +Ryan Canty Ryan Hitchman Ryan Lower +Ryan Roden-Corrent Ryan Seys Ryan Slade +Ryan Zhang Ryoichi KATO Ryuji Iwata +Ryuma Yoshida Ryuzo Yamamoto S.Çağlar Onur +Sabin Mihai Rapan Sai Cheemalapati Sakeven Jiang Salmān Aljammāz @@ -1349,6 +1533,7 @@ Sam Thorogood Sam Whited Sameer Ajmani Sami Commerot +Sami Pönkänen Samuel Tan Samuele Pedroni Sanjay Menakuru @@ -1377,19 +1562,24 @@ Sergei Skorobogatov Sergey 'SnakE' Gromov Sergey Arseev Sergey Frolov +Sergey Lukjanov Sergey Mishin +Sergey Mudrik Sergey Semin Sergio Luis O. B. Correia Sergiusz Bazanski Seth Hoenig Seth Vargo Shahar Kohanim +Shamil Garatuev Shane Hansen Shaozhen Ding +Shaun Dunning Shawn Ledbetter Shawn Smith Shawn Walker-Salas Shenghou Ma +Shengyu Zhang Shi Han Ng Shinji Tanaka Shintaro Kaneko @@ -1411,8 +1601,12 @@ Sridhar Venkatakrishnan StalkR Stan Schwertly Stanislav Afanasev +Steeve Morin Stefan Nilsson +Stephan Renatus Stéphane Travostino +Stephen Lewis +Stephen Lu Stephen Ma Stephen McQuay Stephen Searles @@ -1432,6 +1626,7 @@ Sugu Sougoumarane Suharsh Sivakumar Sukrit Handa Sunny +Suriyaa Sundararuban Suyash Suzy Mueller Sven Almgren @@ -1443,6 +1638,7 @@ Tad Fisher Tad Glines Taj Khattra Takashi Matsuo +Takayoshi Nishida Takeshi YAMANASHI <9.nashi@gmail.com> Takuto Ikuta Takuya Ueda @@ -1453,24 +1649,30 @@ Tarmigan Casebolt Taro Aoki Taru Karttunen Tatsuhiro Tsujikawa +Teague Cole Ted Kornish +Tejasvi Nareddy Terin Stock Terrel Shumway Tetsuo Kiso Than McIntosh +Thanabodee Charoenpiriyakij Thanatat Tamtan Thiago Avelino Thiago Fransosi Farina Thomas Alan Copeland Thomas Bonfort Thomas Bouldin +Thomas Bruyelle Thomas de Zeeuw Thomas Desrosiers Thomas Habets Thomas Kappler +Thomas Meson Thomas Wanielista Thorben Krueger Thordur Bjornsson +Tiago Queiroz Tilman Dilo Tim Cooijmans Tim Cooper @@ -1494,16 +1696,21 @@ Tom Bergan Tom Heng Tom Lanyon Tom Levy +Tom Limoncelli Tom Linford +Tom Payne Tom Szymanski +Tom Thorogood Tom Wilkie Tommy Schaefer +Tomoya Ishizaki Tonis Tiigi Tony Walker Tor Andersson Tormod Erevik Lea Toshiki Shima Totoro W +Travis Bischel Travis Cline Trevor Strohman Trey Lawrence @@ -1512,6 +1719,7 @@ Trey Tacon Tristan Amini Tristan Colgate Tristan Ooohry +Tristan Rice Troels Thomsen Trung Nguyen Tudor Golubenco @@ -1528,9 +1736,13 @@ Uriel Mangado Uttam C Pawar Vadim Grek Vadim Vygonets +Val Polouchkine Vega Garcia Luis Alfonso +Venil Noronha +Veselkov Konstantin Victor Chudnovsky Victor Vrantchan +Vignesh Ramachandra Vikas Kedia Vincent Ambo Vincent Batts @@ -1540,27 +1752,33 @@ Vish Subramanian Vishvananda Ishaya Vitor De Mario Vlad Krasnov +Vladimir Kuzmin Vladimir Mihailenco Vladimir Nikishenko Vladimir Stefanovic Vladimir Varankin Volker Dobler Volodymyr Paprotski +W. Trevor King Wade Simmons Walter Poupore Wander Lairson Costa +Wayne Ashley Berry Wedson Almeida Filho Wèi Cōngruì +Wei Fu Wei Guangjing Wei Xiao Weichao Tang Wembley G. Leach, Jr +Wilfried Teiken Will Chan Will Faught Will Norris Will Storey Willem van der Schyff William Chan +William Chang William Josephson William Orr Wisdom Omuya @@ -1570,14 +1788,20 @@ Xia Bin Xing Xing Xu Fei Xudong Zhang +Xudong Zheng <7pkvm5aw@slicealias.com> Xuyang Kang +Yamagishi Kazutoshi Yan Zou +Yann Hodique Yann Kerhervé Yann Salaün Yao Zhang +Yaron de Leeuw Yasha Bubnov Yasuharu Goto Yasuhiro Matsumoto +Yasuyuki Oka +Yazen Shunnar Yestin Sun Yesudeep Mangalapilly Yissakhar Z. Beck @@ -1585,11 +1809,14 @@ Yo-An Lin Yongjian Xu Yorman Arias Yoshiyuki Kanno +Yoshiyuki Mineo Yosuke Akatsuka Yu Heng Zhang Yu Xuan Zhang +Yuji Yaginuma Yuki Yugui Sonoda Yukihiro Nishinaka <6elpinal@gmail.com> +Yury Smolsky Yusuke Kagiwada Yuusei Kuwana Yuval Pavel Zholkover @@ -1597,13 +1824,17 @@ Yves Junqueira Zac Bergquist Zach Bintliff Zach Gershman +Zachary Gershman Zak Zakatell Kanda Zellyn Hunter Zev Goldstein +Zheng Dayu Zhengyu He +Zhongpeng Lin Zhongtao Chen Zhongwei Yao +Zhou Peng Ziad Hatahet Zorion Arrizabalaga Максим Федосеев diff --git a/api/except.txt b/api/except.txt index e104f8e17b..850724196d 100644 --- a/api/except.txt +++ b/api/except.txt @@ -362,17 +362,21 @@ pkg syscall (openbsd-386-cgo), const SYS_KILL = 37 pkg syscall (openbsd-amd64), const SYS_KILL = 37 pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37 pkg unicode, const Version = "9.0.0" +pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr pkg syscall (windows-386), type CertContext struct, CertInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr -pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-386), type RawSockaddrAny struct, Pad [96]int8 +pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-amd64), type AddrinfoW struct, Addr uintptr pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr pkg syscall (windows-amd64), type CertContext struct, CertInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr -pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295 +pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8 diff --git a/api/go1.11.txt b/api/go1.11.txt index d474cf0e8d..863e1f1625 100644 --- a/api/go1.11.txt +++ b/api/go1.11.txt @@ -1,7 +1,7 @@ pkg crypto/cipher, func NewGCMWithTagSize(Block, int) (AEAD, error) pkg crypto/rsa, method (*PrivateKey) Size() int pkg crypto/rsa, method (*PublicKey) Size() int -pkg crypto/tls, type ConnectionState struct, ExportKeyingMaterial func(string, []uint8, int) ([]uint8, bool) +pkg crypto/tls, method (*ConnectionState) ExportKeyingMaterial(string, []uint8, int) ([]uint8, error) pkg database/sql, method (IsolationLevel) String() string pkg database/sql, type DBStats struct, Idle int pkg database/sql, type DBStats struct, InUse int @@ -445,9 +445,20 @@ pkg net, method (*ListenConfig) ListenPacket(context.Context, string, string) (P pkg net, type Dialer struct, Control func(string, string, syscall.RawConn) error pkg net, type ListenConfig struct pkg net, type ListenConfig struct, Control func(string, string, syscall.RawConn) error +pkg net/http, const SameSiteDefaultMode = 1 +pkg net/http, const SameSiteDefaultMode SameSite +pkg net/http, const SameSiteLaxMode = 2 +pkg net/http, const SameSiteLaxMode SameSite +pkg net/http, const SameSiteStrictMode = 3 +pkg net/http, const SameSiteStrictMode SameSite pkg net/http, const StatusMisdirectedRequest = 421 pkg net/http, const StatusMisdirectedRequest ideal-int +pkg net/http, type Cookie struct, SameSite SameSite +pkg net/http, type SameSite int +pkg net/http, type Transport struct, MaxConnsPerHost int pkg net/http/httptrace, type ClientTrace struct, Got1xxResponse func(int, textproto.MIMEHeader) error +pkg net/http/httptrace, type ClientTrace struct, WroteHeaderField func(string, []string) +pkg net/http/httputil, type ReverseProxy struct, ErrorHandler func(http.ResponseWriter, *http.Request, error) pkg os, const ModeIrregular = 524288 pkg os, const ModeIrregular FileMode pkg os, const ModeType = 2399666176 @@ -519,6 +530,7 @@ pkg syscall (openbsd-amd64-cgo), func Pipe2([]int, int) error pkg syscall (windows-386), const TOKEN_ADJUST_SESSIONID = 256 pkg syscall (windows-386), const TOKEN_ADJUST_SESSIONID ideal-int pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983551 +pkg syscall (windows-386), type AddrinfoW struct, Addr Pointer pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara Pointer pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus Pointer pkg syscall (windows-386), type CertContext struct, CertInfo *CertInfo @@ -532,6 +544,7 @@ pkg syscall (windows-386), type Pointer *struct pkg syscall (windows-amd64), const TOKEN_ADJUST_SESSIONID = 256 pkg syscall (windows-amd64), const TOKEN_ADJUST_SESSIONID ideal-int pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983551 +pkg syscall (windows-amd64), type AddrinfoW struct, Addr Pointer pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara Pointer pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus Pointer pkg syscall (windows-amd64), type CertContext struct, CertInfo *CertInfo diff --git a/doc/code.html b/doc/code.html index 4e8c54a1c5..b6d41ef68c 100644 --- a/doc/code.html +++ b/doc/code.html @@ -44,18 +44,16 @@ control repositories.

Workspaces

-A workspace is a directory hierarchy with three directories at its root: +A workspace is a directory hierarchy with two directories at its root:

    -
  • src contains Go source files, -
  • pkg contains package objects, and +
  • src contains Go source files, and
  • bin contains executable commands.

-The go tool builds source packages and installs the resulting -binaries to the pkg and bin directories. +The go tool builds and installs binaries to the bin directory.

@@ -72,10 +70,6 @@ To give you an idea of how a workspace looks in practice, here's an example: bin/ hello # command executable outyet # command executable -pkg/ - linux_amd64/ - github.com/golang/example/ - stringutil.a # package object src/ github.com/golang/example/ .git/ # Git repository metadata @@ -374,9 +368,8 @@ $ go build

-This won't produce an output file. To do that, you must use go -install, which places the package object inside the pkg -directory of the workspace. +This won't produce an output file. +Instead it saves the compiled package in the local build cache.

@@ -400,19 +393,13 @@ func main() {

-Whenever the go tool installs a package or binary, it also -installs whatever dependencies it has. -So when you install the hello program +Install the hello program:

 $ go install github.com/user/hello
 
-

-the stringutil package will be installed as well, automatically. -

-

Running the new version of the program, you should see a new, reversed message:

@@ -429,10 +416,6 @@ After the steps above, your workspace should look like this:
 bin/
     hello                 # command executable
-pkg/
-    linux_amd64/          # this will reflect your OS and architecture
-        github.com/user/
-            stringutil.a  # package object
 src/
     github.com/user/
         hello/
@@ -441,22 +424,6 @@ src/
             reverse.go    # package source
 
-

-Note that go install placed the stringutil.a object -in a directory inside pkg/linux_amd64 that mirrors its source -directory. -This is so that future invocations of the go tool can find the -package object and avoid recompiling the package unnecessarily. -The linux_amd64 part is there to aid in cross-compilation, -and will reflect the operating system and architecture of your system. -

- -

-Go command executables are statically linked; the package objects need not -be present to run Go programs. -

- -

Package names

@@ -597,12 +564,6 @@ tree should now look like this:

 bin/
     hello                           # command executable
-pkg/
-    linux_amd64/
-        github.com/golang/example/
-            stringutil.a            # package object
-        github.com/user/
-            stringutil.a            # package object
 src/
     github.com/golang/example/
 	.git/                       # Git repository metadata
diff --git a/doc/contribute.html b/doc/contribute.html
index 388016fac0..2068ab8a3e 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -73,7 +73,7 @@ $ go-contrib-init
 

The rest of this chapter elaborates on these instructions. If you have completed the steps above (either manually or through the tool), jump to -Making a change. +Before contributing code.

Step 0: Select a Google Account

@@ -292,6 +292,25 @@ Most issues will be marked with one of the following workflow labels: +

+You can use GitHub's search functionality to find issues to help out with. Examples: +

+ + +

Open an issue for any new problem

@@ -386,7 +405,7 @@ This is an overview of the overall process:

  • -Step 1: Clone the Go source code from go.googlesource.com +Step 1: Clone the Go source code from go.googlesource.com and make sure it's stable by compiling and testing it once:
     $ git clone https://go.googlesource.com/go
    @@ -450,12 +469,11 @@ In addition to a recent Go installation, you need to have a local copy of the so
     checked out from the correct repository.
     You can check out the Go source repo onto your local file system anywhere
     you want as long as it's outside your GOPATH.
    -Either clone from
    -go.googlesource.com or from GitHub:
    +Clone from go.googlesource.com (not GitHub):
     

    -$ git clone https://github.com/golang/go   # or https://go.googlesource.com/go
    +$ git clone https://go.googlesource.com/go
     $ cd go
     
    @@ -678,7 +696,7 @@ Don't use HTML, Markdown, or any other markup language.

    Add any relevant information, such as benchmark data if the change affects performance. -The benchcmp +The benchstat tool is conventionally used to format benchmark data for change descriptions.

    diff --git a/doc/devel/release.html b/doc/devel/release.html index 584340b005..a6dd5f9d28 100644 --- a/doc/devel/release.html +++ b/doc/devel/release.html @@ -23,6 +23,13 @@ in supported releases as needed by issuing minor revisions (for example, Go 1.6.1, Go 1.6.2, and so on).

    +

    go1.11 (released 2018/08/24)

    + +

    +Go 1.11 is a major release of Go. +Read the Go 1.11 Release Notes for more information. +

    +

    go1.10 (released 2018/02/16)

    @@ -57,6 +64,14 @@ See the Go 1.10.3 milestone on our issue tracker for details.

    +

    +go1.10.4 (released 2018/08/24) includes fixes to the go command, linker, and the +net/http, mime/multipart, ld/macho, +bytes, and strings packages. +See the Go +1.10.4 milestone on our issue tracker for details. +

    +

    go1.9 (released 2017/08/24)

    diff --git a/doc/go1.11.html b/doc/go1.11.html index 9aef342a43..afe1939766 100644 --- a/doc/go1.11.html +++ b/doc/go1.11.html @@ -15,14 +15,7 @@ Do not send CLs removing the interior tags from such phrases. ul li { margin: 0.5em 0; } -

    DRAFT RELEASE NOTES - Introduction to Go 1.11

    - -

    - - Go 1.11 is not yet released. These are work-in-progress - release notes. Go 1.11 is expected to be released in August 2018. - -

    +

    Introduction to Go 1.11

    The latest Go release, version 1.11, arrives six months after Go 1.10. @@ -39,10 +32,15 @@ Do not send CLs removing the interior tags from such phrases.

    Ports

    -

    +

    As announced in the Go 1.10 release notes, Go 1.11 now requires OpenBSD 6.2 or later, macOS 10.10 Yosemite or later, or Windows 7 or later; - Support for previous versions of these operating systems has been removed. + support for previous versions of these operating systems has been removed. +

    + +

    + Go 1.11 supports the upcoming OpenBSD 6.4 release. Due to changes in + the OpenBSD kernel, older versions of Go will not work on OpenBSD 6.4.

    @@ -50,21 +48,400 @@ Do not send CLs removing the interior tags from such phrases.

    - TODO: PPC64LE race detector support + The race detector is now supported on linux/ppc64le + and, to a lesser extent, on netbsd/amd64. The NetBSD race detector support + has known issues.

    -

    Package Versioning (vgo)

    -

    - - NOTE: This is not present in go1.11beta1 but will be available in future - betas and subsequent releases. - - Go 1.11 adds experimental, integrated support for package versioning. +

    + The memory sanitizer (-msan) is now supported on linux/arm64. +

    + +

    + The build modes c-shared and c-archive are now supported on + freebsd/amd64. +

    + +

    + On 64-bit MIPS systems, the new environment variable settings + GOMIPS64=hardfloat (the default) and + GOMIPS64=softfloat select whether to use + hardware instructions or software emulation for floating-point computations. + For 32-bit systems, the environment variable is still GOMIPS, + as added in Go 1.10. +

    + +

    + On soft-float ARM systems (GOARM=5), Go now uses a more + efficient software floating point interface. This is transparent to + Go code, but ARM assembly that uses floating-point instructions not + guarded on GOARM will break and must be ported to + the new interface. +

    + +

    + Go 1.11 on ARMv7 no longer requires a Linux kernel configured + with KUSER_HELPERS. This setting is enabled in default + kernel configurations, but is sometimes disabled in stripped-down + configurations.

    WebAssembly

    - Go 1.11 adds an experimental port to WebAssembly (js/wasm). + Go 1.11 adds an experimental port to WebAssembly + (js/wasm). +

    +

    + Go programs currently compile to one WebAssembly module that + includes the Go runtime for goroutine scheduling, garbage + collection, maps, etc. + As a result, the resulting size is at minimum around + 2 MB, or 500 KB compressed. Go programs can call into JavaScript + using the new experimental + syscall/js package. + Binary size and interop with other languages has not yet been a + priority but may be addressed in future releases. +

    +

    + As a result of the addition of the new GOOS value + "js" and GOARCH value "wasm", + Go files named *_js.go or *_wasm.go will + now be ignored by Go + tools except when those GOOS/GOARCH values are being used. + If you have existing filenames matching those patterns, you will need to rename them. +

    +

    + More information can be found on the + WebAssembly wiki page. +

    + +

    RISC-V GOARCH values reserved

    +

    + The main Go compiler does not yet support the RISC-V architecture + but we've reserved the GOARCH values + "riscv" and "riscv64", as used by Gccgo, + which does support RISC-V. This means that Go files + named *_riscv.go will now also + be ignored by Go + tools except when those GOOS/GOARCH values are being used. +

    + +

    Tools

    + +

    Modules, package versioning, and dependency management

    +

    + Go 1.11 adds preliminary support for a new concept called “modules,” + an alternative to GOPATH with integrated support for versioning and + package distribution. + Using modules, developers are no longer confined to working inside GOPATH, + version dependency information is explicit yet lightweight, + and builds are more reliable and reproducible. +

    + +

    + Module support is considered experimental. + Details are likely to change in response to feedback from Go 1.11 users, + and we have more tools planned. + Although the details of module support may change, projects that convert + to modules using Go 1.11 will continue to work with Go 1.12 and later. + If you encounter bugs using modules, + please file issues + so we can fix them. For more information, see the + go command documentation. +

    + +

    Import path restriction

    + +

    + Because Go module support assigns special meaning to the + @ symbol in command line operations, + the go command now disallows the use of + import paths containing @ symbols. + Such import paths were never allowed by go get, + so this restriction can only affect users building + custom GOPATH trees by other means. +

    + +

    Package loading

    + +

    + The new package + golang.org/x/tools/go/packages + provides a simple API for locating and loading packages of Go source code. + Although not yet part of the standard library, for many tasks it + effectively replaces the go/build + package, whose API is unable to fully support modules. + Because it runs an external query command such as + go list + to obtain information about Go packages, it enables the construction of + analysis tools that work equally well with alternative build systems + such as Bazel + and Buck. +

    + +

    Build cache requirement

    + +

    + Go 1.11 will be the last release to support setting the environment + variable GOCACHE=off to disable the + build cache, + introduced in Go 1.10. + Starting in Go 1.12, the build cache will be required, + as a step toward eliminating $GOPATH/pkg. + The module and package loading support described above + already require that the build cache be enabled. + If you have disabled the build cache to avoid problems you encountered, + please file an issue to let us know about them. +

    + +

    Compiler toolchain

    + +

    + More functions are now eligible for inlining by default, including + functions that call panic. +

    + +

    + The compiler toolchain now supports column information + in line + directives. +

    + +

    + A new package export data format has been introduced. + This should be transparent to end users, except for speeding up + build times for large Go projects. + If it does cause problems, it can be turned off again by + passing -gcflags=all=-iexport=false to + the go tool when building a binary. +

    + +

    + The compiler now rejects unused variables declared in a type switch + guard, such as x in the following example: +

    +
    +func f(v interface{}) {
    +	switch x := v.(type) {
    +	}
    +}
    +
    +

    + This was already rejected by both gccgo + and go/types. +

    + +

    Assembler

    + +

    + The assembler for amd64 now accepts AVX512 instructions. +

    + +

    Debugging

    + +

    + The compiler now produces significantly more accurate debug + information for optimized binaries, including variable location + information, line numbers, and breakpoint locations. + + This should make it possible to debug binaries + compiled without -N -l. + + There are still limitations to the quality of the debug information, + some of which are fundamental, and some of which will continue to + improve with future releases. +

    + +

    + DWARF sections are now compressed by default because of the expanded + and more accurate debug information produced by the compiler. + + This is transparent to most ELF tools (such as debuggers on Linux + and *BSD) and is supported by the Delve debugger on all platforms, + but has limited support in the native tools on macOS and Windows. + + To disable DWARF compression, + pass -ldflags=-compressdwarf=false to + the go tool when building a binary. +

    + +

    + Go 1.11 adds experimental support for calling Go functions from + within a debugger. + + This is useful, for example, to call String methods + when paused at a breakpoint. + + This is currently only supported by Delve (version 1.1.0 and up). +

    + +

    Test

    + +

    + Since Go 1.10, the go test command runs + go vet on the package being tested, + to identify problems before running the test. Since vet + typechecks the code with go/types + before running, tests that do not typecheck will now fail. + + In particular, tests that contain an unused variable inside a + closure compiled with Go 1.10, because the Go compiler incorrectly + accepted them (Issue #3059), + but will now fail, since go/types correctly reports an + "unused variable" error in this case. +

    + +

    + The -memprofile flag + to go test now defaults to the + "allocs" profile, which records the total bytes allocated since the + test began (including garbage-collected bytes). +

    + +

    Vet

    + +

    + The go vet + command now reports a fatal error when the package under analysis + does not typecheck. Previously, a type checking error simply caused + a warning to be printed, and vet to exit with status 1. +

    + +

    + Additionally, go vet + has become more robust when format-checking printf wrappers. + Vet now detects the mistake in this example: +

    + +
    +func wrapper(s string, args ...interface{}) {
    +	fmt.Printf(s, args...)
    +}
    +
    +func main() {
    +	wrapper("%s", 42)
    +}
    +
    + +

    Trace

    + +

    + With the new runtime/trace + package's user + annotation API, users can record application-level information + in execution traces and create groups of related goroutines. + The go tool trace + command visualizes this information in the trace view and the new + user task/region analysis page. +

    + +

    Cgo

    + +

    +Since Go 1.10, cgo has translated some C pointer types to the Go +type uintptr. These types include +the CFTypeRef hierarchy in Darwin's CoreFoundation +framework and the jobject hierarchy in Java's JNI +interface. In Go 1.11, several improvements have been made to the code +that detects these types. Code that uses these types may need some +updating. See the Go 1.10 release notes for +details. +

    + +

    Godoc

    + +

    + Go 1.11 will be the last release to support godoc's command-line interface. + In future releases, godoc will only be a web server. Users should use + go doc for command-line help output instead. +

    + +

    + The godoc web server now shows which version of Go introduced + new API features. The initial Go version of types, funcs, and methods are shown + right-aligned. For example, see UserCacheDir, with "1.11" + on the right side. For struct fields, inline comments are added when the struct field was + added in a Go version other than when the type itself was introduced. + For a struct field example, see + ClientTrace.Got1xxResponse. +

    + +

    Gofmt

    + +

    + One minor detail of the default formatting of Go source code has changed. + When formatting expression lists with inline comments, the comments were + aligned according to a heuristic. + However, in some cases the alignment would be split up too easily, or + introduce too much whitespace. + The heuristic has been changed to behave better for human-written code. +

    + +

    + Note that these kinds of minor updates to gofmt are expected from time to + time. + In general, systems that need consistent formatting of Go source code should + use a specific version of the gofmt binary. + See the go/format package documentation for more + information. +

    + +

    Runtime

    + +

    + The runtime now uses a sparse heap layout so there is no longer a + limit to the size of the Go heap (previously, the limit was 512GiB). + This also fixes rare "address space conflict" failures in mixed Go/C + binaries or binaries compiled with -race. +

    + +

    + On macOS and iOS, the runtime now uses libSystem.dylib instead of + calling the kernel directly. This should make Go binaries more + compatible with future versions of macOS and iOS. + The syscall package still makes direct + system calls; fixing this is planned for a future release. +

    + +

    Performance

    + +

    +As always, the changes are so general and varied that precise +statements about performance are difficult to make. Most programs +should run a bit faster, due to better generated code and +optimizations in the core library. +

    + +

    +There were multiple performance changes to the math/big +package as well as many changes across the tree specific to GOARCH=arm64. +

    + +

    Compiler toolchain

    + +

    + The compiler now optimizes map clearing operations of the form: +

    +
    +for k := range m {
    +	delete(m, k)
    +}
    +
    + +

    + The compiler now optimizes slice extension of the form + append(s, make([]T, n)...). +

    + +

    + The compiler now performs significantly more aggressive bounds-check + and branch elimination. Notably, it now recognizes transitive + relations, so if i<j and j<len(s), + it can use these facts to eliminate the bounds check + for s[i]. It also understands simple arithmetic such + as s[i-10] and can recognize more inductive cases in + loops. Furthermore, the compiler now uses bounds information to more + aggressively optimize shift operations.

    Core library

    @@ -81,34 +458,19 @@ Do not send CLs removing the interior tags from such phrases. in mind.

    - - - - - + - -
    all
    -
    -

    - TODO: https://golang.org/cl/93875: enable c-shared/c-archive support for freebsd/amd64 -

    -

    - TODO: https://golang.org/cl/94255: drop support for Windows Vista or below (Windows XP) -

    - -

    - TODO: https://golang.org/cl/115038: remove support for macOS 10.9 and earlier -

    - -
    crypto

    - TODO: https://golang.org/cl/64451: randomly read an extra byte of randomness in some places. + Certain crypto operations, including + ecdsa.Sign, + rsa.EncryptPKCS1v15 and + rsa.GenerateKey, + now randomly read an extra byte of randomness to ensure tests don't rely on internal behavior.

    @@ -116,7 +478,8 @@ Do not send CLs removing the interior tags from such phrases.
    crypto/cipher

    - TODO: https://golang.org/cl/48510: add NewGCMWithTagSize for custom tag sizes. + The new function NewGCMWithTagSize + implements Galois Counter Mode with non-standard tag lengths for compatibility with existing cryptosystems.

    @@ -124,15 +487,55 @@ Do not send CLs removing the interior tags from such phrases.
    crypto/rsa

    - TODO: https://golang.org/cl/103876: add PublicKey.Size accessor + PublicKey now implements a + Size method that + returns the modulus size in bytes.

    +
    crypto/tls
    +
    +

    + ConnectionState's new + ExportKeyingMaterial + method allows exporting keying material bound to the + connection according to RFC 5705. +

    + +
    + +
    crypto/x509
    +
    +

    + The deprecated, legacy behavior of treating the CommonName field as + a hostname when no Subject Alternative Names are present is now disabled when the CN is not a + valid hostname. + The CommonName can be completely ignored by adding the experimental value + x509ignoreCN=1 to the GODEBUG environment variable. + When the CN is ignored, certificates without SANs validate under chains with name constraints + instead of returning NameConstraintsWithoutSANs. +

    + +

    + Extended key usage restrictions are again checked only if they appear in the KeyUsages + field of VerifyOptions, instead of always being checked. + This matches the behavior of Go 1.9 and earlier. +

    + +

    + The value returned by SystemCertPool + is now cached and might not reflect system changes between invocations. +

    + +
    +
    debug/elf

    - TODO: https://golang.org/cl/112115: add machine and OSABI constants + More ELFOSABI + and EM + constants have been added.

    @@ -140,7 +543,8 @@ Do not send CLs removing the interior tags from such phrases.
    encoding/asn1

    - TODO: https://golang.org/cl/110561: allow Marshaling and Unmarshaling private tag class + Marshal and Unmarshal + now support "private" class annotations for fields.

    @@ -148,7 +552,10 @@ Do not send CLs removing the interior tags from such phrases.
    encoding/base32

    - TODO: https://golang.org/cl/112516: handle surplus padding consistently + The decoder now consistently + returns io.ErrUnexpectedEOF for an incomplete + chunk. Previously it would return io.EOF in some + cases.

    @@ -156,23 +563,34 @@ Do not send CLs removing the interior tags from such phrases.
    encoding/csv

    - TODO: https://golang.org/cl/99696: disallow quote for use as Comma + The Reader now rejects attempts to set + the Comma + field to a double-quote character, as double-quote characters + already have a special meaning in CSV.

    -
    go/build, runtime/internal/sys
    + + +
    html/template
    -

    - TODO: https://golang.org/cl/106256: reserve RISC-V arch names +

    + The package has changed its behavior when a typed interface + value is passed to an implicit escaper function. Previously such + a value was written out as (an escaped form) + of <nil>. Now such values are ignored, just + as an untyped nil value is (and always has been) + ignored.

    -
    +
    image/gif

    - TODO: https://golang.org/cl/93076: support non-looping animated gifs (LoopCount=-1) + Non-looping animated GIFs are now supported. They are denoted by having a + LoopCount of -1.

    @@ -180,67 +598,182 @@ Do not send CLs removing the interior tags from such phrases.
    io/ioutil

    - TODO: https://golang.org/cl/105675: change TempFile prefix to a pattern + The TempFile + function now supports specifying where the random characters in + the filename are placed. If the prefix argument + includes a "*", the random string replaces the + "*". For example, a prefix argument of "myname.*.bat" will + result in a random filename such as + "myname.123456.bat". If no "*" is + included the old behavior is retained, and the random digits are + appended to the end.

    math/big
    -

    - TODO: https://golang.org/cl/74851: speed-up addMulVVW on amd64 + +

    + ModInverse now returns nil when g and n are not relatively prime. The result was previously undefined.

    +
    mime/multipart
    +
    +

    + The handling of form-data with missing/empty file names has been + restored to the behavior in Go 1.9: in the + Form for + the form-data part the value is available in + the Value field rather than the File + field. In Go releases 1.10 through 1.10.3 a form-data part with + a missing/empty file name and a non-empty "Content-Type" field + was stored in the File field. This change was a + mistake in 1.10 and has been reverted to the 1.9 behavior. +

    + +
    + +
    mime/quotedprintable
    +
    +

    + To support invalid input found in the wild, the package now + permits non-ASCII bytes but does not validate their encoding. +

    + +
    +
    net

    - TODO: https://golang.org/cl/72810: add ListenConfig, Dialer.Control to permit socket opts before listen/dial + The new ListenConfig type and the new + Dialer.Control field permit + setting socket options before accepting and creating connections, respectively.

    - TODO: https://golang.org/cl/76391: implement (*syscall.RawConn).Read/Write on Windows + The syscall.RawConn Read + and Write methods now work correctly on Windows.

    - TODO: https://golang.org/cl/107715: add support for splice(2) in (*TCPConn).ReadFrom on Linux + The net package now automatically uses the + splice system call + on Linux when copying data between TCP connections in + TCPConn.ReadFrom, as called by + io.Copy. The result is faster, more efficient TCP proxying.

    - TODO: https://golang.org/cl/108297: calling File leaves the socket in nonblocking mode + The TCPConn.File, + UDPConn.File, + UnixConn.File, + and IPConn.File + methods no longer put the returned *os.File into + blocking mode.

    net/http
    -

    - TODO: https://golang.org/cl/89275: don't sniff Content-type in Server when X-Content-Type-Options:nosniff +

    + The Transport type has a + new MaxConnsPerHost + option that permits limiting the maximum number of connections + per host.

    +

    + The Cookie type has a new + SameSite field + (of new type also named + SameSite) to represent the new cookie attribute recently supported by most browsers. + The net/http's Transport does not use the SameSite + attribute itself, but the package supports parsing and serializing the + attribute for browsers to use. +

    + +

    + It is no longer allowed to reuse a Server + after a call to + Shutdown or + Close. It was never officially supported + in the past and had often surprising behavior. Now, all future calls to the server's Serve + methods will return errors after a shutdown or close. +

    + + +

    - TODO: https://golang.org/cl/93296: add StatusMisdirectedRequest (421) + The constant StatusMisdirectedRequest is now defined for HTTP status code 421. +

    + +

    + The HTTP server will no longer cancel contexts or send on + CloseNotifier + channels upon receiving pipelined HTTP/1.1 requests. Browsers do + not use HTTP pipelining, but some clients (such as + Debian's apt) may be configured to do so. +

    + +

    + ProxyFromEnvironment, which is used by the + DefaultTransport, now + supports CIDR notation and ports in the NO_PROXY environment variable.

    +
    net/http/httputil
    +
    +

    + The + ReverseProxy + has a new + ErrorHandler + option to permit changing how errors are handled. +

    + +

    + The ReverseProxy now also passes + "TE: trailers" request headers + through to the backend, as required by the gRPC protocol. +

    + +
    +
    os

    - TODO: https://golang.org/cl/78835: add UserCacheDir + The new UserCacheDir function + returns the default root directory to use for user-specific cached data.

    - TODO: https://golang.org/cl/94856: add ModeIrregular flag + The new ModeIrregular + is a FileMode bit to represent + that a file is not a regular file, but nothing else is known about it, or that + it's not a socket, device, named pipe, symlink, or other file type for which + Go has a defined mode bit.

    - TODO: https://golang.org/cl/99337: enable symlink creation on Windows 10 + Symlink now works + for unprivileged users on Windows 10 on machines with Developer + Mode enabled.

    - TODO: https://golang.org/cl/100077: use poller when NewFile is called with a blocking descriptor. + When a non-blocking descriptor is passed + to NewFile, the + resulting *File will be kept in non-blocking + mode. This means that I/O for that *File will use + the runtime poller rather than a separate thread, and that + the SetDeadline + methods will work.

    @@ -248,7 +781,8 @@ Do not send CLs removing the interior tags from such phrases.
    os/signal

    - TODO: https://golang.org/cl/108376: add func Ignored(sig Signal) bool + The new Ignored function reports + whether a signal is currently ignored.

    @@ -256,59 +790,50 @@ Do not send CLs removing the interior tags from such phrases.
    os/user

    - TODO: https://golang.org/cl/92456: add a way to enforce pure Go implementation + The os/user package can now be built in pure Go + mode using the build tag "osusergo", + independent of the use of the environment + variable CGO_ENABLED=0. Previously the only way to use + the package's pure Go implementation was to disable cgo + support across the entire program.

    -
    runtime
    + + +
    runtime
    -

    - TODO: https://golang.org/cl/85887: use sparse mappings for the heap -

    -

    - TODO: https://golang.org/cl/94076: use native CAS and memory barrier on ARMv7 -

    - -

    - TODO: https://golang.org/cl/106156: use fixed TLS offsets on darwin/amd64 and darwin/386 -

    - -

    - TODO: https://golang.org/cl/109255: enable memory sanitizer on arm64 +

    + Setting the GODEBUG=tracebackancestors=N + environment variable now extends tracebacks with the stacks at + which goroutines were created, where N limits the + number of ancestor goroutines to report.

    -
    runtime,cmd/ld
    -
    -

    - TODO: https://golang.org/cl/108679: on darwin, create theads using libc -

    - -
    -
    runtime/pprof

    - TODO: https://golang.org/cl/102696: introduce "allocs" profile + This release adds a new "allocs" profile type that profiles + total number of bytes allocated since the program began + (including garbage-collected bytes). This is identical to the + existing "heap" profile viewed in -alloc_space mode. + Now go test -memprofile=... reports an "allocs" profile + instead of "heap" profile.

    -
    runtime/traceback
    -
    -

    - TODO: https://golang.org/cl/70993: support tracking goroutine ancestor tracebacks with GODEBUG="tracebackancestors=N" -

    - -
    -
    sync

    - TODO: https://golang.org/cl/87095: enable profiling of RWMutex + The mutex profile now includes reader/writer contention + for RWMutex. + Writer/writer contention was already included in the mutex + profile.

    @@ -316,7 +841,28 @@ Do not send CLs removing the interior tags from such phrases.
    syscall

    - TODO: https://golang.org/cl/106275: introduce Pointer type and use it instead of uintptr + On Windows, several fields were changed from uintptr to a new + Pointer + type to avoid problems with Go's garbage collector. The same change was made + to the golang.org/x/sys/windows + package. For any code affected, users should first migrate away from the syscall + package to the golang.org/x/sys/windows package, and then change + to using the Pointer, while obeying the + unsafe.Pointer conversion rules. +

    + +

    + On Linux, the flags parameter to + Faccessat + is now implemented just as in glibc. In earlier Go releases the + flags parameter was ignored. +

    + +

    + On Linux, the flags parameter to + Fchmodat + is now validated. Linux's fchmodat doesn't support the flags parameter + so we now mimic glibc's behavior and return an error if it's non-zero.

    @@ -324,7 +870,10 @@ Do not send CLs removing the interior tags from such phrases.
    text/scanner

    - TODO: https://golang.org/cl/112037: return RawString token rather than String for raw string literals + The Scanner.Scan method now returns + the RawString token + instead of String + for raw string literals.

    @@ -332,7 +881,19 @@ Do not send CLs removing the interior tags from such phrases.
    text/template

    - TODO: https://golang.org/cl/84480: add variable assignments + Modifying template variables via assignments is now permitted via the = token: +

    +
    +  {{"{{"}} $v := "init" {{"}}"}}
    +  {{"{{"}} if true {{"}}"}}
    +    {{"{{"}} $v = "changed" {{"}}"}}
    +  {{"{{"}} end {{"}}"}}
    +  v: {{"{{"}} $v {{"}}"}} {{"{{"}}/* "changed" */{{"}}"}}
    + +

    + In previous versions untyped nil values passed to + template functions were ignored. They are now passed as normal + arguments.

    @@ -340,7 +901,10 @@ Do not send CLs removing the interior tags from such phrases.
    time

    - TODO: https://golang.org/cl/98157: add support for parsing timezones denoted by sign and offset + Parsing of timezones denoted by sign and offset is now + supported. In previous versions, numeric timezone names + (such as +03) were not considered valid, and only + three-letter abbreviations (such as MST) were accepted + when expecting a timezone name.

    -
    diff --git a/doc/go_faq.html b/doc/go_faq.html index e020ce12c1..b1c15295d6 100644 --- a/doc/go_faq.html +++ b/doc/go_faq.html @@ -9,103 +9,49 @@ What is the purpose of the project?

    -No major systems language has emerged in over a decade, but over that time -the computing landscape has changed tremendously. There are several trends: +At the time of Go's inception, only a decade ago, the programming world was different from today. +Production software was usually written in C++ or Java, +GitHub did not exist, most computers were not yet multiprocessors, +and other than Visual Studio and Eclipse there were few IDEs or other high-level tools available +at all, let alone for free on the Internet.

    -
      -
    • -Computers are enormously quicker but software development is not faster. -
    • -Dependency management is a big part of software development today but the -“header files” of languages in the C tradition are antithetical to clean -dependency analysis—and fast compilation. -
    • -There is a growing rebellion against cumbersome type systems like those of -Java and C++, pushing people towards dynamically typed languages such as -Python and JavaScript. -
    • -Some fundamental concepts such as garbage collection and parallel computation -are not well supported by popular systems languages. -
    • -The emergence of multicore computers has generated worry and confusion. -
    -

    -We believe it's worth trying again with a new language, a concurrent, -garbage-collected language with fast compilation. Regarding the points above: +Meanwhile, we had become frustrated by the undue complexity required to use +the languages we worked with to develop server software. +Computers had become enormously quicker since languages such as +C, C++ and Java were first developed but the act of programming had not +itself advanced nearly as much. +Also, it was clear that multiprocessors were becoming universal but +most languages offered little help to program them efficiently +and safely.

    -
      -
    • -It is possible to compile a large Go program in a few seconds on a single computer. -
    • -Go provides a model for software construction that makes dependency -analysis easy and avoids much of the overhead of C-style include files and -libraries. -
    • -Go's type system has no hierarchy, so no time is spent defining the -relationships between types. Also, although Go has static types, the language -attempts to make types feel lighter weight than in typical OO languages. -
    • -Go is fully garbage-collected and provides fundamental support for -concurrent execution and communication. -
    • -By its design, Go proposes an approach for the construction of system -software on multicore machines. -
    +

    +We decided to take a step back and think about what major issues were +going to dominate software engineering in the years ahead as technology +developed, and how a new language might help address them. +For instance, the rise of multicore CPUs argued that a language should +provide first-class support for some sort of concurrency or parallelism. +And to make resource management tractable in a large concurrent program, +garbage collection, or at least some sort of safe automatic memory management was required. +

    -A much more expansive answer to this question is available in the article, +These considerations led to +a +series of discussions from which Go arose, first as a set of ideas and +desiderata, then as a language. +An overarching goal was that Go do more to help the working programmer +by enabling tooling, automating mundane tasks such as code formatting, +and removing obstacles to working on large code bases. +

    + +

    +A much more expansive description of the goals of Go and how +they are met, or at least approached, is available in the article, Go at Google: Language Design in the Service of Software Engineering. - -

    -What is the status of the project?

    - -

    -Go became a public open source project on November 10, 2009. -After a couple of years of very active design and development, stability was called for and -Go 1 was released -on March 28, 2012. -Go 1, which includes a language specification, -standard libraries, -and custom tools, -provides a stable foundation for creating reliable products, projects, and publications. -

    - -

    -With that stability established, we are using Go to develop programs, products, and tools rather than -actively changing the language and libraries. -In fact, the purpose of Go 1 is to provide long-term stability. -Backwards-incompatible changes will not be made to any Go 1 point release. -We want to use what we have to learn how a future version of Go might look, rather than to play with -the language underfoot. -

    - -

    -Of course, development will continue on Go itself, but the focus will be on performance, reliability, -portability and the addition of new functionality such as improved support for internationalization. -

    - -

    -There may well be a Go 2 one day, but not for a few years and it will be influenced by what we learn using Go 1 as it is today. -

    - -

    -What's the origin of the mascot?

    - -

    -The mascot and logo were designed by -Renée French, who also designed -Glenda, -the Plan 9 bunny. -The gopher -is derived from one she used for an WFMU -T-shirt design some years ago. -The logo and mascot are covered by the -Creative Commons Attribution 3.0 -license.

    @@ -126,14 +72,49 @@ and libraries from prototype to reality.

    Go became a public open source project on November 10, 2009. -Many people from the community have contributed ideas, discussions, and code. +Countless people from the community have contributed ideas, discussions, and code. +

    + +

    +There are now millions of Go programmers—gophers—around the world, +and there are more every day. +Go's success has far exceeded our expectations. +

    + +

    +What's the origin of the gopher mascot?

    + +

    +The mascot and logo were designed by +Renée French, who also designed +Glenda, +the Plan 9 bunny. +A blog post +about the gopher explains how it was +derived from one she used for a WFMU +T-shirt design some years ago. +The logo and mascot are covered by the +Creative Commons Attribution 3.0 +license. +

    + +

    +The gopher has a +model sheet +illustrating his characteristics and how to represent them correctly. +The model sheet was first shown in a +talk +by Renée at Gophercon in 2016. +He has unique features; he's the Go gopher, not just any old gopher.

    -Why are you creating a new language?

    +Why did you create a new language? +

    Go was born out of frustration with existing languages and -environments for systems programming. Programming had become too +environments for the work we were doing at Google. +Programming had become too difficult and the choice of languages was partly to blame. One had to choose either efficient compilation, efficient execution, or ease of programming; all three were not available in the same mainstream @@ -143,10 +124,18 @@ Python and JavaScript rather than C++ or, to a lesser extent, Java.

    -Go is an attempt to combine the ease of programming of an interpreted, +We were not alone in our concerns. +After many years with a pretty quiet landscape for programming languages, +Go was among the first of several new languages—Rust, +Elixir, Swift, and more—that have made programming language development +an active, almost mainstream field again. +

    + +

    +Go addressed these issues by attempting to combine the ease of programming of an interpreted, dynamically typed language with the efficiency and safety of a statically typed, compiled language. -It also aims to be modern, with support for networked and multicore +It also aimed to be modern, with support for networked and multicore computing. Finally, working with Go is intended to be fast: it should take at most a few seconds to build a large executable on a single computer. To meet these goals required addressing a number of @@ -162,6 +151,7 @@ discusses the background and motivation behind the design of the Go language, as well as providing more detail about many of the answers presented in this FAQ.

    +

    What are Go's ancestors?

    @@ -179,15 +169,19 @@ kind of programming we do, more effective, which means more fun.

    What are the guiding principles in the design?

    +

    -Programming today involves too much bookkeeping, repetition, and -clerical work. As Dick Gabriel says, “Old programs read -like quiet conversations between a well-spoken research worker and a -well-studied mechanical colleague, not as a debate with a compiler. -Who'd have guessed sophistication bought such noise?” -The sophistication is worthwhile—no one wants to go back to -the old languages—but can it be more quietly achieved? +When Go was designed, Java and C++ were the most commonly +used languages for writing servers, at least at Google. +We felt that these languages required +too much bookkeeping and repetition. +Some programmers reacted by moving towards more dynamic, +fluid languages like Python, at the cost of efficiency and +type safety. +We felt it should be possible to have the efficiency, +the safety, and the fluidity in a single language.

    +

    Go attempts to reduce the amount of typing in both senses of the word. Throughout its design, we have tried to reduce clutter and @@ -210,11 +204,12 @@ easier to understand what happens when things combine.

    Usage

    -

    Is Google using Go internally?

    +

    +Is Google using Go internally?

    -Yes. There are now several Go programs deployed in -production inside Google. A public example is the server behind +Yes. Go is used widely in production inside Google. +One easy example is the server behind golang.org. It's just the godoc document server running in a production configuration on @@ -222,39 +217,109 @@ document server running in a production configuration on

    -Other examples include the Vitess -system for large-scale SQL installations and Google's download server, dl.google.com, +A more significant instance is Google's download server, dl.google.com, which delivers Chrome binaries and other large installables such as apt-get packages.

    +

    +Go is not the only language used at Google, far from it, but it is a key language +for a number of areas including +site reliability +engineering (SRE) +and large-scale data processing. +

    + +

    +What other companies use Go?

    + +

    +Go usage is growing worldwide, especially but by no means exclusively +in the cloud computing space. +A couple of major cloud infrastructure projects written in Go are +Docker and Kubernetes, +but there are many more. +

    + +

    +It's not just cloud, though. +The Go Wiki includes a +page, +updated regularly, that lists some of the many companies using Go. +

    + +

    +The Wiki also has a page with links to +success stories +about companies and projects that are using the language. +

    +

    -There are two Go compiler implementations, gc -and gccgo. -Gc uses a different calling convention and linker and can -therefore only be linked with C programs using the same convention. -There is such a C compiler but no C++ compiler. -Gccgo is a GCC front-end that can, with care, be linked with -GCC-compiled C or C++ programs. +It is possible to use C and Go together in the same address space, +but it is not a natural fit and can require special interface software. +Also, linking C with Go code gives up the memory +safety and stack management properties that Go provides. +Sometimes it's absolutely necessary to use C libraries to solve a problem, +but doing so always introduces an element of risk not present with +pure Go code, so do so with care.

    -The cgo program provides the mechanism for a -“foreign function interface” to allow safe calling of -C libraries from Go code. SWIG extends this capability to C++ libraries. +If you do need to use C with Go, how to proceed depends on the Go +compiler implementation. +There are three Go compiler implementations supported by the +Go team. +These are gc, the default compiler, +gccgo, which uses the GCC back end, +and a somewhat less mature gollvm, which uses the LLVM infrastructure.

    +

    +Gc uses a different calling convention and linker from C and +therefore cannot be called directly from C programs, or vice versa. +The cgo program provides the mechanism for a +“foreign function interface” to allow safe calling of +C libraries from Go code. +SWIG extends this capability to C++ libraries. +

    -

    +

    +You can also use cgo and SWIG with Gccgo and gollvm. +Since they use a traditional API, it's also possible, with great care, +to link code from these compilers directly with GCC/LLVM-compiled C or C++ programs. +However, doing so safely requires an understanding of the calling conventions for +all languages concerned, as well as concern for stack limits when calling C or C++ +from Go. +

    + +

    +What IDEs does Go support?

    + +

    +The Go project does not include a custom IDE, but the language and +libraries have been designed to make it easy to analyze source code. +As a consequence, most well-known editors and IDEs support Go well, +either directly or through a plugin. +

    + +

    +The list of well-known IDEs and editors that have good Go support +available includes Emacs, Vim, VSCode, Atom, Eclipse, Sublime, IntelliJ +(through a custom variant called Goland), and many more. +Chances are your favorite environment is a productive one for +programming in Go. +

    + +

    Does Go support Google's protocol buffers?

    A separate open source project provides the necessary compiler plugin and library. It is available at -github.com/golang/protobuf/ +github.com/golang/protobuf/.

    @@ -286,7 +351,8 @@ to libc, the C library.

    It is important to understand, however, that Go's runtime does not include a virtual machine, such as is provided by the Java runtime. -Go programs are compiled ahead of time to native machine code. +Go programs are compiled ahead of time to native machine code +(or JavaScript or WebAssembly, for some variant implementations). Thus, although the term is often used to describe the virtual environment in which a program runs, in Go the word “runtime” is just the name given to the library providing critical language services. @@ -296,28 +362,47 @@ is just the name given to the library providing critical language services. What's up with Unicode identifiers?

    -It was important to us to extend the space of identifiers from the -confines of ASCII. Go's rule—identifier characters must be +When designing Go, we wanted to make sure that it was not +overly ASCII-centric, +which meant extending the space of identifiers from the +confines of 7-bit ASCII. +Go's rule—identifier characters must be letters or digits as defined by Unicode—is simple to understand -and to implement but has restrictions. Combining characters are -excluded by design, for instance. -Until there -is an agreed external definition of what an identifier might be, -plus a definition of canonicalization of identifiers that guarantees -no ambiguity, it seemed better to keep combining characters out of -the mix. Thus we have a simple rule that can be expanded later -without breaking programs, one that avoids bugs that would surely arise -from a rule that admits ambiguous identifiers. +and to implement but has restrictions. +Combining characters are +excluded by design, for instance, +and that excludes some languages such as Devanagari.

    -On a related note, since an exported identifier must begin with an -upper-case letter, identifiers created from “letters” -in some languages can, by definition, not be exported. For now the +This rule has one other unfortunate consequence. +Since an exported identifier must begin with an +upper-case letter, identifiers created from characters +in some languages can, by definition, not be exported. +For now the only solution is to use something like X日本語, which -is clearly unsatisfactory; we are considering other options. The -case-for-visibility rule is unlikely to change however; it's one -of our favorite features of Go. +is clearly unsatisfactory. +

    + +

    +Since the earliest version of the language, there has been considerable +thought into how best to expand the identifier space to accommodate +programmers using other native languages. +Exactly what to do remains an active topic of discussion, and a future +version of the language may be more liberal in its definition +of an identifier. +For instance, it might adopt some of the ideas from the Unicode +organization's recommendations +for identifiers. +Whatever happens, it must be done compatibly while preserving +(or perhaps expanding) the way letter case determines visibility of +identifiers, which remains one of our favorite features of Go. +

    + +

    +For the time being, we have a simple rule that can be expanded later +without breaking programs, one that avoids bugs that would surely arise +from a rule that admits ambiguous identifiers.

    Why does Go not have feature X?

    @@ -345,6 +430,23 @@ Generics may well be added at some point. We don't feel an urgency for them, although we understand some programmers do.

    +

    +Go was intended as a language for writing server programs that would be +easy to maintain over time. +(See this +article for more background.) +The design concentrated on things like scalability, readability, and +concurrency. +Polymorphic programming did not seem essential to the language's +goals at the time, and so was left out for simplicity. +

    + +

    +The language is more mature now, and there is scope to consider +some form of generic programming. +However, there remain some caveats. +

    +

    Generics are convenient but they come at a cost in complexity in the type system and run-time. We haven't yet found a @@ -391,6 +493,9 @@ when used well, can result in clean error-handling code.

    See the Defer, Panic, and Recover article for details. +Also, the Errors are values blog post +describes one approach to handling errors cleanly in Go by demonstrating that, +since errors are just values, the full power of Go can deployed in error handling.

    @@ -400,7 +505,7 @@ Why does Go not have assertions?

    Go doesn't provide assertions. They are undeniably convenient, but our experience has been that programmers use them as a crutch to avoid thinking about proper error handling and reporting. Proper error handling means that -servers continue operation after non-fatal errors instead of crashing. +servers continue to operate instead of crashing after a non-fatal error. Proper error reporting means that errors are direct and to the point, saving the programmer from interpreting a large crash trace. Precise errors are particularly important when the programmer seeing the errors is @@ -416,9 +521,11 @@ because we feel it's sometimes worth trying a different approach.

    Why build concurrency on the ideas of CSP?

    -Concurrency and multi-threaded programming have a reputation -for difficulty. We believe this is due partly to complex -designs such as pthreads and partly to overemphasis on low-level details +Concurrency and multi-threaded programming have over time +developed a reputation for difficulty. We believe this is due partly to complex +designs such as +pthreads +and partly to overemphasis on low-level details such as mutexes, condition variables, and memory barriers. Higher-level interfaces enable much simpler code, even if there are still mutexes and such under the covers. @@ -488,6 +595,12 @@ by assigning to elements or doing deletions, it is safe for them to access the map concurrently without synchronization.

    +

    +As an aid to correct map use, some implementations of the language +contain a special check that automatically reports at run time when a map is modified +unsafely by concurrent execution. +

    +

    Will you accept my language change?

    @@ -501,11 +614,15 @@ been accepted.

    Although Go is an open source project, the language and libraries are protected by a compatibility promise that prevents -changes that break existing programs. +changes that break existing programs, at least at the source code level +(programs may need to be recompiled occasionally to stay current). If your proposal violates the Go 1 specification we cannot even entertain the idea, regardless of its merit. -A future major release of Go may be incompatible with Go 1, but we're not ready -to start talking about what that might be. +A future major release of Go may be incompatible with Go 1, but discussions +on that topic have only just begun and one thing is certain: +there will be very few such incompatibilities introduced in the process. +Moreover, the compatibility promise encourages us to provide an automatic path +forward for old programs to adapt should that situation arise.

    @@ -619,7 +736,8 @@ Why doesn't Go have "implements" declarations?

    A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without -having to modify existing code. It enables a kind of structural typing that +needing to modify existing code. It enables a kind of +structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, @@ -764,7 +882,9 @@ examples and also have them be statically checked. Can I convert a []T to an []interface{}?

    -Not directly, because they do not have the same representation in memory. +Not directly. +It is disallowed by the language specification because the two types +do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}: @@ -806,22 +926,30 @@ Why is my nil error value not equal to nil?

    -Under the covers, interfaces are implemented as two elements, a type and a value. -The value, called the interface's dynamic value, -is an arbitrary concrete value and the type is that of the value. -For the int value 3, an interface value contains, -schematically, (int, 3). +Under the covers, interfaces are implemented as two elements, a type T +and a value V. +V is a concrete value such as an int, +struct or pointer, never an interface itself, and has +type T. +For instance, if we store the int value 3 in an interface, +the resulting interface value has, schematically, +(T=int, V=3). +The value V is also known as the interface's +dynamic value, +since a given interface variable might hold different values V +(and corresponding types T) +during the execution of the program.

    -An interface value is nil only if the inner value and type are both unset, -(nil, nil). +An interface value is nil only if the V and T +are both unset, (T=nil, V is not set), In particular, a nil interface will always hold a nil type. If we store a nil pointer of type *int inside an interface value, the inner type will be *int regardless of the value of the pointer: -(*int, nil). +(T=*int, V=nil). Such an interface value will therefore be non-nil -even when the pointer inside is nil. +even when the pointer value V inside is nil.

    @@ -842,7 +970,7 @@ func returnsError() error {

    If all goes well, the function returns a nil p, so the return value is an error interface -value holding (*MyError, nil). +value holding (T=*MyError, V=nil). This means that if the caller compares the returned error to nil, it will always look as if there was an error even if nothing bad happened. To return a proper nil error to the caller, @@ -953,6 +1081,7 @@ and implementation.

    Why does Go not provide implicit numeric conversions?

    +

    The convenience of automatic conversion between numeric types in C is outweighed by the confusion it causes. When is an expression unsigned? @@ -974,6 +1103,43 @@ type is generic; if you care about how many bits an integer holds, Go encourages you to be explicit.

    +

    +How do constants work in Go?

    + +

    +Although Go is strict about conversion between variables of different +numeric types, constants in the language are much more flexible. +Literal constants such as 23, 3.14159 +and math.Pi +occupy a sort of ideal number space, with arbitrary precision and +no overflow or underflow. +For instance, the value of math.Pi is specified to 63 places +in the source code, and constant expressions involving the value keep +precision beyond what a float64 could hold. +Only when the constant or constant expression is assigned to a +variable—a memory location in the program—does +it become a "computer" number with +the usual floating-point properties and precision. +

    + +

    +Also, +because they are just numbers, not typed values, constants in Go can be +used more freely than variables, thereby softening some of the awkwardness +around the strict conversion rules. +One can write expressions such as +

    + +
    +sqrt2 := math.Sqrt(2)
    +
    + +

    +without complaint from the compiler because the ideal number 2 +can be converted safely and accurately +to a float64 for the call to math.Sqrt. +

    +

    A blog post titled Constants explores this topic in more detail. @@ -1028,8 +1194,9 @@ How are libraries documented?

    There is a program, godoc, written in Go, that extracts -package documentation from the source code. It can be used on the -command line or on the web. An instance is running at +package documentation from the source code and serves it as a web +page with links to declarations, files, and so on. +An instance is running at golang.org/pkg/. In fact, godoc implements the full site at golang.org/. @@ -1052,14 +1219,20 @@ subcommand that provides a textual interface to the same information. Is there a Go programming style guide?

    -Eventually, there may be a small number of rules to guide things -like naming, layout, and file organization. +There is no explicit style guide, although there is certainly +a recognizable "Go style". +

    + +

    +Go has established conventions to guide decisions around +naming, layout, and file organization. The document Effective Go -contains some style advice. +contains some advice on these topics. More directly, the program gofmt is a pretty-printer whose purpose is to enforce layout rules; it replaces the usual compendium of do's and don'ts that allows interpretation. -All the Go code in the repository has been run through gofmt. +All the Go code in the repository, and the vast majority in the +open source world, has been run through gofmt.

    @@ -1123,11 +1296,25 @@ add these lines to your ~/.gitconfig: How should I manage package versions using "go get"?

    -"Go get" does not have any explicit concept of package versions. +Since the inception of the project, Go has had no explicit concept of package versions, +but that is changing. Versioning is a source of significant complexity, especially in large code bases, -and we are unaware of any approach that works well at scale in a large enough -variety of situations to be appropriate to force on all Go users. -What "go get" and the larger Go toolchain do provide is isolation of +and it has taken some time to develop an +approach that works well at scale in a large enough +variety of situations to be appropriate to supply to all Go users. +

    + +

    +The Go 1.11 release adds new, experimental support +for package versioning to the go command, +in the form of Go modules. +For more information, see the Go 1.11 release notes +and the go command documentation. +

    + +

    +Regardless of the actual package management technology, +"go get" and the larger Go toolchain does provide isolation of packages with different import paths. For example, the standard library's html/template and text/template coexist even though both are "package template". @@ -1139,34 +1326,21 @@ Packages intended for public use should try to maintain backwards compatibility The Go 1 compatibility guidelines are a good reference here: don't remove exported names, encourage tagged composite literals, and so on. If different functionality is required, add a new name instead of changing an old one. -If a complete break is required, create a new package with a new import path.

    +If a complete break is required, create a new package with a new import path. +

    If you're using an externally supplied package and worry that it might change in -unexpected ways, the simplest solution is to copy it to your local repository. -(This is the approach Google takes internally.) -Store the copy under a new import path that identifies it as a local copy. -For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg". -The gomvpkg -program is one tool to help automate this process. -

    - -

    -The Go 1.5 release added a facility to the -go command -that makes it easier to manage external dependencies by "vendoring" -them into a special directory near the package that depends upon them. +unexpected ways, but are not yet using Go modules, +the simplest solution is to copy it to your local repository. +This is the approach Google takes internally and is supported by the +go command through a technique called "vendoring". +This involves +storing a copy of the dependency under a new import path that identifies it as a local copy. See the design document for details.

    -

    -Work is underway on an experimental package management tool, -dep, to learn -more about how tooling can help package management. More information can be found in -the dep FAQ. -

    -

    Pointers and Allocation

    @@ -1208,7 +1382,7 @@ disguising an interface value's type for delayed evaluation.

    -It is however a common mistake to pass a pointer to an interface value +It is a common mistake to pass a pointer to an interface value to a function expecting an interface. The compiler will complain about this error but the situation can still be confusing, because sometimes a pointer @@ -1284,9 +1458,10 @@ of passing a value), so changes it makes will be invisible to the caller.

    -By the way, pointer receivers are identical to the situation in Java, -although in Java the pointers are hidden under the covers; it's Go's -value receivers that are unusual. +By the way, in Java method receivers are always pointers, +although their pointer nature is somewhat disguised +(and there is a proposal to add value receivers to the language). +It is the value receivers in Go that are unusual.

    @@ -1314,7 +1489,7 @@ requires a pointer, a value receiver is efficient and clear. What's the difference between new and make?

    -In short: new allocates memory, make initializes +In short: new allocates memory, while make initializes the slice, map, and channel types.

    @@ -1331,9 +1506,9 @@ The sizes of int and uint are implementation-specific but the same as each other on a given platform. For portability, code that relies on a particular size of value should use an explicitly sized type, like int64. -Prior to Go 1.1, the 64-bit Go compilers (both gc and gccgo) used -a 32-bit representation for int. As of Go 1.1 they use -a 64-bit representation. +On 32-bit machines the compilers use 32-bit integers by default, +while on 64-bit machines integers have 64 bits. +(Historically, this was not always true.)

    @@ -1406,16 +1581,28 @@ To find the amount of actual memory allocated to a Go process, use the Unix What operations are atomic? What about mutexes?

    -We haven't fully defined it all yet, but some details about atomicity are -available in the Go Memory Model specification. +A description of the atomicity of operations in Go can be found in +the Go Memory Model document.

    -Regarding mutexes, the sync -package implements them, but we hope Go programming style will -encourage people to try higher-level techniques. In particular, consider -structuring your program so that only one goroutine at a time is ever -responsible for a particular piece of data. +Low-level synchronization and atomic primitives are available in the +sync and +sync/atomic +packages. +These packages are good for simple tasks such as incrementing +reference counts or guaranteeing small-scale mutual exclusion. +

    + +

    +For higher-level operations, such as coordination among +concurrent servers, higher-level techniques can lead +to nicer programs, and Go supports this approach through +its goroutines and channels. +For instance, you can structure your program so that only one +goroutine at a time is ever responsible for a particular piece of data. +That approach is summarized by the original +Go proverb,

    @@ -1423,70 +1610,84 @@ Do not communicate by sharing memory. Instead, share memory by communicating.

    -See the Share Memory By Communicating code walk and its associated article for a detailed discussion of this concept. -

    - -

    -Why doesn't my multi-goroutine program use multiple CPUs?

    - -

    -The number of CPUs available simultaneously to executing goroutines is -controlled by the GOMAXPROCS shell environment variable. -In earlier releases of Go, the default value was 1, but as of Go 1.5 the default -value is the number of cores available. -Therefore programs compiled after 1.5 should demonstrate parallel execution -of multiple goroutines. -To change the behavior, set the environment variable or use the similarly-named -function -of the runtime package to configure the -run-time support to utilize a different number of threads. +See the Share Memory By Communicating code walk +and its +associated article for a detailed discussion of this concept.

    -Programs that perform parallel computation might benefit from a further increase in -GOMAXPROCS. -However, be aware that -concurrency -is not parallelism. +Large concurrent programs are likely to borrow from both these toolkits.

    -

    -Why does using GOMAXPROCS > 1 sometimes make my program -slower?

    +

    +Why doesn't my program run faster with more CPUs?

    -It depends on the nature of your program. +Whether a program runs faster with more CPUs depends on the problem +it is solving. +The Go language provides concurrency primitives, such as goroutines +and channels, but concurrency only enables parallelism +when the underlying problem is intrinsically parallel. Problems that are intrinsically sequential cannot be sped up by adding -more goroutines. -Concurrency only becomes parallelism when the problem is -intrinsically parallel. +more CPUs, while those that can be broken into pieces that can +execute in parallel can be sped up, sometimes dramatically.

    +Sometimes adding more CPUs can slow a program down. In practical terms, programs that spend more time -communicating on channels than doing computation +synchronizing or communicating than doing useful computation may experience performance degradation when using multiple OS threads. -This is because sending data between threads involves switching -contexts, which has significant cost. +This is because passing data between threads involves switching +contexts, which has significant cost, and that cost can increase +with more CPUs. For instance, the prime sieve example from the Go specification has no significant parallelism although it launches many -goroutines; increasing GOMAXPROCS is more likely to slow it down than +goroutines; increasing the number of threads (CPUs) is more likely to slow it down than to speed it up.

    +

    +For more detail on this topic see the talk entitled +Concurrency +is not Parallelism. + +

    +How can I control the number of CPUs?

    + +

    +The number of CPUs available simultaneously to executing goroutines is +controlled by the GOMAXPROCS shell environment variable, +whose default value is the number of CPU cores available. +Programs with the potential for parallel execution should therefore +achieve it by default on a multiple-CPU machine. +To change the number of parallel CPUs to use, +set the environment variable or use the similarly-named +function +of the runtime package to configure the +run-time support to utilize a different number of threads. +Setting it to 1 eliminates the possibility of true parallelism, +forcing independent goroutines to take turns executing. +

    + +

    +The runtime can allocate more threads than the value +of GOMAXPROCS to service multiple outstanding +I/O requests. +GOMAXPROCS only affects how many goroutines +can actually execute at once; arbitrarily more may be blocked +in system calls. +

    +

    Go's goroutine scheduler is not as good as it needs to be, although it -has improved in recent releases. +has improved over time. In the future, it may better optimize its use of OS threads. For now, if there are performance issues, setting GOMAXPROCS on a per-application basis may help.

    -

    -For more detail on this topic see the talk entitled, -Concurrency -is not Parallelism.

    Why is there no goroutine ID?

    @@ -1541,21 +1742,26 @@ used in flexible ways to interact with it. Why do T and *T have different method sets?

    -From the Go Spec: +As the Go specification says, +the method set of a type T consists of all methods +with receiver type T, +while that of the corresponding pointer +type *T consists of all methods with receiver *T or +T. +That means the method set of *T +includes that of T), +but not the reverse.

    -
    -The method set of any other named type T consists of all methods -with receiver type T. The method set of the corresponding pointer -type *T is the set of all methods with receiver *T or -T (that is, it also contains the method set of T). -
    -

    -If an interface value contains a pointer *T, +This distinction arises because +if an interface value contains a pointer *T, a method call can obtain a value by dereferencing the pointer, but if an interface value contains a value T, -there is no useful way for a method call to obtain a pointer. +there is no safe way for a method call to obtain a pointer. +(Doing so would allow a method to modify the contents of +the value inside the interface, which is not permitted by +the language specification.)

    @@ -1653,13 +1859,21 @@ seem odd but works fine in Go: }

    +

    +This behavior of the language, not defining a new variable for +each iteration, may have been a mistake in retrospect. +It may be addressed in a later version but, for compatibility, +cannot change in Go version 1. +

    +

    Control flow

    -Does Go have the ?: operator?

    +Why does Go not have the ?: operator?

    -There is no ternary testing operation in Go. You may use the following to achieve the same +There is no ternary testing operation in Go. +You may use the following to achieve the same result:

    @@ -1671,6 +1885,14 @@ if expr { }
+

+The reason ?: is absent from Go is that the language's designers +had seen the operation used too often to create impenetrably complex expressions. +The if-else form, although longer, +is unquestionably clearer. +A language needs only one conditional control flow construct. +

+

Packages and Testing

@@ -1803,38 +2025,69 @@ But we encourage most new code to live elsewhere. What compiler technology is used to build the compilers?

-Gccgo has a front end written in C++, with a recursive descent parser coupled to the -standard GCC back end. Gc is written in Go with a recursive descent parser +There are several production compilers for Go, and a number of others +in development for various platforms. +

+ +

+The default compiler, gc, is included with the +Go distribution as part of the support for the go +command. +Gc was originally written in C +because of the difficulties of bootstrapping—you'd need a Go compiler to +set up a Go environment. +But things have advanced and since the Go 1.5 release the compiler has been +a Go program. +The compiler was converted from C to Go using automatic translation tools, as +described in this design document +and talk. +Thus the compiler is now "self-hosting", which means we needed to face +the bootstrapping problem. +The solution is to have a working Go installation already in place, +just as one normally has with a working C installation. +The story of how to bring up a new Go environment from source +is described here and +here. +

+ +

+Gc is written in Go with a recursive descent parser and uses a custom loader, also written in Go but based on the Plan 9 loader, to generate ELF/Mach-O/PE binaries.

-We considered using LLVM for gc but we felt it was too large and -slow to meet our performance goals. +At the beginning of the project we considered using LLVM for +gc but decided it was too large and slow to meet +our performance goals. +More important in retrospect, starting with LLVM would have made it +harder to introduce some of the ABI and related changes, such as +stack management, that Go requires but not are not part of the +standard C setup. +A new LLVM implementation +is starting to come together now, however.

-The original gc, the Go compiler, was written in C -because of the difficulties of bootstrapping—you'd need a Go compiler to -set up a Go environment. -But things have advanced and as of Go 1.5 the compiler is written in Go. -It was converted from C to Go using automatic translation tools, as -described in this design document -and a recent talk. -Thus the compiler is now "self-hosting", which means we must face -the bootstrapping problem. -The solution, naturally, is to have a working Go installation already, -just as one normally has a working C installation in place. -The story of how to bring up a new Go installation from source -is described separately. +The Gccgo compiler is a front end written in C++ +with a recursive descent parser coupled to the +standard GCC back end. +

+ +

+Go turned out to be a fine language in which to implement a Go compiler, +although that was not its original goal. +Not being self-hosting from the beginning allowed Go's design to +concentrate on its original use case, which was networked servers. +Had we decided Go should compile itself early on, we might have +ended up with a language targeted more for compiler construction, +which is a worthy goal but not the one we had initially.

-Go is a fine language in which to implement a Go compiler. Although gc does not use them (yet?), a native lexer and parser are available in the go package -and there is also a type checker. +and there is also a native type checker.

@@ -1848,6 +2101,8 @@ tiny bit of assembler) but it has since been translated to Go The gccgo compiler implements goroutines using a technique called segmented stacks, supported by recent modifications to the gold linker. +Gollvm similarly is built on the corresponding +LLVM infrastructure.

@@ -1857,7 +2112,7 @@ Why is my trivial program such a large binary?

The linker in the gc toolchain creates statically-linked binaries by default. All Go binaries therefore include the Go -run-time, along with the run-time type information necessary to support dynamic +runtime, along with the run-time type information necessary to support dynamic type checks, reflection, and even panic-time stack traces.

@@ -1870,6 +2125,14 @@ An equivalent Go program using more powerful run-time support and type and debugging information.

+

+A Go program compiled with gc can be linked with +the -ldflags=-w flag to disable DWARF generation, +removing debugging information from the binary but with no +other loss of functionality. +This can reduce the binary size substantially. +

+

Can I stop these complaints about my unused variable/import?

@@ -2109,7 +2372,7 @@ brace to live on the next line. We disagree. Since Go code is meant to be formatted automatically by gofmt, some style must be chosen. That style may differ from what -you've used in C or Java, but Go is a new language and +you've used in C or Java, but Go is a different language and gofmt's style is as good as any other. More important—much more important—the advantages of a single, programmatically mandated format for all Go programs greatly outweigh @@ -2122,16 +2385,25 @@ Go can use the standard syntax one line at a time without special rules. Why do garbage collection? Won't it be too expensive?

One of the biggest sources of bookkeeping in systems programs is -memory management. We feel it's critical to eliminate that -programmer overhead, and advances in garbage collection -technology in the last few years give us confidence that we can -implement it with low enough overhead and no significant -latency. +managing the lifetimes of allocated objects. +In languages such as C in which it is done manually, +it can consume a significant amount of programmer time and is +often the cause of pernicious bugs. +Even in languages like C++ or Rust that provide mechanisms +to assist, those mechanisms can have a significant effect on the +design of the software, often adding programming overhead +of its own. +We felt it was critical to eliminate such +programmer overheads, and advances in garbage collection +technology in the last few years gave us confidence that it +could be implemented cheaply enough, and with low enough +latency, that it could be a viable approach for networked +systems.

-Another point is that a large part of the difficulty of concurrent -and multi-threaded programming is memory management; +Much of the difficulty of concurrent programming +has its roots in the object lifetime problem: as objects get passed among threads it becomes cumbersome to guarantee they become freed safely. Automatic garbage collection makes concurrent code far easier to write. @@ -2146,12 +2418,29 @@ simpler because they don't need to specify how memory is managed across them.

-The current implementation is a parallel mark-and-sweep collector. -Recent improvements, documented in -this design document, -have introduced bounded pause times and improved the -parallelism. -Future versions might attempt new approaches. +This is not to say that the recent work in languages +like Rust that bring new ideas to the problem of managing +resources is misguided; we encourage this work and are excited to see +how it evolves. +But Go takes a more traditional approach by addressing +object lifetimes through +garbage collection, and garbage collection alone. +

+ +

+The current implementation is a mark-and-sweep collector. +If the machine is a multiprocessor, the collector runs on a separate CPU +core in parallel with the main program. +Major work on the collector in recent years has reduced pause times +often to the sub-millisecond range, even for large heaps, +all but eliminating one of the major objections to garbage collection +in networked servers. +Work continues to refine the algorithm, reduce overhead and +latency further, and to explore new approaches. +The 2018 +ISMM keynote +by Rick Hudson of the Go team +describes the progress so far and suggests some future approaches.

diff --git a/doc/go_spec.html b/doc/go_spec.html index f70ff7a02f..57bb3b53f5 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,6 +1,6 @@ @@ -2112,8 +2112,8 @@ with initializer expressions but no types: i, j := 0, 10 f := func() int { return 7 } ch := make(chan int) -r, w := os.Pipe(fd) // os.Pipe() returns two values -_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate +r, w, _ := os.Pipe() // os.Pipe() returns a connected pair of Files and an error, if any +_, y, _ := coord(p) // coord() returns three values; only interested in y coordinate

diff --git a/doc/gopher/modelsheet.jpg b/doc/gopher/modelsheet.jpg new file mode 100644 index 0000000000..c31e35a6df Binary files /dev/null and b/doc/gopher/modelsheet.jpg differ diff --git a/doc/install-source.html b/doc/install-source.html index f6d9473d9b..2d12a28869 100644 --- a/doc/install-source.html +++ b/doc/install-source.html @@ -639,14 +639,10 @@ contains further details regarding Go's ARM support.

-
  • $GOMIPS (for mips and mipsle only) +
  • $GOMIPS (for mips and mipsle only)
    $GOMIPS64 (for mips64 and mips64le only)

    -This sets whether to use floating point instructions. + These variables set whether to use floating point instructions. Set to "hardfloat" to use floating point instructions; this is the default. Set to "softfloat" to use soft floating point.

    -
      -
    • GOMIPS=hardfloat: use floating point instructions (the default)
    • -
    • GOMIPS=softfloat: use soft floating point
    • -
  • diff --git a/doc/install.html b/doc/install.html index 3bb4a15b25..2e0c7f859d 100644 --- a/doc/install.html +++ b/doc/install.html @@ -50,7 +50,7 @@ If your OS or architecture is not on the list, you may be able to FreeBSD 10.3 or later amd64, 386 Debian GNU/kFreeBSD not supported Linux 2.6.23 or later with glibc amd64, 386, arm, arm64,
    s390x, ppc64le CentOS/RHEL 5.x not supported.
    Install from source for other libc. macOS 10.10 or later amd64 use the clang or gcc that comes with Xcode for cgo support -Windows XP SP2 or later amd64, 386 use MinGW gcc. No need for cygwin or msys. +Windows 7, Server 2008R2 or later amd64, 386 use MinGW gcc. No need for cygwin or msys.

    diff --git a/doc/security.html b/doc/security.html index 0d8b5ee526..c305ae03c1 100644 --- a/doc/security.html +++ b/doc/security.html @@ -38,7 +38,7 @@ security team directly:

    diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go index 4c7f676e0b..ccacc50fe1 100644 --- a/misc/cgo/test/cgo_test.go +++ b/misc/cgo/test/cgo_test.go @@ -90,6 +90,8 @@ func Test22906(t *testing.T) { test22906(t) } func Test24206(t *testing.T) { test24206(t) } func Test25143(t *testing.T) { test25143(t) } func Test23356(t *testing.T) { test23356(t) } +func Test26066(t *testing.T) { test26066(t) } +func Test26213(t *testing.T) { test26213(t) } func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) } func BenchmarkGoString(b *testing.B) { benchGoString(b) } diff --git a/misc/cgo/test/issue21897.go b/misc/cgo/test/issue21897.go index d13246bd84..454a141827 100644 --- a/misc/cgo/test/issue21897.go +++ b/misc/cgo/test/issue21897.go @@ -2,7 +2,16 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin,cgo,!internal +// We skip this test in race mode because, for unknown reasons, +// linking against CoreFoundation on macOS 10.10 causes mmap to ignore +// the hint address, which makes the Go allocator incompatible with +// TSAN. See golang.org/issue/26475. +// +// TODO(austin): Once support for macOS 10.10 is dropped, remove the +// race constraint (and the one in issue21897b.go). See +// golang.org/issue/26513. + +// +build darwin,cgo,!internal,!race package cgotest diff --git a/misc/cgo/test/issue21897b.go b/misc/cgo/test/issue21897b.go index 08b5f4d808..e143bad086 100644 --- a/misc/cgo/test/issue21897b.go +++ b/misc/cgo/test/issue21897b.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !darwin !cgo internal +// +build !darwin !cgo internal race package cgotest diff --git a/misc/cgo/test/issue24161_darwin_test.go b/misc/cgo/test/issue24161_darwin_test.go new file mode 100644 index 0000000000..48072ff121 --- /dev/null +++ b/misc/cgo/test/issue24161_darwin_test.go @@ -0,0 +1,39 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// See issue21897.go and golang.org/issue/26475 for why this is +// skipped in race mode. +// +// TODO(austin): Once support for macOS 10.10 is dropped, remove the +// race constraint. See golang.org/issue/26513. + +// +build !race + +package cgotest + +import ( + "testing" + + "./issue24161arg" + "./issue24161e0" + "./issue24161e1" + "./issue24161e2" + "./issue24161res" +) + +func Test24161Arg(t *testing.T) { + issue24161arg.Test(t) +} +func Test24161Res(t *testing.T) { + issue24161res.Test(t) +} +func Test24161Example0(t *testing.T) { + issue24161e0.Test(t) +} +func Test24161Example1(t *testing.T) { + issue24161e1.Test(t) +} +func Test24161Example2(t *testing.T) { + issue24161e2.Test(t) +} diff --git a/misc/cgo/test/issue24161arg/def.go b/misc/cgo/test/issue24161arg/def.go new file mode 100644 index 0000000000..d33479a891 --- /dev/null +++ b/misc/cgo/test/issue24161arg/def.go @@ -0,0 +1,17 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161arg + +/* +#cgo LDFLAGS: -framework CoreFoundation +#include +*/ +import "C" + +func test24161array() C.CFArrayRef { + return C.CFArrayCreate(0, nil, 0, nil) +} diff --git a/misc/cgo/test/issue24161arg/use.go b/misc/cgo/test/issue24161arg/use.go new file mode 100644 index 0000000000..3e74944013 --- /dev/null +++ b/misc/cgo/test/issue24161arg/use.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161arg + +/* +#cgo LDFLAGS: -framework CoreFoundation +#include +*/ +import "C" +import "testing" + +func Test(t *testing.T) { + a := test24161array() + C.CFArrayCreateCopy(0, a) +} diff --git a/misc/cgo/test/issue24161e0/main.go b/misc/cgo/test/issue24161e0/main.go new file mode 100644 index 0000000000..cbc1deea78 --- /dev/null +++ b/misc/cgo/test/issue24161e0/main.go @@ -0,0 +1,29 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161e0 + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework CoreFoundation -framework Security +#include +#include +#include +#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200 + typedef CFStringRef SecKeyAlgorithm; + static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;} + #define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo() + static SecKeyAlgorithm foo(void){return NULL;} +#endif +*/ +import "C" +import "testing" + +func f1() { + C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil) +} + +func Test(t *testing.T) {} diff --git a/misc/cgo/test/issue24161e1/main.go b/misc/cgo/test/issue24161e1/main.go new file mode 100644 index 0000000000..eb48fc0059 --- /dev/null +++ b/misc/cgo/test/issue24161e1/main.go @@ -0,0 +1,38 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161e1 + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework CoreFoundation -framework Security +#include +#include +#include +#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200 + typedef CFStringRef SecKeyAlgorithm; + static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;} + #define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo() + static SecKeyAlgorithm foo(void){return NULL;} +#endif +*/ +import "C" +import ( + "fmt" + "testing" +) + +func f1() { + C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil) +} + +func f2(e C.CFErrorRef) { + if desc := C.CFErrorCopyDescription(e); desc != 0 { + fmt.Println(desc) + } +} + +func Test(t *testing.T) {} diff --git a/misc/cgo/test/issue24161e2/main.go b/misc/cgo/test/issue24161e2/main.go new file mode 100644 index 0000000000..1951c86317 --- /dev/null +++ b/misc/cgo/test/issue24161e2/main.go @@ -0,0 +1,40 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161e2 + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework CoreFoundation -framework Security +#include +#include +#include +#if TARGET_OS_IPHONE == 0 && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200 + typedef CFStringRef SecKeyAlgorithm; + static CFDataRef SecKeyCreateSignature(SecKeyRef key, SecKeyAlgorithm algorithm, CFDataRef dataToSign, CFErrorRef *error){return NULL;} + #define kSecKeyAlgorithmECDSASignatureDigestX962SHA1 foo() + static SecKeyAlgorithm foo(void){return NULL;} +#endif +*/ +import "C" +import ( + "fmt" + "testing" +) + +var _ C.CFStringRef + +func f1() { + C.SecKeyCreateSignature(0, C.kSecKeyAlgorithmECDSASignatureDigestX962SHA1, 0, nil) +} + +func f2(e C.CFErrorRef) { + if desc := C.CFErrorCopyDescription(e); desc != 0 { + fmt.Println(desc) + } +} + +func Test(t *testing.T) {} diff --git a/misc/cgo/test/issue24161res/restype.go b/misc/cgo/test/issue24161res/restype.go new file mode 100644 index 0000000000..e5719f22a4 --- /dev/null +++ b/misc/cgo/test/issue24161res/restype.go @@ -0,0 +1,23 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +package issue24161res + +/* +#cgo LDFLAGS: -framework CoreFoundation +#include +*/ +import "C" +import ( + "reflect" + "testing" +) + +func Test(t *testing.T) { + if k := reflect.TypeOf(C.CFArrayCreate(0, nil, 0, nil)).Kind(); k != reflect.Uintptr { + t.Fatalf("bad kind %s\n", k) + } +} diff --git a/misc/cgo/test/issue26066.go b/misc/cgo/test/issue26066.go new file mode 100644 index 0000000000..21028e7479 --- /dev/null +++ b/misc/cgo/test/issue26066.go @@ -0,0 +1,19 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Wrong type of constant with GCC 8 and newer. + +package cgotest + +// const unsigned long long int issue26066 = (const unsigned long long) -1; +import "C" + +import "testing" + +func test26066(t *testing.T) { + var i = int64(C.issue26066) + if i != -1 { + t.Errorf("got %d, want -1", i) + } +} diff --git a/misc/cgo/test/issue26213/jni.h b/misc/cgo/test/issue26213/jni.h new file mode 100644 index 0000000000..0c76979a5a --- /dev/null +++ b/misc/cgo/test/issue26213/jni.h @@ -0,0 +1,29 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// It's going to be hard to include a whole real JVM to test this. +// So we'll simulate a really easy JVM using just the parts we need. + +// This is the relevant part of jni.h. + +// On Android NDK16, jobject is defined like this in C and C++ +typedef void* jobject; + +typedef jobject jclass; +typedef jobject jthrowable; +typedef jobject jstring; +typedef jobject jarray; +typedef jarray jbooleanArray; +typedef jarray jbyteArray; +typedef jarray jcharArray; +typedef jarray jshortArray; +typedef jarray jintArray; +typedef jarray jlongArray; +typedef jarray jfloatArray; +typedef jarray jdoubleArray; +typedef jarray jobjectArray; + +typedef jobject jweak; + +// Note: jvalue is already a non-pointer type due to it being a C union. diff --git a/misc/cgo/test/issue26213/test26213.go b/misc/cgo/test/issue26213/test26213.go new file mode 100644 index 0000000000..5d1f637ff9 --- /dev/null +++ b/misc/cgo/test/issue26213/test26213.go @@ -0,0 +1,46 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue26213 + +/* +#include "jni.h" +*/ +import "C" +import ( + "testing" +) + +func Test26213(t *testing.T) { + var x1 C.jobject = 0 // Note: 0, not nil. That makes sure we use uintptr for these types. + _ = x1 + var x2 C.jclass = 0 + _ = x2 + var x3 C.jthrowable = 0 + _ = x3 + var x4 C.jstring = 0 + _ = x4 + var x5 C.jarray = 0 + _ = x5 + var x6 C.jbooleanArray = 0 + _ = x6 + var x7 C.jbyteArray = 0 + _ = x7 + var x8 C.jcharArray = 0 + _ = x8 + var x9 C.jshortArray = 0 + _ = x9 + var x10 C.jintArray = 0 + _ = x10 + var x11 C.jlongArray = 0 + _ = x11 + var x12 C.jfloatArray = 0 + _ = x12 + var x13 C.jdoubleArray = 0 + _ = x13 + var x14 C.jobjectArray = 0 + _ = x14 + var x15 C.jweak = 0 + _ = x15 +} diff --git a/misc/cgo/test/issue26430.go b/misc/cgo/test/issue26430.go new file mode 100644 index 0000000000..3ad5420989 --- /dev/null +++ b/misc/cgo/test/issue26430.go @@ -0,0 +1,10 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 26430: incomplete typedef leads to inconsistent typedefs error. +// No runtime test; just make sure it compiles. + +package cgotest + +import _ "./issue26430" diff --git a/src/internal/syscall/unix/empty.s b/misc/cgo/test/issue26430/a.go similarity index 51% rename from src/internal/syscall/unix/empty.s rename to misc/cgo/test/issue26430/a.go index 7151ab838b..fbaa46b1e8 100644 --- a/src/internal/syscall/unix/empty.s +++ b/misc/cgo/test/issue26430/a.go @@ -2,6 +2,12 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// This file is here just to make the go tool happy. It allows -// empty function declarations (no function body). -// It is used with "go:linkname". +package a + +// typedef struct S ST; +// static ST* F() { return 0; } +import "C" + +func F1() { + C.F() +} diff --git a/misc/cgo/test/issue26430/b.go b/misc/cgo/test/issue26430/b.go new file mode 100644 index 0000000000..a7c527cde3 --- /dev/null +++ b/misc/cgo/test/issue26430/b.go @@ -0,0 +1,13 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package a + +// typedef struct S ST; +// struct S { int f; }; +import "C" + +func F2(p *C.ST) { + p.f = 1 +} diff --git a/misc/cgo/test/issue26517.go b/misc/cgo/test/issue26517.go new file mode 100644 index 0000000000..c1bf1c9213 --- /dev/null +++ b/misc/cgo/test/issue26517.go @@ -0,0 +1,23 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +// Introduce two pointer types which are distinct, but have the same +// base type. Make sure that both of those pointer types get resolved +// correctly. Before the fix for 26517 if one of these pointer types +// was resolved before the other one was processed, the second one +// would never be resolved. +// Before this issue was fixed this test failed on Windows, +// where va_list expands to a named char* type. + +/* +#include +typedef va_list TypeOne; +typedef char *TypeTwo; +*/ +import "C" + +var a C.TypeOne +var b C.TypeTwo diff --git a/misc/cgo/test/issue26743.go b/misc/cgo/test/issue26743.go new file mode 100644 index 0000000000..35c8473a61 --- /dev/null +++ b/misc/cgo/test/issue26743.go @@ -0,0 +1,10 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Issue 26743: typedef of uint leads to inconsistent typedefs error. +// No runtime test; just make sure it compiles. + +package cgotest + +import _ "./issue26743" diff --git a/misc/cgo/test/issue26743/a.go b/misc/cgo/test/issue26743/a.go new file mode 100644 index 0000000000..a3df1797b3 --- /dev/null +++ b/misc/cgo/test/issue26743/a.go @@ -0,0 +1,11 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue26743 + +// typedef unsigned int uint; +// int C1(uint x) { return x; } +import "C" + +var V1 = C.C1(0) diff --git a/misc/cgo/test/issue26743/b.go b/misc/cgo/test/issue26743/b.go new file mode 100644 index 0000000000..c5f1ae478c --- /dev/null +++ b/misc/cgo/test/issue26743/b.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package issue26743 + +import "C" + +var V2 C.uint diff --git a/misc/cgo/test/issue4029.c b/misc/cgo/test/issue4029.c index 7205c5a5a2..30646ade02 100644 --- a/misc/cgo/test/issue4029.c +++ b/misc/cgo/test/issue4029.c @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows +// +build !windows,!static #include #include diff --git a/misc/cgo/test/issue4029.go b/misc/cgo/test/issue4029.go index 8e468d367d..1bf029d760 100644 --- a/misc/cgo/test/issue4029.go +++ b/misc/cgo/test/issue4029.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !windows +// +build !windows,!static package cgotest diff --git a/misc/cgo/test/issue4029w.go b/misc/cgo/test/issue4029w.go index 18c720191b..eee33f7010 100644 --- a/misc/cgo/test/issue4029w.go +++ b/misc/cgo/test/issue4029w.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build windows +// +build windows static package cgotest diff --git a/misc/cgo/test/issue9400_linux.go b/misc/cgo/test/issue9400_linux.go index 34eb4983a4..7719535d25 100644 --- a/misc/cgo/test/issue9400_linux.go +++ b/misc/cgo/test/issue9400_linux.go @@ -41,7 +41,7 @@ func test9400(t *testing.T) { // Grow the stack and put down a test pattern const pattern = 0x123456789abcdef - var big [1024]uint64 // len must match assmebly + var big [1024]uint64 // len must match assembly for i := range big { big[i] = pattern } diff --git a/misc/cgo/test/test26213.go b/misc/cgo/test/test26213.go new file mode 100644 index 0000000000..176a7ece9c --- /dev/null +++ b/misc/cgo/test/test26213.go @@ -0,0 +1,15 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cgotest + +import ( + "testing" + + "./issue26213" +) + +func test26213(t *testing.T) { + issue26213.Test26213(t) +} diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go index 71232305f6..457ac0db09 100644 --- a/misc/cgo/testcarchive/carchive_test.go +++ b/misc/cgo/testcarchive/carchive_test.go @@ -14,6 +14,7 @@ import ( "os/exec" "path/filepath" "regexp" + "runtime" "strings" "syscall" "testing" @@ -83,13 +84,17 @@ func init() { cc = append(cc, []string{"-framework", "CoreFoundation", "-framework", "Foundation"}...) } libgodir = GOOS + "_" + GOARCH - switch GOOS { - case "darwin": - if GOARCH == "arm" || GOARCH == "arm64" { + if runtime.Compiler == "gccgo" { + libgodir = "gccgo_" + libgodir + "_fPIC" + } else { + switch GOOS { + case "darwin": + if GOARCH == "arm" || GOARCH == "arm64" { + libgodir += "_shared" + } + case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": libgodir += "_shared" } - case "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": - libgodir += "_shared" } cc = append(cc, "-I", filepath.Join("pkg", libgodir)) @@ -155,6 +160,9 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) { } else { ccArgs = append(ccArgs, "main_unix.c", libgoa) } + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } t.Log(ccArgs) if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) @@ -163,7 +171,11 @@ func testInstall(t *testing.T, exe, libgoa, libgoh string, buildcmd ...string) { defer os.Remove(exe) binArgs := append(cmdToRun(exe), "arg1", "arg2") - if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil { + cmd = exec.Command(binArgs[0], binArgs[1:]...) + if runtime.Compiler == "gccgo" { + cmd.Env = append(os.Environ(), "GCCGO=1") + } + if out, err := cmd.CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) } @@ -194,8 +206,13 @@ func checkLineComments(t *testing.T, hdrname string) { func TestInstall(t *testing.T) { defer os.RemoveAll("pkg") + libgoa := "libgo.a" + if runtime.Compiler == "gccgo" { + libgoa = "liblibgo.a" + } + testInstall(t, "./testp1"+exeSuffix, - filepath.Join("pkg", libgodir, "libgo.a"), + filepath.Join("pkg", libgodir, libgoa), filepath.Join("pkg", libgodir, "libgo.h"), "go", "install", "-i", "-buildmode=c-archive", "libgo") @@ -235,6 +252,9 @@ func TestEarlySignalHandler(t *testing.T) { checkLineComments(t, "libgo2.h") ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -265,6 +285,9 @@ func TestSignalForwarding(t *testing.T) { checkLineComments(t, "libgo2.h") ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -306,6 +329,9 @@ func TestSignalForwardingExternal(t *testing.T) { checkLineComments(t, "libgo2.h") ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -419,6 +445,9 @@ func TestOsSignal(t *testing.T) { checkLineComments(t, "libgo3.h") ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -452,6 +481,9 @@ func TestSigaltstack(t *testing.T) { checkLineComments(t, "libgo4.h") ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -476,6 +508,9 @@ func TestExtar(t *testing.T) { case "windows": t.Skip("skipping signal test on Windows") } + if runtime.Compiler == "gccgo" { + t.Skip("skipping -extar test when using gccgo") + } defer func() { os.Remove("libgo4.a") @@ -530,14 +565,26 @@ func TestPIE(t *testing.T) { t.Fatal(err) } - ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, "libgo.a")) + libgoa := "libgo.a" + if runtime.Compiler == "gccgo" { + libgoa = "liblibgo.a" + } + + ccArgs := append(cc, "-fPIE", "-pie", "-o", "testp"+exeSuffix, "main.c", "main_unix.c", filepath.Join("pkg", libgodir, libgoa)) + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) } binArgs := append(bin, "arg1", "arg2") - if out, err := exec.Command(binArgs[0], binArgs[1:]...).CombinedOutput(); err != nil { + cmd = exec.Command(binArgs[0], binArgs[1:]...) + if runtime.Compiler == "gccgo" { + cmd.Env = append(os.Environ(), "GCCGO=1") + } + if out, err := cmd.CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) } @@ -605,6 +652,9 @@ func TestSIGPROF(t *testing.T) { checkLineComments(t, "libgo6.h") ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } if out, err := exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput(); err != nil { t.Logf("%s", out) t.Fatal(err) @@ -648,6 +698,9 @@ func TestCompileWithoutShared(t *testing.T) { // In some cases, -no-pie is needed here, but not accepted everywhere. First try // if -no-pie is accepted. See #22126. ccArgs := append(cc, "-o", exe, "-no-pie", "main5.c", "libgo2.a") + if runtime.Compiler == "gccgo" { + ccArgs = append(ccArgs, "-lgo") + } t.Log(ccArgs) out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput() diff --git a/misc/cgo/testcarchive/main_unix.c b/misc/cgo/testcarchive/main_unix.c index 4d9d16f03b..b23ac1c242 100644 --- a/misc/cgo/testcarchive/main_unix.c +++ b/misc/cgo/testcarchive/main_unix.c @@ -5,6 +5,7 @@ #include #include #include +#include #include struct sigaction sa; @@ -30,7 +31,12 @@ int install_handler() { perror("sigaction"); return 2; } - if (osa.sa_handler == SIG_DFL || (osa.sa_flags&SA_ONSTACK) == 0) { + if (osa.sa_handler == SIG_DFL) { + fprintf(stderr, "Go runtime did not install signal handler\n"); + return 2; + } + // gccgo does not set SA_ONSTACK for SIGSEGV. + if (getenv("GCCGO") == "" && (osa.sa_flags&SA_ONSTACK) == 0) { fprintf(stderr, "Go runtime did not install signal handler\n"); return 2; } diff --git a/misc/cgo/testcarchive/src/libgo3/libgo3.go b/misc/cgo/testcarchive/src/libgo3/libgo3.go index e276a3c347..3725f7ab0f 100644 --- a/misc/cgo/testcarchive/src/libgo3/libgo3.go +++ b/misc/cgo/testcarchive/src/libgo3/libgo3.go @@ -29,13 +29,13 @@ func ResetSIGIO() { signal.Reset(syscall.SIGIO) } -// SawSIGIO returns whether we saw a SIGIO within a brief pause. +// SawSIGIO reports whether we saw a SIGIO. //export SawSIGIO func SawSIGIO() C.int { select { case <-sigioChan: return 1 - case <-time.After(100 * time.Millisecond): + case <-time.After(5 * time.Second): return 0 } } diff --git a/misc/cgo/testcshared/cshared_test.go b/misc/cgo/testcshared/cshared_test.go index 77cefc5a66..89b19d653a 100644 --- a/misc/cgo/testcshared/cshared_test.go +++ b/misc/cgo/testcshared/cshared_test.go @@ -201,6 +201,16 @@ func run(t *testing.T, env []string, args ...string) string { t.Helper() cmd := exec.Command(args[0], args[1:]...) cmd.Env = env + + if GOOS != "windows" { + // TestUnexportedSymbols relies on file descriptor 30 + // being closed when the program starts, so enforce + // that in all cases. (The first three descriptors are + // stdin/stdout/stderr, so we just need to make sure + // that cmd.ExtraFiles[27] exists and is nil.) + cmd.ExtraFiles = make([]*os.File, 28) + } + out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("command failed: %v\n%v\n%s\n", args, err, out) diff --git a/misc/cgo/testgodefs/fieldtypedef.go b/misc/cgo/testgodefs/fieldtypedef.go new file mode 100644 index 0000000000..45c0bf8653 --- /dev/null +++ b/misc/cgo/testgodefs/fieldtypedef.go @@ -0,0 +1,18 @@ +// Copyright 2018 The Go Authors. All rights reserve d. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. +// +// +build ignore + +package main + +/* +struct S1 { int f1; }; +struct S2 { struct S1 s1; }; +typedef struct S1 S1Type; +typedef struct S2 S2Type; +*/ +import "C" + +type S1 C.S1Type +type S2 C.S2Type diff --git a/misc/cgo/testgodefs/test.bash b/misc/cgo/testgodefs/test.bash index a82ff9328f..012d007fc3 100755 --- a/misc/cgo/testgodefs/test.bash +++ b/misc/cgo/testgodefs/test.bash @@ -7,7 +7,7 @@ # We are testing cgo -godefs, which translates Go files that use # import "C" into Go files with Go definitions of types defined in the # import "C" block. Add more tests here. -FILE_PREFIXES="anonunion issue8478" +FILE_PREFIXES="anonunion issue8478 fieldtypedef" RM= for FP in $FILE_PREFIXES diff --git a/misc/cgo/testplugin/src/checkdwarf/main.go b/misc/cgo/testplugin/src/checkdwarf/main.go new file mode 100644 index 0000000000..7886c834e7 --- /dev/null +++ b/misc/cgo/testplugin/src/checkdwarf/main.go @@ -0,0 +1,106 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Usage: +// +// checkdwarf +// +// Opens , which must be an executable or a library and checks that +// there is an entry in .debug_info whose name ends in + +package main + +import ( + "debug/dwarf" + "debug/elf" + "debug/macho" + "debug/pe" + "fmt" + "os" + "strings" +) + +func usage() { + fmt.Fprintf(os.Stderr, "checkdwarf executable-or-library DIE-suffix\n") +} + +type dwarfer interface { + DWARF() (*dwarf.Data, error) +} + +func openElf(path string) dwarfer { + exe, err := elf.Open(path) + if err != nil { + return nil + } + return exe +} + +func openMacho(path string) dwarfer { + exe, err := macho.Open(path) + if err != nil { + return nil + } + return exe +} + +func openPE(path string) dwarfer { + exe, err := pe.Open(path) + if err != nil { + return nil + } + return exe +} + +func main() { + if len(os.Args) != 3 { + usage() + } + + exePath := os.Args[1] + dieSuffix := os.Args[2] + + var exe dwarfer + + for _, openfn := range []func(string) dwarfer{openMacho, openPE, openElf} { + exe = openfn(exePath) + if exe != nil { + break + } + } + + if exe == nil { + fmt.Fprintf(os.Stderr, "could not open %s\n", exePath) + os.Exit(1) + } + + data, err := exe.DWARF() + if err != nil { + fmt.Fprintf(os.Stderr, "%s: error opening DWARF: %v\n", exePath, err) + os.Exit(1) + } + + rdr := data.Reader() + for { + e, err := rdr.Next() + if err != nil { + fmt.Fprintf(os.Stderr, "%s: error reading DWARF: %v\n", exePath, err) + os.Exit(1) + } + if e == nil { + break + } + name, hasname := e.Val(dwarf.AttrName).(string) + if !hasname { + continue + } + if strings.HasSuffix(name, dieSuffix) { + // found + os.Exit(0) + } + } + + fmt.Fprintf(os.Stderr, "%s: no entry with a name ending in %q was found\n", exePath, dieSuffix) + os.Exit(1) +} diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash index bf8ed3cd19..1b94bc4bad 100755 --- a/misc/cgo/testplugin/test.bash +++ b/misc/cgo/testplugin/test.bash @@ -32,6 +32,14 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed1.so u GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o=unnamed2.so unnamed2/main.go GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" host +# test that DWARF sections are emitted for plugins and programs importing "plugin" +if [ $GOOS != "darwin" ]; then + # On macOS, for some reason, the linker doesn't add debug sections to .so, + # see issue #27502. + go run src/checkdwarf/main.go plugin2.so plugin2.UnexportedNameReuse +fi +go run src/checkdwarf/main.go host main.main + LD_LIBRARY_PATH=$(pwd) ./host # Test that types and itabs get properly uniqified. diff --git a/misc/cgo/testsanitizers/cc_test.go b/misc/cgo/testsanitizers/cc_test.go index 306844bdc8..f09ad52cee 100644 --- a/misc/cgo/testsanitizers/cc_test.go +++ b/misc/cgo/testsanitizers/cc_test.go @@ -381,12 +381,13 @@ func (c *config) checkRuntime() (skip bool, err error) { return false, err } cmd.Args = append(cmd.Args, "-dM", "-E", "../../../src/runtime/cgo/libcgo.h") + cmdStr := strings.Join(cmd.Args, " ") out, err := cmd.CombinedOutput() if err != nil { - return false, fmt.Errorf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out) + return false, fmt.Errorf("%#q exited with %v\n%s", cmdStr, err, out) } if !bytes.Contains(out, []byte("#define CGO_TSAN")) { - return true, fmt.Errorf("%#q did not define CGO_TSAN") + return true, fmt.Errorf("%#q did not define CGO_TSAN", cmdStr) } return false, nil } diff --git a/misc/cgo/testsanitizers/msan_test.go b/misc/cgo/testsanitizers/msan_test.go index af5afa9ee4..88b90d3d70 100644 --- a/misc/cgo/testsanitizers/msan_test.go +++ b/misc/cgo/testsanitizers/msan_test.go @@ -27,6 +27,7 @@ func TestMSAN(t *testing.T) { {src: "msan3.go"}, {src: "msan4.go"}, {src: "msan5.go"}, + {src: "msan6.go"}, {src: "msan_fail.go", wantErr: true}, } for _, tc := range cases { diff --git a/misc/cgo/testsanitizers/src/msan6.go b/misc/cgo/testsanitizers/src/msan6.go new file mode 100644 index 0000000000..003989c2be --- /dev/null +++ b/misc/cgo/testsanitizers/src/msan6.go @@ -0,0 +1,72 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// A C function returning a value on the Go stack could leave the Go +// stack marked as uninitialized, potentially causing a later error +// when the stack is used for something else. Issue 26209. + +/* +#cgo LDFLAGS: -fsanitize=memory +#cgo CPPFLAGS: -fsanitize=memory + +#include +#include +#include + +typedef struct { + uintptr_t a[20]; +} S; + +S f() { + S *p; + + p = (S *)(malloc(sizeof(S))); + p->a[0] = 0; + return *p; +} +*/ +import "C" + +// allocateStack extends the stack so that stack copying doesn't +// confuse the msan data structures. +//go:noinline +func allocateStack(i int) int { + if i == 0 { + return i + } + return allocateStack(i - 1) +} + +// F1 marks a chunk of stack as uninitialized. +// C.f returns an uninitialized struct on the stack, so msan will mark +// the stack as uninitialized. +//go:noinline +func F1() uintptr { + s := C.f() + return uintptr(s.a[0]) +} + +// F2 allocates a struct on the stack and converts it to an empty interface, +// which will call msanread and see that the data appears uninitialized. +//go:noinline +func F2() interface{} { + return C.S{} +} + +func poisonStack(i int) int { + if i == 0 { + return int(F1()) + } + F1() + r := poisonStack(i - 1) + F2() + return r +} + +func main() { + allocateStack(16384) + poisonStack(128) +} diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go index a296005780..529a2c692f 100644 --- a/misc/cgo/testshared/shared_test.go +++ b/misc/cgo/testshared/shared_test.go @@ -560,7 +560,7 @@ func TestNotes(t *testing.T) { abiHashNoteFound = true case 3: // ELF_NOTE_GODEPS_TAG if depsNoteFound { - t.Error("multiple depedency list notes") + t.Error("multiple dependency list notes") } testDepsNote(t, f, note) depsNoteFound = true @@ -905,3 +905,9 @@ func TestGlobal(t *testing.T) { AssertIsLinkedTo(t, "./bin/global", soname) AssertHasRPath(t, "./bin/global", gorootInstallDir) } + +// Run a test using -linkshared of an installed shared package. +// Issue 26400. +func TestTestInstalledShared(t *testing.T) { + goCmd(nil, "test", "-linkshared", "-test.short", "sync/atomic") +} diff --git a/misc/cgo/testshared/src/depBase/asm.s b/misc/cgo/testshared/src/depBase/asm.s index f203f8b030..a8acf77f0b 100644 --- a/misc/cgo/testshared/src/depBase/asm.s +++ b/misc/cgo/testshared/src/depBase/asm.s @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//+build !gccgo +// +build !gccgo #include "textflag.h" diff --git a/misc/cgo/testshared/src/depBase/dep.go b/misc/cgo/testshared/src/depBase/dep.go index 569c210aa1..e7cc7c81eb 100644 --- a/misc/cgo/testshared/src/depBase/dep.go +++ b/misc/cgo/testshared/src/depBase/dep.go @@ -1,3 +1,7 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + package depBase import ( diff --git a/misc/cgo/testshared/src/depBase/gccgo.go b/misc/cgo/testshared/src/depBase/gccgo.go index 3e2b69b50b..2b02a1e83b 100644 --- a/misc/cgo/testshared/src/depBase/gccgo.go +++ b/misc/cgo/testshared/src/depBase/gccgo.go @@ -1,4 +1,8 @@ -//+build gccgo +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build gccgo package depBase diff --git a/misc/cgo/testshared/src/depBase/stubs.go b/misc/cgo/testshared/src/depBase/stubs.go index 96573c12ec..04534f38dd 100644 --- a/misc/cgo/testshared/src/depBase/stubs.go +++ b/misc/cgo/testshared/src/depBase/stubs.go @@ -1,4 +1,8 @@ -//+build !gccgo +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !gccgo package depBase diff --git a/misc/wasm/wasm_exec.html b/misc/wasm/wasm_exec.html index cc37ea73ce..f5e21e40f3 100644 --- a/misc/wasm/wasm_exec.html +++ b/misc/wasm/wasm_exec.html @@ -27,6 +27,8 @@ license that can be found in the LICENSE file. mod = result.module; inst = result.instance; document.getElementById("runButton").disabled = false; + }).catch((err) => { + console.error(err); }); async function run() { diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js index ecb096509f..94b9552c59 100644 --- a/misc/wasm/wasm_exec.js +++ b/misc/wasm/wasm_exec.js @@ -27,11 +27,17 @@ global.TextEncoder = util.TextEncoder; global.TextDecoder = util.TextDecoder; } else { - window.global = window; + if (typeof window !== "undefined") { + window.global = window; + } else if (typeof self !== "undefined") { + self.global = self; + } else { + throw new Error("cannot export Go (neither window nor self is defined)"); + } let outputBuf = ""; global.fs = { - constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_NONBLOCK: -1, O_SYNC: -1 }, // unused + constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused writeSync(fd, buf) { outputBuf += decoder.decode(buf); const nl = outputBuf.lastIndexOf("\n"); @@ -91,9 +97,11 @@ } const storeValue = (addr, v) => { + const nanHead = 0x7FF80000; + if (typeof v === "number") { if (isNaN(v)) { - mem().setUint32(addr + 4, 0x7FF80000, true); // NaN + mem().setUint32(addr + 4, nanHead, true); mem().setUint32(addr, 0, true); return; } @@ -101,51 +109,44 @@ return; } - mem().setUint32(addr + 4, 0x7FF80000, true); // NaN - switch (v) { case undefined: + mem().setUint32(addr + 4, nanHead, true); mem().setUint32(addr, 1, true); return; case null: + mem().setUint32(addr + 4, nanHead, true); mem().setUint32(addr, 2, true); return; case true: + mem().setUint32(addr + 4, nanHead, true); mem().setUint32(addr, 3, true); return; case false: + mem().setUint32(addr + 4, nanHead, true); mem().setUint32(addr, 4, true); return; } - if (typeof v === "string") { - let ref = this._stringRefs.get(v); - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - this._stringRefs.set(v, ref); - } - mem().setUint32(addr, ref, true); - return; - } - - if (typeof v === "symbol") { - let ref = this._symbolRefs.get(v); - if (ref === undefined) { - ref = this._values.length; - this._values.push(v); - this._symbolRefs.set(v, ref); - } - mem().setUint32(addr, ref, true); - return; - } - - let ref = v[this._refProp]; + let ref = this._refs.get(v); if (ref === undefined) { ref = this._values.length; this._values.push(v); - v[this._refProp] = ref; + this._refs.set(v, ref); } + let typeFlag = 0; + switch (typeof v) { + case "string": + typeFlag = 1; + break; + case "symbol": + typeFlag = 2; + break; + case "function": + typeFlag = 3; + break; + } + mem().setUint32(addr + 4, nanHead | typeFlag, true); mem().setUint32(addr, ref, true); } @@ -176,8 +177,12 @@ go: { // func wasmExit(code int32) "runtime.wasmExit": (sp) => { + const code = mem().getInt32(sp + 8, true); this.exited = true; - this.exit(mem().getInt32(sp + 8, true)); + delete this._inst; + delete this._values; + delete this._refs; + this.exit(code); }, // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) @@ -328,16 +333,10 @@ false, global, this._inst.exports.mem, - () => { // resolveCallbackPromise - if (this.exited) { - throw new Error("bad callback: Go program has already exited"); - } - setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous - }, + this, ]; - this._stringRefs = new Map(); - this._symbolRefs = new Map(); - this._refProp = Symbol(); + this._refs = new Map(); + this._callbackShutdown = false; this.exited = false; const mem = new DataView(this._inst.exports.mem.buffer) @@ -374,7 +373,12 @@ while (true) { const callbackPromise = new Promise((resolve) => { - this._resolveCallbackPromise = resolve; + this._resolveCallbackPromise = () => { + if (this.exited) { + throw new Error("bad callback: Go program has already exited"); + } + setTimeout(resolve, 0); // make sure it is asynchronous + }; }); this._inst.exports.run(argc, argv); if (this.exited) { @@ -383,6 +387,28 @@ await callbackPromise; } } + + static _makeCallbackHelper(id, pendingCallbacks, go) { + return function() { + pendingCallbacks.push({ id: id, args: arguments }); + go._resolveCallbackPromise(); + }; + } + + static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) { + return function(event) { + if (preventDefault) { + event.preventDefault(); + } + if (stopPropagation) { + event.stopPropagation(); + } + if (stopImmediatePropagation) { + event.stopImmediatePropagation(); + } + fn(event); + }; + } } if (isNodeJS) { @@ -396,17 +422,16 @@ go.env = process.env; go.exit = process.exit; WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => { - process.on("exit", () => { // Node.js exits if no callback is pending - if (!go.exited) { - console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!"); - process.exit(1); + process.on("exit", (code) => { // Node.js exits if no callback is pending + if (code === 0 && !go.exited) { + // deadlock, make Go print error and stack traces + go._callbackShutdown = true; + go._inst.exports.run(); } }); return go.run(result.instance); }).catch((err) => { - console.error(err); - go.exited = true; - process.exit(1); + throw err; }); } })(); diff --git a/src/archive/tar/format.go b/src/archive/tar/format.go index 1f89d0c59a..cfe24a5e1d 100644 --- a/src/archive/tar/format.go +++ b/src/archive/tar/format.go @@ -160,7 +160,7 @@ func (b *block) V7() *headerV7 { return (*headerV7)(b) } func (b *block) GNU() *headerGNU { return (*headerGNU)(b) } func (b *block) STAR() *headerSTAR { return (*headerSTAR)(b) } func (b *block) USTAR() *headerUSTAR { return (*headerUSTAR)(b) } -func (b *block) Sparse() sparseArray { return (sparseArray)(b[:]) } +func (b *block) Sparse() sparseArray { return sparseArray(b[:]) } // GetFormat checks that the block is a valid tar header based on the checksum. // It then attempts to guess the specific format based on magic values. @@ -263,7 +263,7 @@ func (h *headerGNU) DevMajor() []byte { return h[329:][:8] } func (h *headerGNU) DevMinor() []byte { return h[337:][:8] } func (h *headerGNU) AccessTime() []byte { return h[345:][:12] } func (h *headerGNU) ChangeTime() []byte { return h[357:][:12] } -func (h *headerGNU) Sparse() sparseArray { return (sparseArray)(h[386:][:24*4+1]) } +func (h *headerGNU) Sparse() sparseArray { return sparseArray(h[386:][:24*4+1]) } func (h *headerGNU) RealSize() []byte { return h[483:][:12] } type headerSTAR [blockSize]byte @@ -293,7 +293,7 @@ func (h *headerUSTAR) Prefix() []byte { return h[345:][:155] } type sparseArray []byte -func (s sparseArray) Entry(i int) sparseElem { return (sparseElem)(s[i*24:]) } +func (s sparseArray) Entry(i int) sparseElem { return sparseElem(s[i*24:]) } func (s sparseArray) IsExtended() []byte { return s[24*s.MaxEntries():][:1] } func (s sparseArray) MaxEntries() int { return len(s) / 24 } diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go index 2444106ba6..2260b398c3 100644 --- a/src/archive/zip/reader.go +++ b/src/archive/zip/reader.go @@ -69,6 +69,9 @@ func OpenReader(name string) (*ReadCloser, error) { // NewReader returns a new Reader reading from r, which is assumed to // have the given size in bytes. func NewReader(r io.ReaderAt, size int64) (*Reader, error) { + if size < 0 { + return nil, errors.New("zip: size cannot be negative") + } zr := new(Reader) if err := zr.init(r, size); err != nil { return nil, err diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index 1e58b26b6e..6b3f2f33bb 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -658,6 +658,12 @@ func TestInvalidFiles(t *testing.T) { if err != ErrFormat { t.Errorf("sigs: error=%v, want %v", err, ErrFormat) } + + // negative size + _, err = NewReader(bytes.NewReader([]byte("foobar")), -1) + if err == nil { + t.Errorf("archive/zip.NewReader: expected error when negative size is passed") + } } func messWith(fileName string, corrupter func(b []byte)) (r io.ReaderAt, size int64) { diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go index c90151d9d4..bd637d185b 100644 --- a/src/archive/zip/struct.go +++ b/src/archive/zip/struct.go @@ -303,8 +303,8 @@ func (h *FileHeader) SetMode(mode os.FileMode) { } // isZip64 reports whether the file size exceeds the 32 bit limit -func (fh *FileHeader) isZip64() bool { - return fh.CompressedSize64 >= uint32max || fh.UncompressedSize64 >= uint32max +func (h *FileHeader) isZip64() bool { + return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max } func msdosModeToFileMode(m uint32) (mode os.FileMode) { diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go index 506148ee30..5f0c0a1a55 100644 --- a/src/archive/zip/writer.go +++ b/src/archive/zip/writer.go @@ -336,6 +336,12 @@ func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { fh.Method = Store fh.Flags &^= 0x8 // we will not write a data descriptor + // Explicitly clear sizes as they have no meaning for directories. + fh.CompressedSize = 0 + fh.CompressedSize64 = 0 + fh.UncompressedSize = 0 + fh.UncompressedSize64 = 0 + ow = dirWriter{} } else { fh.Flags |= 0x8 // we will write a data descriptor @@ -419,7 +425,10 @@ func (w *Writer) compressor(method uint16) Compressor { type dirWriter struct{} -func (dirWriter) Write([]byte) (int, error) { +func (dirWriter) Write(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } return 0, errors.New("zip: write to directory") } diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go index 468424c72a..1fedfd85e8 100644 --- a/src/archive/zip/writer_test.go +++ b/src/archive/zip/writer_test.go @@ -306,21 +306,28 @@ func TestWriterDir(t *testing.T) { if err != nil { t.Fatal(err) } + if _, err := dw.Write(nil); err != nil { + t.Errorf("Write(nil) to directory: got %v, want nil", err) + } if _, err := dw.Write([]byte("hello")); err == nil { - t.Error("Write to directory: got nil error, want non-nil") + t.Error(`Write("hello") to directory: got nil error, want non-nil`) } } func TestWriterDirAttributes(t *testing.T) { var buf bytes.Buffer w := NewWriter(&buf) - if _, err := w.Create("dir/"); err != nil { + if _, err := w.CreateHeader(&FileHeader{ + Name: "dir/", + Method: Deflate, + CompressedSize64: 1234, + UncompressedSize64: 5678, + }); err != nil { t.Fatal(err) } if err := w.Close(); err != nil { t.Fatal(err) } - b := buf.Bytes() var sig [4]byte diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go index 72545a7509..8d162b34a0 100644 --- a/src/bufio/bufio.go +++ b/src/bufio/bufio.go @@ -63,7 +63,7 @@ func NewReader(rd io.Reader) *Reader { } // Size returns the size of the underlying buffer in bytes. -func (r *Reader) Size() int { return len(r.buf) } +func (b *Reader) Size() int { return len(b.buf) } // Reset discards any buffered data, resets all state, and switches // the buffered reader to read from r. @@ -314,9 +314,11 @@ func (b *Reader) Buffered() int { return b.w - b.r } // ReadBytes or ReadString instead. // ReadSlice returns err != nil if and only if line does not end in delim. func (b *Reader) ReadSlice(delim byte) (line []byte, err error) { + s := 0 // search start index for { // Search buffer. - if i := bytes.IndexByte(b.buf[b.r:b.w], delim); i >= 0 { + if i := bytes.IndexByte(b.buf[b.r+s:b.w], delim); i >= 0 { + i += s line = b.buf[b.r : b.r+i+1] b.r += i + 1 break @@ -338,6 +340,8 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) { break } + s = b.w - b.r // do not rescan area we scanned before + b.fill() // buffer is not full } diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index a2eca2ed12..14c5bc38d6 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -441,9 +441,9 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) { // NewBuffer creates and initializes a new Buffer using buf as its // initial contents. The new Buffer takes ownership of buf, and the // caller should not use buf after this call. NewBuffer is intended to -// prepare a Buffer to read existing data. It can also be used to size -// the internal buffer for writing. To do that, buf should have the -// desired capacity but a length of zero. +// prepare a Buffer to read existing data. It can also be used to set +// the initial size of the internal buffer for writing. To do that, +// buf should have the desired capacity but a length of zero. // // In most cases, new(Buffer) (or just declaring a Buffer variable) is // sufficient to initialize a Buffer. diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index acbe5ca0c4..6e9d6952a5 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -293,7 +293,7 @@ func TestReadFromPanicReader(t *testing.T) { } check(t, "TestReadFromPanicReader (1)", &buf, "") - // Confirm that when Reader panics, the emtpy buffer remains empty + // Confirm that when Reader panics, the empty buffer remains empty var buf2 Buffer defer func() { recover() diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 437a6e12df..77a7ce98e0 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -489,19 +489,19 @@ func ToTitle(s []byte) []byte { return Map(unicode.ToTitle, s) } // ToUpperSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // upper case, giving priority to the special casing rules. func ToUpperSpecial(c unicode.SpecialCase, s []byte) []byte { - return Map(func(r rune) rune { return c.ToUpper(r) }, s) + return Map(c.ToUpper, s) } // ToLowerSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // lower case, giving priority to the special casing rules. func ToLowerSpecial(c unicode.SpecialCase, s []byte) []byte { - return Map(func(r rune) rune { return c.ToLower(r) }, s) + return Map(c.ToLower, s) } // ToTitleSpecial treats s as UTF-8-encoded bytes and returns a copy with all the Unicode letters mapped to their // title case, giving priority to the special casing rules. func ToTitleSpecial(c unicode.SpecialCase, s []byte) []byte { - return Map(func(r rune) rune { return c.ToTitle(r) }, s) + return Map(c.ToTitle, s) } // isSeparator reports whether the rune could mark a word boundary. diff --git a/src/bytes/compare_test.go b/src/bytes/compare_test.go index 35088a1b2e..3e33c27c9c 100644 --- a/src/bytes/compare_test.go +++ b/src/bytes/compare_test.go @@ -6,6 +6,7 @@ package bytes_test import ( . "bytes" + "internal/testenv" "testing" ) @@ -58,10 +59,20 @@ func TestCompareIdenticalSlice(t *testing.T) { } func TestCompareBytes(t *testing.T) { - n := 128 + lengths := make([]int, 0) // lengths to test in ascending order + for i := 0; i <= 128; i++ { + lengths = append(lengths, i) + } + lengths = append(lengths, 256, 512, 1024, 1333, 4095, 4096, 4097) + + if !testing.Short() || testenv.Builder() != "" { + lengths = append(lengths, 65535, 65536, 65537, 99999) + } + + n := lengths[len(lengths)-1] a := make([]byte, n+1) b := make([]byte, n+1) - for len := 0; len < 128; len++ { + for _, len := range lengths { // randomish but deterministic data. No 0 or 255. for i := 0; i < len; i++ { a[i] = byte(1 + 31*i%254) diff --git a/src/bytes/example_test.go b/src/bytes/example_test.go index 5b7a46058f..4d5cdfa280 100644 --- a/src/bytes/example_test.go +++ b/src/bytes/example_test.go @@ -39,6 +39,14 @@ func ExampleBuffer_Grow() { // Output: "64 bytes or fewer" } +func ExampleBuffer_Len() { + var b bytes.Buffer + b.Grow(64) + b.Write([]byte("abcde")) + fmt.Printf("%d", b.Len()) + // Output: 5 +} + func ExampleCompare() { // Interpret Compare's result by comparing it to zero. var a, b []byte diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index 0e4d63744b..ecea6ba97d 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Package arch defines architecture-specific information and support functions. package arch import ( diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index 475d7da5f9..98858bd181 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -74,11 +74,12 @@ func IsARM64STLXR(op obj.As) bool { arm64.ASTXRB, arm64.ASTXRH, arm64.ASTXRW, arm64.ASTXR, arm64.ASTXP, arm64.ASTXPW, arm64.ASTLXP, arm64.ASTLXPW, arm64.ASWPB, arm64.ASWPH, arm64.ASWPW, arm64.ASWPD, + arm64.ASWPALB, arm64.ASWPALH, arm64.ASWPALW, arm64.ASWPALD, arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD, arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD, arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD, arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD, - arm64.ALDADDALD, arm64.ALDADDALW: + arm64.ALDADDALD, arm64.ALDADDALW, arm64.ALDADDALH, arm64.ALDADDALB: return true } return false diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go index 1e2d5d39ed..627be09d08 100644 --- a/src/cmd/asm/internal/asm/asm.go +++ b/src/cmd/asm/internal/asm/asm.go @@ -137,7 +137,7 @@ func (p *Parser) asmText(operands [][]lex.Token) { // Bizarre syntax: $frameSize-argSize is two words, not subtraction. // Both frameSize and argSize must be simple integers; only frameSize // can be negative. - // The "-argSize" may be missing; if so, set it to obj.ArgsSizeUnknown. + // The "-argSize" may be missing; if so, set it to objabi.ArgsSizeUnknown. // Parse left to right. op := operands[next] if len(op) < 2 || op[0].ScanToken != '$' { diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go index 1d1cf510cb..df60b71ebd 100644 --- a/src/cmd/asm/internal/asm/operand_test.go +++ b/src/cmd/asm/internal/asm/operand_test.go @@ -33,7 +33,7 @@ func newParser(goarch string) *Parser { // tryParse executes parse func in panicOnError=true context. // parse is expected to call any parsing methods that may panic. -// Returns error gathered from recover; nil if no parse errors occured. +// Returns error gathered from recover; nil if no parse errors occurred. // // For unexpected panics, calls t.Fatal. func tryParse(t *testing.T, parse func()) (err error) { diff --git a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s index afd1dfd313..2f0d9ecf86 100644 --- a/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s +++ b/src/cmd/asm/internal/asm/testdata/amd64enc_extra.s @@ -911,7 +911,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 VADDPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95808 VMAXPD.BCST (AX), Z2, K1, Z1 // 62f1ed595f08 VMAXPD.BCST.Z (AX), Z2, K1, Z1 // 62f1edd95f08 - // EVEX: surpress all exceptions (SAE). + // EVEX: suppress all exceptions (SAE). VMAXPD.SAE Z3, Z2, K1, Z1 // 62f1ed595fcb or 62f1ed195fcb VMAXPD.SAE.Z Z3, Z2, K1, Z1 // 62f1edd95fcb or 62f1ed995fcb VMAXPD (AX), Z2, K1, Z1 // 62f1ed495f08 diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 859f71a26b..361b7a45c0 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -163,6 +163,21 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 MOVB (R29)(R30<<0), R14 // ae7bbe38 MOVB (R29)(R30), R14 // MOVB (R29)(R30*1), R14 // ae6bbe38 MOVB R4, (R2)(R6.SXTX) // 44e82638 + FMOVS $(4.0), F0 // 0010221e + FMOVD $(4.0), F0 // 0010621e + FMOVS $(0.265625), F1 // 01302a1e + FMOVD $(0.1796875), F2 // 02f0681e + FMOVS $(0.96875), F3 // 03f02d1e + FMOVD $(28.0), F4 // 0490671e + + FMOVS (R2)(R6), F4 // FMOVS (R2)(R6*1), F4 // 446866bc + FMOVS (R2)(R6<<2), F4 // 447866bc + FMOVD (R2)(R6), F4 // FMOVD (R2)(R6*1), F4 // 446866fc + FMOVD (R2)(R6<<3), F4 // 447866fc + FMOVS F4, (R2)(R6) // FMOVS F4, (R2)(R6*1) // 446826bc + FMOVS F4, (R2)(R6<<2) // 447826bc + FMOVD F4, (R2)(R6) // FMOVD F4, (R2)(R6*1) // 446826fc + FMOVD F4, (R2)(R6<<3) // 447826fc // LTYPE1 imsr ',' spreg ',' // { @@ -470,14 +485,14 @@ again: // { // outcode($1, &$2, NREG, &$4); // } - FADDD $0.5, F1 // FADDD $(0.5), F1 +// FADDD $0.5, F1 // FADDD $(0.5), F1 FADDD F1, F2 // LTYPEK frcon ',' freg ',' freg // { // outcode($1, &$2, $4.reg, &$6); // } - FADDD $0.7, F1, F2 // FADDD $(0.69999999999999996), F1, F2 +// FADDD $0.7, F1, F2 // FADDD $(0.69999999999999996), F1, F2 FADDD F1, F2, F3 // @@ -572,6 +587,14 @@ again: SWPH R5, (RSP), R7 // e7832578 SWPB R5, (R6), R7 // c7802538 SWPB R5, (RSP), R7 // e7832538 + SWPALD R5, (R6), R7 // c780e5f8 + SWPALD R5, (RSP), R7 // e783e5f8 + SWPALW R5, (R6), R7 // c780e5b8 + SWPALW R5, (RSP), R7 // e783e5b8 + SWPALH R5, (R6), R7 // c780e578 + SWPALH R5, (RSP), R7 // e783e578 + SWPALB R5, (R6), R7 // c780e538 + SWPALB R5, (RSP), R7 // e783e538 LDADDD R5, (R6), R7 // c70025f8 LDADDD R5, (RSP), R7 // e70325f8 LDADDW R5, (R6), R7 // c70025b8 @@ -605,7 +628,9 @@ again: LDORB R5, (R6), R7 // c7302538 LDORB R5, (RSP), R7 // e7332538 LDADDALD R2, (R1), R3 // 2300e2f8 - LDADDALW R5, (R4), R6 // 8600e5b8 + LDADDALW R2, (R1), R3 // 2300e2b8 + LDADDALH R2, (R1), R3 // 2300e278 + LDADDALB R2, (R1), R3 // 2300e238 // RET // @@ -716,6 +741,86 @@ again: STPW (R3, R4), x(SB) STPW (R3, R4), x+8(SB) +// bit field operation + BFI $0, R1, $1, R2 // 220040b3 + BFIW $0, R1, $1, R2 // 22000033 + SBFIZ $0, R1, $1, R2 // 22004093 + SBFIZW $0, R1, $1, R2 // 22000013 + UBFIZ $0, R1, $1, R2 // 220040d3 + UBFIZW $0, R1, $1, R2 // 22000053 + +// FSTPD/FSTPS/FLDPD/FLDPS + FLDPD (R0), (F1, F2) // 0108406d + FLDPD 8(R0), (F1, F2) // 0188406d + FLDPD -8(R0), (F1, F2) // 01887f6d + FLDPD 11(R0), (F1, F2) // 1b2c0091610b406d + FLDPD 1024(R0), (F1, F2) // 1b001091610b406d + FLDPD.W 8(R0), (F1, F2) // 0188c06d + FLDPD.P 8(R0), (F1, F2) // 0188c06c + FLDPD (RSP), (F1, F2) // e10b406d + FLDPD 8(RSP), (F1, F2) // e18b406d + FLDPD -8(RSP), (F1, F2) // e18b7f6d + FLDPD 11(RSP), (F1, F2) // fb2f0091610b406d + FLDPD 1024(RSP), (F1, F2) // fb031091610b406d + FLDPD.W 8(RSP), (F1, F2) // e18bc06d + FLDPD.P 8(RSP), (F1, F2) // e18bc06c + FLDPD -31(R0), (F1, F2) // 1b7c00d1610b406d + FLDPD -4(R0), (F1, F2) // 1b1000d1610b406d + FLDPD -8(R0), (F1, F2) // 01887f6d + FLDPD x(SB), (F1, F2) + FLDPD x+8(SB), (F1, F2) + FLDPS -5(R0), (F1, F2) // 1b1400d1610b402d + FLDPS (R0), (F1, F2) // 0108402d + FLDPS 4(R0), (F1, F2) // 0188402d + FLDPS -4(R0), (F1, F2) // 01887f2d + FLDPS.W 4(R0), (F1, F2) // 0188c02d + FLDPS.P 4(R0), (F1, F2) // 0188c02c + FLDPS 11(R0), (F1, F2) // 1b2c0091610b402d + FLDPS 1024(R0), (F1, F2) // 1b001091610b402d + FLDPS (RSP), (F1, F2) // e10b402d + FLDPS 4(RSP), (F1, F2) // e18b402d + FLDPS -4(RSP), (F1, F2) // e18b7f2d + FLDPS.W 4(RSP), (F1, F2) // e18bc02d + FLDPS.P 4(RSP), (F1, F2) // e18bc02c + FLDPS 11(RSP), (F1, F2) // fb2f0091610b402d + FLDPS 1024(RSP), (F1, F2) // fb031091610b402d + FLDPS x(SB), (F1, F2) + FLDPS x+8(SB), (F1, F2) + FSTPD (F3, F4), (R5) // a310006d + FSTPD (F3, F4), 8(R5) // a390006d + FSTPD.W (F3, F4), 8(R5) // a390806d + FSTPD.P (F3, F4), 8(R5) // a390806c + FSTPD (F3, F4), -8(R5) // a3903f6d + FSTPD (F3, F4), -4(R5) // bb1000d16313006d + FSTPD (F3, F4), 11(R0) // 1b2c00916313006d + FSTPD (F3, F4), 1024(R0) // 1b0010916313006d + FSTPD (F3, F4), (RSP) // e313006d + FSTPD (F3, F4), 8(RSP) // e393006d + FSTPD.W (F3, F4), 8(RSP) // e393806d + FSTPD.P (F3, F4), 8(RSP) // e393806c + FSTPD (F3, F4), -8(RSP) // e3933f6d + FSTPD (F3, F4), 11(RSP) // fb2f00916313006d + FSTPD (F3, F4), 1024(RSP) // fb0310916313006d + FSTPD (F3, F4), x(SB) + FSTPD (F3, F4), x+8(SB) + FSTPS (F3, F4), (R5) // a310002d + FSTPS (F3, F4), 4(R5) // a390002d + FSTPS.W (F3, F4), 4(R5) // a390802d + FSTPS.P (F3, F4), 4(R5) // a390802c + FSTPS (F3, F4), -4(R5) // a3903f2d + FSTPS (F3, F4), -5(R5) // bb1400d16313002d + FSTPS (F3, F4), 11(R0) // 1b2c00916313002d + FSTPS (F3, F4), 1024(R0) // 1b0010916313002d + FSTPS (F3, F4), (RSP) // e313002d + FSTPS (F3, F4), 4(RSP) // e393002d + FSTPS.W (F3, F4), 4(RSP) // e393802d + FSTPS.P (F3, F4), 4(RSP) // e393802c + FSTPS (F3, F4), -4(RSP) // e3933f2d + FSTPS (F3, F4), 11(RSP) // fb2f00916313002d + FSTPS (F3, F4), 1024(RSP) // fb0310916313002d + FSTPS (F3, F4), x(SB) + FSTPS (F3, F4), x+8(SB) + // END // // LTYPEE comma diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index be2251e442..b2ec0cc425 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -89,4 +89,9 @@ TEXT errors(SB),$0 CSEL LT, R1, R2 // ERROR "illegal combination" AND $0x22220000, R2, RSP // ERROR "illegal combination" ANDS $0x22220000, R2, RSP // ERROR "illegal combination" + LDP (R0), (F0, F1) // ERROR "invalid register pair" + LDP (R0), (R3, ZR) // ERROR "invalid register pair" + STP (F2, F3), (R0) // ERROR "invalid register pair" + FLDPD (R0), (R1, R2) // ERROR "invalid register pair" + FSTPD (R1, R2), (R0) // ERROR "invalid register pair" RET diff --git a/src/cmd/asm/internal/asm/testdata/s390x.s b/src/cmd/asm/internal/asm/testdata/s390x.s index fce855ee30..ad70d2af44 100644 --- a/src/cmd/asm/internal/asm/testdata/s390x.s +++ b/src/cmd/asm/internal/asm/testdata/s390x.s @@ -115,6 +115,7 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16- NEGW R1 // b9130011 NEGW R1, R2 // b9130021 FLOGR R2, R2 // b9830022 + POPCNT R3, R4 // b9e10043 AND R1, R2 // b9800021 AND R1, R2, R3 // b9e42031 diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go index 8dceb25ca6..4462136bf4 100644 --- a/src/cmd/cgo/ast.go +++ b/src/cmd/cgo/ast.go @@ -95,7 +95,7 @@ func (f *File) ParseGo(name string, src []byte) { } } if !sawC { - error_(token.NoPos, `cannot find import "C"`) + error_(ast1.Package, `cannot find import "C"`) } // In ast2, strip the import "C" line. diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go index 4bd82ebd12..157cd94d65 100644 --- a/src/cmd/cgo/doc.go +++ b/src/cmd/cgo/doc.go @@ -104,10 +104,13 @@ compiled with the C compiler. Any .cc, .cpp, or .cxx files will be compiled with the C++ compiler. Any .f, .F, .for or .f90 files will be compiled with the fortran compiler. Any .h, .hh, .hpp, or .hxx files will not be compiled separately, but, if these header files are changed, -the C and C++ files will be recompiled. The default C and C++ -compilers may be changed by the CC and CXX environment variables, -respectively; those environment variables may include command line -options. +the package (including its non-Go source files) will be recompiled. +Note that changes to files in other directories do not cause the package +to be recompiled, so all non-Go source code for the package should be +stored in the package directory, not in subdirectories. +The default C and C++ compilers may be changed by the CC and CXX +environment variables, respectively; those environment variables +may include command line options. The cgo tool is enabled by default for native builds on systems where it is expected to work. It is disabled by default when @@ -377,6 +380,14 @@ and of course there is nothing stopping the C code from doing anything it likes. However, programs that break these rules are likely to fail in unexpected and unpredictable ways. +Note: the current implementation has a bug. While Go code is permitted +to write nil or a C pointer (but not a Go pointer) to C memory, the +current implementation may sometimes cause a runtime error if the +contents of the C memory appear to be a Go pointer. Therefore, avoid +passing uninitialized C memory to Go code if the Go code is going to +store pointer values in it. Zero out the memory in C before passing it +to Go. + Special cases A few special C types which would normally be represented by a pointer diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go index ae1df0d90f..019ee64c8e 100644 --- a/src/cmd/cgo/gcc.go +++ b/src/cmd/cgo/gcc.go @@ -164,9 +164,29 @@ func (p *Package) Translate(f *File) { cref.Name.C = cname(cref.Name.Go) } p.loadDefines(f) - needType := p.guessKinds(f) - if len(needType) > 0 { - p.loadDWARF(f, needType) + p.typedefs = map[string]bool{} + p.typedefList = nil + numTypedefs := -1 + for len(p.typedefs) > numTypedefs { + numTypedefs = len(p.typedefs) + // Also ask about any typedefs we've seen so far. + for _, a := range p.typedefList { + f.Name[a] = &Name{ + Go: a, + C: a, + } + } + needType := p.guessKinds(f) + if len(needType) > 0 { + p.loadDWARF(f, needType) + } + + // In godefs mode we're OK with the typedefs, which + // will presumably also be defined in the file, we + // don't want to resolve them to their base types. + if *godefs { + break + } } if p.rewriteCalls(f) { // Add `import _cgo_unsafe "unsafe"` after the package statement. @@ -551,6 +571,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) { fatalf("malformed __cgo__ name: %s", name) } types[i] = t.Type + p.recordTypedefs(t.Type) } if e.Tag != dwarf.TagCompileUnit { r.SkipChildren() @@ -586,7 +607,25 @@ func (p *Package) loadDWARF(f *File, names []*Name) { } } case "fconst": - if i < len(floats) { + if i >= len(floats) { + break + } + switch base(types[i]).(type) { + case *dwarf.IntType, *dwarf.UintType: + // This has an integer type so it's + // not really a floating point + // constant. This can happen when the + // C compiler complains about using + // the value as an integer constant, + // but not as a general constant. + // Treat this as a variable of the + // appropriate type, not a constant, + // to get C-style type handling, + // avoiding the problem that C permits + // uint64(-1) but Go does not. + // See issue 26066. + n.Kind = "var" + default: n.Const = fmt.Sprintf("%f", floats[i]) } case "sconst": @@ -599,6 +638,47 @@ func (p *Package) loadDWARF(f *File, names []*Name) { } } +// recordTypedefs remembers in p.typedefs all the typedefs used in dtypes and its children. +func (p *Package) recordTypedefs(dtype dwarf.Type) { + p.recordTypedefs1(dtype, map[dwarf.Type]bool{}) +} +func (p *Package) recordTypedefs1(dtype dwarf.Type, visited map[dwarf.Type]bool) { + if dtype == nil { + return + } + if visited[dtype] { + return + } + visited[dtype] = true + switch dt := dtype.(type) { + case *dwarf.TypedefType: + if strings.HasPrefix(dt.Name, "__builtin") { + // Don't look inside builtin types. There be dragons. + return + } + if !p.typedefs[dt.Name] { + p.typedefs[dt.Name] = true + p.typedefList = append(p.typedefList, dt.Name) + p.recordTypedefs1(dt.Type, visited) + } + case *dwarf.PtrType: + p.recordTypedefs1(dt.Type, visited) + case *dwarf.ArrayType: + p.recordTypedefs1(dt.Type, visited) + case *dwarf.QualType: + p.recordTypedefs1(dt.Type, visited) + case *dwarf.FuncType: + p.recordTypedefs1(dt.ReturnType, visited) + for _, a := range dt.ParamType { + p.recordTypedefs1(a, visited) + } + case *dwarf.StructType: + for _, f := range dt.Field { + p.recordTypedefs1(f.Type, visited) + } + } +} + // mangleName does name mangling to translate names // from the original Go source files to the names // used in the final Go files generated by cgo. @@ -1613,6 +1693,9 @@ func (p *Package) gccErrors(stdin []byte) string { } } + // Force -O0 optimization + nargs = append(nargs, "-O0") + if *debugGcc { fmt.Fprintf(os.Stderr, "$ %s < 0 { dtype := c.ptrKeys[0] c.ptrKeys = c.ptrKeys[1:] + ptrs := c.ptrs[dtype] + delete(c.ptrs, dtype) // Note Type might invalidate c.ptrs[dtype]. t := c.Type(dtype, pos) - for _, ptr := range c.ptrs[dtype] { + for _, ptr := range ptrs { ptr.Go.(*ast.StarExpr).X = t.Go ptr.C.Set("%s*", t.C) } - c.ptrs[dtype] = nil // retain the map key } } @@ -2085,6 +2170,10 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { s := *sub s.Go = c.uintptr sub = &s + // Make sure we update any previously computed type. + if oldType := typedef[name.Name]; oldType != nil { + oldType.Go = sub.Go + } } t.Go = name if unionWithPointer[sub.Go] { @@ -2246,7 +2335,7 @@ func (c *typeConv) FuncArg(dtype dwarf.Type, pos token.Pos) *Type { } // ...or the typedef is one in which we expect bad pointers. // It will be a uintptr instead of *X. - if c.badPointerTypedef(dt) { + if c.baseBadPointerTypedef(dt) { break } @@ -2598,6 +2687,19 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool { return false } +// baseBadPointerTypedef reports whether the base of a chain of typedefs is a bad typedef +// as badPointerTypedef reports. +func (c *typeConv) baseBadPointerTypedef(dt *dwarf.TypedefType) bool { + for { + if t, ok := dt.Type.(*dwarf.TypedefType); ok { + dt = t + continue + } + break + } + return c.badPointerTypedef(dt) +} + func (c *typeConv) badCFType(dt *dwarf.TypedefType) bool { // The real bad types are CFNumberRef and CFDateRef. // Sometimes non-pointers are stored in these types. @@ -2686,13 +2788,31 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool { } } - // Check that the typedef is: - // struct _jobject; - // typedef struct _jobject *jobject; + // Check that the typedef is either: + // 1: + // struct _jobject; + // typedef struct _jobject *jobject; + // 2: (in NDK16 in C++) + // class _jobject {}; + // typedef _jobject* jobject; + // 3: (in NDK16 in C) + // typedef void* jobject; if ptr, ok := w.Type.(*dwarf.PtrType); ok { - if str, ok := ptr.Type.(*dwarf.StructType); ok { - if str.StructName == "_jobject" && str.Kind == "struct" && len(str.Field) == 0 && str.Incomplete { - return true + switch v := ptr.Type.(type) { + case *dwarf.VoidType: + return true + case *dwarf.StructType: + if v.StructName == "_jobject" && len(v.Field) == 0 { + switch v.Kind { + case "struct": + if v.Incomplete { + return true + } + case "class": + if !v.Incomplete { + return true + } + } } } } diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go index 246898ab77..b6f059001f 100644 --- a/src/cmd/cgo/main.go +++ b/src/cmd/cgo/main.go @@ -43,9 +43,11 @@ type Package struct { Name map[string]*Name // accumulated Name from Files ExpFunc []*ExpFunc // accumulated ExpFunc from Files Decl []ast.Decl - GoFiles []string // list of Go files - GccFiles []string // list of gcc output files - Preamble string // collected preamble for _cgo_export.h + GoFiles []string // list of Go files + GccFiles []string // list of gcc output files + Preamble string // collected preamble for _cgo_export.h + typedefs map[string]bool // type names that appear in the types of the objects we're interested in + typedefList []string } // A File collects information about a single Go input file. @@ -261,6 +263,9 @@ func main() { if arg == "-fsanitize=thread" { tsanProlog = yesTsanProlog } + if arg == "-fsanitize=memory" { + msanProlog = yesMsanProlog + } } p := newPackage(args[:i]) @@ -394,6 +399,14 @@ func (p *Package) Record(f *File) { for k, v := range f.Name { if p.Name[k] == nil { p.Name[k] = v + } else if p.incompleteTypedef(p.Name[k].Type) { + p.Name[k] = v + } else if p.incompleteTypedef(v.Type) { + // Nothing to do. + } else if _, ok := nameToC[k]; ok { + // Names we predefine may appear inconsistent + // if some files typedef them and some don't. + // Issue 26743. } else if !reflect.DeepEqual(p.Name[k], v) { error_(token.NoPos, "inconsistent definitions for C.%s", fixGo(k)) } @@ -406,3 +419,9 @@ func (p *Package) Record(f *File) { } p.Decl = append(p.Decl, f.AST.Decls...) } + +// incompleteTypedef reports whether t appears to be an incomplete +// typedef definition. +func (p *Package) incompleteTypedef(t *Type) bool { + return t == nil || (t.Size == 0 && t.Align == -1) +} diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go index dbc17d2d56..6217bb17a3 100644 --- a/src/cmd/cgo/out.go +++ b/src/cmd/cgo/out.go @@ -272,10 +272,7 @@ func dynimport(obj string) { } } } - sym, err := f.ImportedSymbols() - if err != nil { - fatalf("cannot load imported symbols from ELF file %s: %v", obj, err) - } + sym, _ := f.ImportedSymbols() for _, s := range sym { targ := s.Name if s.Version != "" { @@ -283,10 +280,7 @@ func dynimport(obj string) { } fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) } - lib, err := f.ImportedLibraries() - if err != nil { - fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) - } + lib, _ := f.ImportedLibraries() for _, l := range lib { fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } @@ -294,20 +288,14 @@ func dynimport(obj string) { } if f, err := macho.Open(obj); err == nil { - sym, err := f.ImportedSymbols() - if err != nil { - fatalf("cannot load imported symbols from Mach-O file %s: %v", obj, err) - } + sym, _ := f.ImportedSymbols() for _, s := range sym { if len(s) > 0 && s[0] == '_' { s = s[1:] } fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "") } - lib, err := f.ImportedLibraries() - if err != nil { - fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) - } + lib, _ := f.ImportedLibraries() for _, l := range lib { fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } @@ -315,10 +303,7 @@ func dynimport(obj string) { } if f, err := pe.Open(obj); err == nil { - sym, err := f.ImportedSymbols() - if err != nil { - fatalf("cannot load imported symbols from PE file %s: %v", obj, err) - } + sym, _ := f.ImportedSymbols() for _, s := range sym { ss := strings.Split(s, ":") name := strings.Split(ss[0], "@")[0] @@ -537,7 +522,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { // Write Go output: Go input with rewrites of C.xxx to _C_xxx. fmt.Fprintf(fgo1, "// Code generated by cmd/cgo; DO NOT EDIT.\n\n") - fmt.Fprintf(fgo1, "//line %s:1\n", srcfile) + fmt.Fprintf(fgo1, "//line %s:1:1\n", srcfile) fgo1.Write(f.Edit.Bytes()) // While we process the vars and funcs, also write gcc output. @@ -546,6 +531,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { fmt.Fprintf(fgcc, "%s\n", f.Preamble) fmt.Fprintf(fgcc, "%s\n", gccProlog) fmt.Fprintf(fgcc, "%s\n", tsanProlog) + fmt.Fprintf(fgcc, "%s\n", msanProlog) for _, key := range nameKeys(f.Name) { n := f.Name[key] @@ -651,6 +637,16 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n") // Save the return value. fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n") + // The return value is on the Go stack. If we are using msan, + // and if the C value is partially or completely uninitialized, + // the assignment will mark the Go stack as uninitialized. + // The Go compiler does not update msan for changes to the + // stack. It is possible that the stack will remain + // uninitialized, and then later be used in a way that is + // visible to msan, possibly leading to a false positive. + // Mark the stack space as written, to avoid this problem. + // See issue 26209. + fmt.Fprintf(fgcc, "\t_cgo_msan_write(&_cgo_a->r, sizeof(_cgo_a->r));\n") } if n.AddError { fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n") @@ -749,6 +745,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n") fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);") fmt.Fprintf(fgcc, "%s\n", tsanProlog) + fmt.Fprintf(fgcc, "%s\n", msanProlog) for _, exp := range p.ExpFunc { fn := exp.Func @@ -986,6 +983,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog) fmt.Fprintf(fgcc, "%s\n", tsanProlog) + fmt.Fprintf(fgcc, "%s\n", msanProlog) for _, exp := range p.ExpFunc { fn := exp.Func @@ -1398,6 +1396,25 @@ static void _cgo_tsan_release() { // Set to yesTsanProlog if we see -fsanitize=thread in the flags for gcc. var tsanProlog = noTsanProlog +// noMsanProlog is a prologue defining an MSAN function in C. +// This is used when not compiling with -fsanitize=memory. +const noMsanProlog = ` +#define _cgo_msan_write(addr, sz) +` + +// yesMsanProlog is a prologue defining an MSAN function in C. +// This is used when compiling with -fsanitize=memory. +// See the comment above where _cgo_msan_write is called. +const yesMsanProlog = ` +extern void __msan_unpoison(const volatile void *, size_t); + +#define _cgo_msan_write(addr, sz) __msan_unpoison((addr), (sz)) +` + +// msanProlog is set to yesMsanProlog if we see -fsanitize=memory in the flags +// for the C compiler. +var msanProlog = noMsanProlog + const builtinProlog = ` #line 1 "cgo-builtin-prolog" #include /* for ptrdiff_t and size_t below */ @@ -1415,7 +1432,7 @@ void *CBytes(_GoBytes_); void *_CMalloc(size_t); __attribute__ ((unused)) -static size_t _GoStringLen(_GoString_ s) { return s.n; } +static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; } __attribute__ ((unused)) static const char *_GoStringPtr(_GoString_ s) { return s.p; } diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go index 4f5c48864e..921306b7aa 100644 --- a/src/cmd/cgo/util.go +++ b/src/cmd/cgo/util.go @@ -59,6 +59,8 @@ func run(stdin []byte, argv []string) (stdout, stderr []byte, ok bool) { var bout, berr bytes.Buffer p.Stdout = &bout p.Stderr = &berr + // Disable escape codes in clang error messages. + p.Env = append(os.Environ(), "TERM=dumb") err := p.Run() if _, ok := err.(*exec.ExitError); err != nil && !ok { fatalf("%s", err) @@ -97,6 +99,8 @@ func error_(pos token.Pos, msg string, args ...interface{}) { nerrors++ if pos.IsValid() { fmt.Fprintf(os.Stderr, "%s: ", fset.Position(pos).String()) + } else { + fmt.Fprintf(os.Stderr, "cgo: ") } fmt.Fprintf(os.Stderr, msg, args...) fmt.Fprintf(os.Stderr, "\n") diff --git a/src/cmd/compile/README.md b/src/cmd/compile/README.md index b78786e5f2..babc3f7679 100644 --- a/src/cmd/compile/README.md +++ b/src/cmd/compile/README.md @@ -1,6 +1,8 @@ + ## Introduction to the Go compiler @@ -19,7 +21,7 @@ the `go/*` packages were developed to enable writing tools working with Go code, such as `gofmt` and `vet`. It should be clarified that the name "gc" stands for "Go compiler", and has -little to do with uppercase GC, which stands for garbage collection. +little to do with uppercase "GC", which stands for garbage collection. ### 1. Parsing @@ -113,4 +115,4 @@ and debugging information. ### Further reading To dig deeper into how the SSA package works, including its passes and rules, -head to `cmd/compile/internal/ssa/README.md`. +head to [cmd/compile/internal/ssa/README.md](internal/ssa/README.md). diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go index 531298a216..e28e428a17 100644 --- a/src/cmd/compile/fmt_test.go +++ b/src/cmd/compile/fmt_test.go @@ -73,6 +73,9 @@ type File struct { } func TestFormats(t *testing.T) { + if testing.Short() { + t.Skip("Skipping in short mode") + } testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok // process all directories @@ -721,6 +724,7 @@ var knownFormats = map[string]string{ "uint16 %d": "", "uint16 %v": "", "uint16 %x": "", + "uint32 %#x": "", "uint32 %d": "", "uint32 %v": "", "uint32 %x": "", diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 307cdc5e83..ae6141dd12 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -524,6 +524,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8, ssa.OpAMD64LEAL1, ssa.OpAMD64LEAL2, ssa.OpAMD64LEAL4, ssa.OpAMD64LEAL8, ssa.OpAMD64LEAW1, ssa.OpAMD64LEAW2, ssa.OpAMD64LEAW4, ssa.OpAMD64LEAW8: + o := v.Reg() r := v.Args[0].Reg() i := v.Args[1].Reg() p := s.Prog(v.Op.Asm()) @@ -543,9 +544,24 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.From.Type = obj.TYPE_MEM p.From.Reg = r p.From.Index = i - gc.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG - p.To.Reg = v.Reg() + p.To.Reg = o + if v.AuxInt != 0 && v.Aux == nil { + // Emit an additional LEA to add the displacement instead of creating a slow 3 operand LEA. + switch v.Op { + case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8: + p = s.Prog(x86.ALEAQ) + case ssa.OpAMD64LEAL1, ssa.OpAMD64LEAL2, ssa.OpAMD64LEAL4, ssa.OpAMD64LEAL8: + p = s.Prog(x86.ALEAL) + case ssa.OpAMD64LEAW1, ssa.OpAMD64LEAW2, ssa.OpAMD64LEAW4, ssa.OpAMD64LEAW8: + p = s.Prog(x86.ALEAW) + } + p.From.Type = obj.TYPE_MEM + p.From.Reg = o + p.To.Type = obj.TYPE_REG + p.To.Reg = o + } + gc.AddAux(&p.From, v) case ssa.OpAMD64LEAQ, ssa.OpAMD64LEAL, ssa.OpAMD64LEAW: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM @@ -683,7 +699,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore: + case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore, + ssa.OpAMD64ADDQmodify, ssa.OpAMD64SUBQmodify, ssa.OpAMD64ANDQmodify, ssa.OpAMD64ORQmodify, ssa.OpAMD64XORQmodify, + ssa.OpAMD64ADDLmodify, ssa.OpAMD64SUBLmodify, ssa.OpAMD64ANDLmodify, ssa.OpAMD64ORLmodify, ssa.OpAMD64XORLmodify: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[1].Reg() @@ -754,6 +772,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.To.Reg = v.Args[0].Reg() gc.AddAux2(&p.To, v, off) } + case ssa.OpAMD64ANDQconstmodify, ssa.OpAMD64ANDLconstmodify, ssa.OpAMD64ORQconstmodify, ssa.OpAMD64ORLconstmodify, + ssa.OpAMD64XORQconstmodify, ssa.OpAMD64XORLconstmodify: + sc := v.AuxValAndOff() + off := sc.Off() + val := sc.Val() + p := s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_CONST + p.From.Offset = val + p.To.Type = obj.TYPE_MEM + p.To.Reg = v.Args[0].Reg() + gc.AddAux2(&p.To, v, off) case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST @@ -810,7 +839,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { case ssa.OpAMD64ADDQload, ssa.OpAMD64ADDLload, ssa.OpAMD64SUBQload, ssa.OpAMD64SUBLload, ssa.OpAMD64ANDQload, ssa.OpAMD64ANDLload, ssa.OpAMD64ORQload, ssa.OpAMD64ORLload, ssa.OpAMD64XORQload, ssa.OpAMD64XORLload, ssa.OpAMD64ADDSDload, ssa.OpAMD64ADDSSload, - ssa.OpAMD64SUBSDload, ssa.OpAMD64SUBSSload, ssa.OpAMD64MULSDload, ssa.OpAMD64MULSSload: + ssa.OpAMD64SUBSDload, ssa.OpAMD64SUBSSload, ssa.OpAMD64MULSDload, ssa.OpAMD64MULSSload, + ssa.OpAMD64DIVSDload, ssa.OpAMD64DIVSSload: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[1].Reg() diff --git a/src/cmd/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go index f7b3851398..204391fef1 100644 --- a/src/cmd/compile/internal/arm64/ggen.go +++ b/src/cmd/compile/internal/arm64/ggen.go @@ -14,10 +14,10 @@ import ( var darwin = objabi.GOOS == "darwin" func padframe(frame int64) int64 { - // arm64 requires that the frame size (not counting saved LR) - // be empty or be 8 mod 16. If not, pad it. - if frame != 0 && frame%16 != 8 { - frame += 8 + // arm64 requires that the frame size (not counting saved FP&LR) + // be 16 bytes aligned. If not, pad it. + if frame%16 != 0 { + frame += 16 - (frame % 16) } return frame } diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index c396ba06d1..db7064cff0 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -212,7 +212,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ssa.OpARM64FMSUBS, ssa.OpARM64FMSUBD, ssa.OpARM64FNMSUBS, - ssa.OpARM64FNMSUBD: + ssa.OpARM64FNMSUBD, + ssa.OpARM64MADD, + ssa.OpARM64MADDW, + ssa.OpARM64MSUB, + ssa.OpARM64MSUBW: rt := v.Reg() ra := v.Args[0].Reg() rm := v.Args[1].Reg() @@ -369,6 +373,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ssa.OpARM64MOVWloadidx, ssa.OpARM64MOVWUloadidx, ssa.OpARM64MOVDloadidx, + ssa.OpARM64FMOVSloadidx, + ssa.OpARM64FMOVDloadidx, ssa.OpARM64MOVHloadidx2, ssa.OpARM64MOVHUloadidx2, ssa.OpARM64MOVWloadidx4, @@ -404,6 +410,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ssa.OpARM64MOVHstoreidx, ssa.OpARM64MOVWstoreidx, ssa.OpARM64MOVDstoreidx, + ssa.OpARM64FMOVSstoreidx, + ssa.OpARM64FMOVDstoreidx, ssa.OpARM64MOVHstoreidx2, ssa.OpARM64MOVWstoreidx4, ssa.OpARM64MOVDstoreidx8: diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 0d4997ccfc..d0b1804eb6 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -464,19 +464,22 @@ func (p *exporter) markType(t *types.Type) { } // Recursively mark any types that can be produced given a - // value of type t: dereferencing a pointer; indexing an - // array, slice, or map; receiving from a channel; accessing a - // struct field or interface method; or calling a function. + // value of type t: dereferencing a pointer; indexing or + // iterating over an array, slice, or map; receiving from a + // channel; accessing a struct field or interface method; or + // calling a function. // - // Notably, we don't mark map key or function parameter types, - // because the user already needs some way to construct values - // of those types. - // - // It's not critical for correctness that this algorithm is - // perfect. Worst case, we might miss opportunities to inline - // some function calls in downstream packages. + // Notably, we don't mark function parameter types, because + // the user already needs some way to construct values of + // those types. switch t.Etype { - case TPTR32, TPTR64, TARRAY, TSLICE, TCHAN, TMAP: + case TPTR32, TPTR64, TARRAY, TSLICE, TCHAN: + // TODO(mdempsky): Skip marking element type for + // send-only channels? + p.markType(t.Elem()) + + case TMAP: + p.markType(t.Key()) p.markType(t.Elem()) case TSTRUCT: diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go index e9db35ede2..5ddfd5f2ca 100644 --- a/src/cmd/compile/internal/gc/bv.go +++ b/src/cmd/compile/internal/gc/bv.go @@ -227,17 +227,6 @@ type bvecSet struct { uniq []bvec // unique bvecs, in insertion order } -func newBvecSet(size int) bvecSet { - // bvecSet is a linear probing hash table. - // The hash table has 4n entries to keep the linear - // scan short. - index := make([]int, size*4) - for i := range index { - index[i] = -1 - } - return bvecSet{index, nil} -} - func (m *bvecSet) grow() { // Allocate new index. n := len(m.index) * 2 diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go index ce575a6418..834cdc41eb 100644 --- a/src/cmd/compile/internal/gc/closure.go +++ b/src/cmd/compile/internal/gc/closure.go @@ -382,10 +382,7 @@ func walkclosure(clo *Node, init *Nodes) *Node { clos.List.Set(append([]*Node{nod(OCFUNC, xfunc.Func.Nname, nil)}, clo.Func.Enter.Slice()...)) // Force type conversion from *struct to the func type. - clos = nod(OCONVNOP, clos, nil) - clos.Type = clo.Type - - clos = typecheck(clos, Erv) + clos = convnop(clos, clo.Type) // typecheck will insert a PTRLIT node under CONVNOP, // tag it with escape analysis result. @@ -511,10 +508,7 @@ func walkpartialcall(n *Node, init *Nodes) *Node { clos.List.Append(n.Left) // Force type conversion from *struct to the func type. - clos = nod(OCONVNOP, clos, nil) - clos.Type = n.Type - - clos = typecheck(clos, Erv) + clos = convnop(clos, n.Type) // typecheck will insert a PTRLIT node under CONVNOP, // tag it with escape analysis result. diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index 2827543e31..1403a2be11 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -121,6 +121,17 @@ func (n *Node) Int64() int64 { return n.Val().U.(*Mpint).Int64() } +// CanInt64 reports whether it is safe to call Int64() on n. +func (n *Node) CanInt64() bool { + if !Isconst(n, CTINT) { + return false + } + + // if the value inside n cannot be represented as an int64, the + // return value of Int64 is undefined + return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0 +} + // Bool returns n as a bool. // n must be a boolean constant. func (n *Node) Bool() bool { @@ -766,7 +777,7 @@ func evconst(n *Node) { v.U.(*Mpint).Neg() case OCOM_ | CTINT_: - var et types.EType = Txxx + et := Txxx if nl.Type != nil { et = nl.Type.Etype } diff --git a/src/cmd/compile/internal/gc/dwinl.go b/src/cmd/compile/internal/gc/dwinl.go index f514281061..51251c9139 100644 --- a/src/cmd/compile/internal/gc/dwinl.go +++ b/src/cmd/compile/internal/gc/dwinl.go @@ -8,7 +8,6 @@ import ( "cmd/internal/dwarf" "cmd/internal/obj" "cmd/internal/src" - "sort" "strings" ) @@ -96,7 +95,6 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls { // the pre-inlining decls for the target function and assign child // index accordingly. for ii, sl := range vmap { - sort.Sort(byClassThenName(sl)) var m map[varPos]int if ii == 0 { if !fnsym.WasInlined() { @@ -142,7 +140,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls { // return temps (~r%d) that were created during // lowering, or unnamed params ("_"). v.ChildIndex = int32(synthCount) - synthCount += 1 + synthCount++ } } } @@ -311,31 +309,6 @@ func beginRange(calls []dwarf.InlCall, p *obj.Prog, ii int, imap map[int]int) *d return &call.Ranges[len(call.Ranges)-1] } -func cmpDwarfVar(a, b *dwarf.Var) bool { - // named before artificial - aart := 0 - if strings.HasPrefix(a.Name, "~r") { - aart = 1 - } - bart := 0 - if strings.HasPrefix(b.Name, "~r") { - bart = 1 - } - if aart != bart { - return aart < bart - } - - // otherwise sort by name - return a.Name < b.Name -} - -// byClassThenName implements sort.Interface for []*dwarf.Var using cmpDwarfVar. -type byClassThenName []*dwarf.Var - -func (s byClassThenName) Len() int { return len(s) } -func (s byClassThenName) Less(i, j int) bool { return cmpDwarfVar(s[i], s[j]) } -func (s byClassThenName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - func dumpInlCall(inlcalls dwarf.InlCalls, idx, ilevel int) { for i := 0; i < ilevel; i++ { Ctxt.Logf(" ") diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go index 0baf7e7441..9db6c8e0b4 100644 --- a/src/cmd/compile/internal/gc/esc.go +++ b/src/cmd/compile/internal/gc/esc.go @@ -502,8 +502,6 @@ func escAnalyze(all []*Node, recursive bool) { } } - // print("escapes: %d e.dsts, %d edges\n", e.dstcount, e.edgecount); - // visit the upstream of each dst, mark address nodes with // addrescapes, mark parameters unsafe escapes := make([]uint16, len(e.dsts)) @@ -551,7 +549,6 @@ func escAnalyze(all []*Node, recursive bool) { } func (e *EscState) escfunc(fn *Node) { - // print("escfunc %N %s\n", fn.Func.Nname, e.recursive?"(recursive)":""); if fn.Esc != EscFuncPlanned { Fatalf("repeat escfunc %v", fn.Func.Nname) } @@ -630,8 +627,6 @@ func (e *EscState) escloopdepth(n *Node) { // Walk will complain about this label being already defined, but that's not until // after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc - // if(n.Left.Sym.Label != nil) - // fatal("escape analysis messed up analyzing label: %+N", n); n.Left.Sym.Label = asTypesNode(&nonlooping) case OGOTO: @@ -659,6 +654,58 @@ func (e *EscState) esclist(l Nodes, parent *Node) { } } +// isSelfAssign reports whether assignment from src to dst can +// be ignored by the escape analysis as it's effectively a self-assignment. +func (e *EscState) isSelfAssign(dst, src *Node) bool { + if dst == nil || src == nil || dst.Op != src.Op { + return false + } + + switch dst.Op { + case ODOT, ODOTPTR: + // Safe trailing accessors that are permitted to differ. + case OINDEX: + if e.mayAffectMemory(dst.Right) || e.mayAffectMemory(src.Right) { + return false + } + default: + return false + } + + // The expression prefix must be both "safe" and identical. + return samesafeexpr(dst.Left, src.Left) +} + +// mayAffectMemory reports whether n evaluation may affect program memory state. +// If expression can't affect it, then it can be safely ignored by the escape analysis. +func (e *EscState) mayAffectMemory(n *Node) bool { + // We may want to use "memory safe" black list instead of general + // "side-effect free", which can include all calls and other ops + // that can affect allocate or change global state. + // It's safer to start from a whitelist for now. + // + // We're ignoring things like division by zero, index out of range, + // and nil pointer dereference here. + switch n.Op { + case ONAME, OCLOSUREVAR, OLITERAL: + return false + case ODOT, ODOTPTR: + return e.mayAffectMemory(n.Left) + case OIND, OCONVNOP: + return e.mayAffectMemory(n.Left) + case OCONV: + return e.mayAffectMemory(n.Left) + case OINDEX: + return e.mayAffectMemory(n.Left) || e.mayAffectMemory(n.Right) + case OADD, OSUB, OOR, OXOR, OMUL, OLSH, ORSH, OAND, OANDNOT, ODIV, OMOD: + return e.mayAffectMemory(n.Left) || e.mayAffectMemory(n.Right) + case ONOT, OCOM, OPLUS, OMINUS, OALIGNOF, OOFFSETOF, OSIZEOF: + return e.mayAffectMemory(n.Left) + default: + return true + } +} + func (e *EscState) esc(n *Node, parent *Node) { if n == nil { return @@ -756,10 +803,6 @@ opSwitch: e.loopdepth++ } - // See case OLABEL in escloopdepth above - // else if(n.Left.Sym.Label == nil) - // fatal("escape analysis missed or messed up a label: %+N", n); - n.Left.Sym.Label = nil case ORANGE: @@ -822,13 +865,30 @@ opSwitch: break } + // Also skip trivial assignments that assign back to the same object. + // + // It covers these cases: + // val.x = val.y + // val.x[i] = val.y[j] + // val.x1.x2 = val.x1.y2 + // ... etc + // + // These assignments do not change assigned object lifetime. + if e.isSelfAssign(n.Left, n.Right) { + if Debug['m'] != 0 { + Warnl(n.Pos, "%v ignoring self-assignment in %S", e.curfnSym(n), n) + } + break + } + e.escassign(n.Left, n.Right, e.stepAssignWhere(nil, nil, "", n)) case OAS2: // x,y = a,b if n.List.Len() == n.Rlist.Len() { rs := n.Rlist.Slice() + where := n for i, n := range n.List.Slice() { - e.escassignWhyWhere(n, rs[i], "assign-pair", n) + e.escassignWhyWhere(n, rs[i], "assign-pair", where) } } @@ -869,11 +929,12 @@ opSwitch: // esccall already done on n.Rlist.First(). tie it's Retval to n.List case OAS2FUNC: // x,y = f() rs := e.nodeEscState(n.Rlist.First()).Retval.Slice() + where := n for i, n := range n.List.Slice() { if i >= len(rs) { break } - e.escassignWhyWhere(n, rs[i], "assign-pair-func-call", n) + e.escassignWhyWhere(n, rs[i], "assign-pair-func-call", where) } if n.List.Len() != len(rs) { Fatalf("esc oas2func") @@ -1561,12 +1622,11 @@ func (e *EscState) esccall(call *Node, parent *Node) { cE := e.nodeEscState(call) if fn != nil && fn.Op == ONAME && fn.Class() == PFUNC && fn.Name.Defn != nil && fn.Name.Defn.Nbody.Len() != 0 && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged { + // function in same mutually recursive group. Incorporate into flow graph. if Debug['m'] > 3 { fmt.Printf("%v::esccall:: %S in recursive group\n", linestr(lineno), call) } - // function in same mutually recursive group. Incorporate into flow graph. - // print("esc local fn: %N\n", fn.Func.Ntype); if fn.Name.Defn.Esc == EscFuncUnknown || cE.Retval.Len() != 0 { Fatalf("graph inconsistency") } @@ -1629,8 +1689,6 @@ func (e *EscState) esccall(call *Node, parent *Node) { // set up out list on this call node with dummy auto ONAMES in the current (calling) function. e.initEscRetval(call, fntype) - // print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, e.nodeEscState(call).Retval); - // Receiver. if call.Op != OCALLFUNC { rf := fntype.Recv() diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index becc4e1f3b..3aa7c39067 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -88,7 +88,7 @@ func dumpexport(bout *bio.Writer) { } } -func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op) *Node { +func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node { n := asNode(s.PkgDef()) if n == nil { // iimport should have created a stub ONONAME @@ -113,7 +113,7 @@ func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op) *Node { // If no such type has been declared yet, a forward declaration is returned. // ipkg is the package being imported func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type { - n := importsym(ipkg, pos, s, OTYPE) + n := importsym(ipkg, s, OTYPE) if n.Op != OTYPE { t := types.New(TFORW) t.Sym = s @@ -135,7 +135,7 @@ func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type { // importobj declares symbol s as an imported object representable by op. // ipkg is the package being imported func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t *types.Type) *Node { - n := importsym(ipkg, pos, s, op) + n := importsym(ipkg, s, op) if n.Op != ONONAME { if n.Op == op && (n.Class() != ctxt || !eqtype(n.Type, t)) { redeclare(lineno, s, fmt.Sprintf("during import %q", ipkg.Path)) diff --git a/src/cmd/compile/internal/gc/float_test.go b/src/cmd/compile/internal/gc/float_test.go index 4cb9532e55..c0a8cfc89e 100644 --- a/src/cmd/compile/internal/gc/float_test.go +++ b/src/cmd/compile/internal/gc/float_test.go @@ -362,6 +362,117 @@ func TestFloatConvertFolded(t *testing.T) { } } +func TestFloat32StoreToLoadConstantFold(t *testing.T) { + // Test that math.Float32{,from}bits constant fold correctly. + // In particular we need to be careful that signalling NaN (sNaN) values + // are not converted to quiet NaN (qNaN) values during compilation. + // See issue #27193 for more information. + + // signalling NaNs + { + const nan = uint32(0x7f800001) // sNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0x7fbfffff) // sNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0xff800001) // sNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0xffbfffff) // sNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + + // quiet NaNs + { + const nan = uint32(0x7fc00000) // qNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0x7fffffff) // qNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0x8fc00000) // qNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + { + const nan = uint32(0x8fffffff) // qNaN + if x := math.Float32bits(math.Float32frombits(nan)); x != nan { + t.Errorf("got %#x, want %#x", x, nan) + } + } + + // infinities + { + const inf = uint32(0x7f800000) // +∞ + if x := math.Float32bits(math.Float32frombits(inf)); x != inf { + t.Errorf("got %#x, want %#x", x, inf) + } + } + { + const negInf = uint32(0xff800000) // -∞ + if x := math.Float32bits(math.Float32frombits(negInf)); x != negInf { + t.Errorf("got %#x, want %#x", x, negInf) + } + } + + // numbers + { + const zero = uint32(0) // +0.0 + if x := math.Float32bits(math.Float32frombits(zero)); x != zero { + t.Errorf("got %#x, want %#x", x, zero) + } + } + { + const negZero = uint32(1 << 31) // -0.0 + if x := math.Float32bits(math.Float32frombits(negZero)); x != negZero { + t.Errorf("got %#x, want %#x", x, negZero) + } + } + { + const one = uint32(0x3f800000) // 1.0 + if x := math.Float32bits(math.Float32frombits(one)); x != one { + t.Errorf("got %#x, want %#x", x, one) + } + } + { + const negOne = uint32(0xbf800000) // -1.0 + if x := math.Float32bits(math.Float32frombits(negOne)); x != negOne { + t.Errorf("got %#x, want %#x", x, negOne) + } + } + { + const frac = uint32(0x3fc00000) // +1.5 + if x := math.Float32bits(math.Float32frombits(frac)); x != frac { + t.Errorf("got %#x, want %#x", x, frac) + } + } + { + const negFrac = uint32(0xbfc00000) // -1.5 + if x := math.Float32bits(math.Float32frombits(negFrac)); x != negFrac { + t.Errorf("got %#x, want %#x", x, negFrac) + } + } +} + var sinkFloat float64 func BenchmarkMul2(b *testing.B) { diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 75194ca6f0..5b7445d4db 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -7,6 +7,7 @@ package gc import ( "cmd/compile/internal/types" "fmt" + "io" "strconv" "strings" "unicode/utf8" @@ -1836,6 +1837,10 @@ func dumplist(s string, l Nodes) { fmt.Printf("%s%+v\n", s, l) } +func fdumplist(w io.Writer, s string, l Nodes) { + fmt.Fprintf(w, "%s%+v\n", s, l) +} + func Dump(s string, n *Node) { fmt.Printf("%s [%p]%+v\n", s, n, n) } diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 95bf562e2c..d8ab5eb39c 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -281,7 +281,7 @@ var ( assertE2I2, assertI2I, assertI2I2, - Deferproc, + deferproc, Deferreturn, Duffcopy, Duffzero, @@ -290,7 +290,7 @@ var ( growslice, msanread, msanwrite, - Newproc, + newproc, panicdivide, panicdottypeE, panicdottypeI, diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go index 3abbd15e16..3007c9cabf 100644 --- a/src/cmd/compile/internal/gc/iexport.go +++ b/src/cmd/compile/internal/gc/iexport.go @@ -595,7 +595,7 @@ func (p *iexporter) typOff(t *types.Type) uint64 { if !ok { w := p.newWriter() w.doTyp(t) - off = predeclReserved + uint64(w.flush()) + off = predeclReserved + w.flush() p.typIndex[t] = off } return off @@ -952,6 +952,16 @@ func (w *exportWriter) funcExt(n *Node) { if n.Func.ExportInline() { w.p.doInline(n) } + + // Endlineno for inlined function. + if n.Name.Defn != nil { + w.pos(n.Name.Defn.Func.Endlineno) + } else { + // When the exported node was defined externally, + // e.g. io exports atomic.(*Value).Load or bytes exports errors.New. + // Keep it as we don't distinguish this case in iimport.go. + w.pos(n.Func.Endlineno) + } } else { w.uint64(0) } diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go index 54c5d8dc2f..6f0fd6b6d2 100644 --- a/src/cmd/compile/internal/gc/iimport.go +++ b/src/cmd/compile/internal/gc/iimport.go @@ -296,8 +296,23 @@ func (r *importReader) doDecl(n *Node) { // declaration before recursing. t := importtype(r.p.ipkg, pos, n.Sym) + // We also need to defer width calculations until + // after the underlying type has been assigned. + // + // TODO(mdempsky): Add nesting support directly to + // {defer,resume}checkwidth? Width calculations are + // already deferred during initial typechecking, but + // not when we're expanding inline function bodies, so + // we currently need to handle both cases here. + deferring := defercalc != 0 + if !deferring { + defercheckwidth() + } underlying := r.typ() copytype(typenod(t), underlying) + if !deferring { + resumecheckwidth() + } if underlying.IsInterface() { break @@ -576,6 +591,10 @@ func (r *importReader) typ1() *types.Type { t := types.New(TINTER) t.SetPkg(r.currPkg) t.SetInterface(append(embeddeds, methods...)) + + // Ensure we expand the interface in the frontend (#25055). + checkwidth(t) + return t } } @@ -660,6 +679,7 @@ func (r *importReader) funcExt(n *Node) { n.Func.Inl = &Inline{ Cost: int32(u - 1), } + n.Func.Endlineno = r.pos() } } diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go index cb3ddaf2a5..fb5a413b84 100644 --- a/src/cmd/compile/internal/gc/inl.go +++ b/src/cmd/compile/internal/gc/inl.go @@ -41,6 +41,9 @@ const ( inlineExtraCallCost = inlineMaxBudget // default is do not inline, -l=4 enables by using 1 instead. inlineExtraPanicCost = 1 // do not penalize inlining panics. inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help. + + inlineBigFunctionNodes = 5000 // Functions with this many nodes are considered "big". + inlineBigFunctionMaxCost = 20 // Max cost of inlinee when inlining into a "big" function. ) // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods @@ -459,12 +462,38 @@ func inlcopy(n *Node) *Node { return m } +func countNodes(n *Node) int { + if n == nil { + return 0 + } + cnt := 1 + cnt += countNodes(n.Left) + cnt += countNodes(n.Right) + for _, n1 := range n.Ninit.Slice() { + cnt += countNodes(n1) + } + for _, n1 := range n.Nbody.Slice() { + cnt += countNodes(n1) + } + for _, n1 := range n.List.Slice() { + cnt += countNodes(n1) + } + for _, n1 := range n.Rlist.Slice() { + cnt += countNodes(n1) + } + return cnt +} + // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any // calls made to inlineable functions. This is the external entry point. func inlcalls(fn *Node) { savefn := Curfn Curfn = fn - fn = inlnode(fn) + maxCost := int32(inlineMaxBudget) + if countNodes(fn) >= inlineBigFunctionNodes { + maxCost = inlineBigFunctionMaxCost + } + fn = inlnode(fn, maxCost) if fn != Curfn { Fatalf("inlnode replaced curfn") } @@ -505,10 +534,10 @@ func inlconv2list(n *Node) []*Node { return s } -func inlnodelist(l Nodes) { +func inlnodelist(l Nodes, maxCost int32) { s := l.Slice() for i := range s { - s[i] = inlnode(s[i]) + s[i] = inlnode(s[i], maxCost) } } @@ -525,7 +554,7 @@ func inlnodelist(l Nodes) { // shorter and less complicated. // The result of inlnode MUST be assigned back to n, e.g. // n.Left = inlnode(n.Left) -func inlnode(n *Node) *Node { +func inlnode(n *Node, maxCost int32) *Node { if n == nil { return n } @@ -547,19 +576,19 @@ func inlnode(n *Node) *Node { lno := setlineno(n) - inlnodelist(n.Ninit) + inlnodelist(n.Ninit, maxCost) for _, n1 := range n.Ninit.Slice() { if n1.Op == OINLCALL { inlconv2stmt(n1) } } - n.Left = inlnode(n.Left) + n.Left = inlnode(n.Left, maxCost) if n.Left != nil && n.Left.Op == OINLCALL { n.Left = inlconv2expr(n.Left) } - n.Right = inlnode(n.Right) + n.Right = inlnode(n.Right, maxCost) if n.Right != nil && n.Right.Op == OINLCALL { if n.Op == OFOR || n.Op == OFORUNTIL { inlconv2stmt(n.Right) @@ -568,7 +597,7 @@ func inlnode(n *Node) *Node { } } - inlnodelist(n.List) + inlnodelist(n.List, maxCost) switch n.Op { case OBLOCK: for _, n2 := range n.List.Slice() { @@ -595,7 +624,7 @@ func inlnode(n *Node) *Node { } } - inlnodelist(n.Rlist) + inlnodelist(n.Rlist, maxCost) if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL { n.Rlist.Set(inlconv2list(n.Rlist.First())) n.Op = OAS2 @@ -614,7 +643,7 @@ func inlnode(n *Node) *Node { } } - inlnodelist(n.Nbody) + inlnodelist(n.Nbody, maxCost) for _, n := range n.Nbody.Slice() { if n.Op == OINLCALL { inlconv2stmt(n) @@ -637,12 +666,12 @@ func inlnode(n *Node) *Node { fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left) } if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case - n = mkinlcall(n, n.Left) + n = mkinlcall(n, n.Left, maxCost) } else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil { - n = mkinlcall(n, asNode(n.Left.Sym.Def)) + n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost) } else if n.Left.Op == OCLOSURE { if f := inlinableClosure(n.Left); f != nil { - n = mkinlcall(n, f) + n = mkinlcall(n, f, maxCost) } } else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil { if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE { @@ -668,7 +697,7 @@ func inlnode(n *Node) *Node { } break } - n = mkinlcall(n, f) + n = mkinlcall(n, f, maxCost) } } } @@ -687,7 +716,7 @@ func inlnode(n *Node) *Node { Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type) } - n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname)) + n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), maxCost) } lineno = lno @@ -788,7 +817,7 @@ func (v *reassignVisitor) visitList(l Nodes) *Node { // The result of mkinlcall MUST be assigned back to n, e.g. // n.Left = mkinlcall(n.Left, fn, isddd) -func mkinlcall(n *Node, fn *Node) *Node { +func mkinlcall(n *Node, fn *Node, maxCost int32) *Node { save_safemode := safemode // imported functions may refer to unsafe as long as the @@ -798,7 +827,7 @@ func mkinlcall(n *Node, fn *Node) *Node { if pkg != localpkg && pkg != nil { safemode = false } - n = mkinlcall1(n, fn) + n = mkinlcall1(n, fn, maxCost) safemode = save_safemode return n } @@ -824,11 +853,16 @@ var inlgen int // parameters. // The result of mkinlcall1 MUST be assigned back to n, e.g. // n.Left = mkinlcall1(n.Left, fn, isddd) -func mkinlcall1(n, fn *Node) *Node { +func mkinlcall1(n, fn *Node, maxCost int32) *Node { if fn.Func.Inl == nil { // No inlinable body. return n } + if fn.Func.Inl.Cost > maxCost { + // The inlined function body is too big. Typically we use this check to restrict + // inlining into very big functions. See issue 26546 and 17566. + return n + } if fn == Curfn || fn.Name.Defn == Curfn { // Can't recursively inline a function into itself. @@ -859,6 +893,10 @@ func mkinlcall1(n, fn *Node) *Node { fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n) } + if ssaDump != "" && ssaDump == Curfn.funcname() { + ssaDumpInlined = append(ssaDumpInlined, fn) + } + ninit := n.Ninit // Make temp names to use instead of the originals. @@ -1094,7 +1132,7 @@ func mkinlcall1(n, fn *Node) *Node { // instead we emit the things that the body needs // and each use must redo the inlining. // luckily these are small. - inlnodelist(call.Nbody) + inlnodelist(call.Nbody, maxCost) for _, n := range call.Nbody.Slice() { if n.Op == OINLCALL { inlconv2stmt(n) diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 9f1ea2ab4b..44cf75e7c9 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -216,14 +216,18 @@ func Main(archInit func(*Arch)) { flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") objabi.Flagcount("live", "debug liveness analysis", &debuglive) objabi.Flagcount("m", "print optimization decisions", &Debug['m']) - flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") + if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) { + flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") + } flag.BoolVar(&dolinkobj, "dolinkobj", true, "generate linker-specific objects; if false, some invalid code may compile") flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports") flag.StringVar(&outfile, "o", "", "write output to `file`") flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o") objabi.Flagcount("r", "debug generated wrappers", &Debug['r']) - flag.BoolVar(&flag_race, "race", false, "enable race detector") + if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) { + flag.BoolVar(&flag_race, "race", false, "enable race detector") + } objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") flag.BoolVar(&safemode, "u", false, "reject unsafe code") @@ -341,7 +345,7 @@ func Main(archInit func(*Arch)) { } // display help about the -d option itself and quit if name == "help" { - fmt.Printf(debugHelpHeader) + fmt.Print(debugHelpHeader) maxLen := len("ssa/help") for _, t := range debugtab { if len(t.name) > maxLen { @@ -353,7 +357,7 @@ func Main(archInit func(*Arch)) { } // ssa options have their own help fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging") - fmt.Printf(debugHelpFooter) + fmt.Print(debugHelpFooter) os.Exit(0) } val, valstring, haveInt := 1, "", true @@ -423,6 +427,12 @@ func Main(archInit func(*Arch)) { Debug['l'] = 1 - Debug['l'] } + ssaDump = os.Getenv("GOSSAFUNC") + if strings.HasSuffix(ssaDump, "+") { + ssaDump = ssaDump[:len(ssaDump)-1] + ssaDumpStdout = true + } + trackScopes = flagDWARF Widthptr = thearch.LinkArch.PtrSize diff --git a/src/cmd/compile/internal/gc/mpint.go b/src/cmd/compile/internal/gc/mpint.go index e9471b2a21..de47205435 100644 --- a/src/cmd/compile/internal/gc/mpint.go +++ b/src/cmd/compile/internal/gc/mpint.go @@ -299,8 +299,8 @@ func (a *Mpint) SetString(as string) { } } -func (x *Mpint) String() string { - return bconv(x, 0) +func (a *Mpint) String() string { + return bconv(a, 0) } func bconv(xval *Mpint, flag FmtFlag) string { diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index cf1164772b..563eb9e966 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -15,7 +15,6 @@ import ( "fmt" "math/rand" "sort" - "strings" "sync" "time" ) @@ -428,7 +427,8 @@ func createSimpleVars(automDecls []*Node) ([]*Node, []*dwarf.Var, map[*Node]bool if Ctxt.FixedFrameSize() == 0 { offs -= int64(Widthptr) } - if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" { + // There is a word space for FP on ARM64 even if the frame pointer is disabled offs -= int64(Widthptr) } @@ -594,35 +594,9 @@ func preInliningDcls(fnsym *obj.LSym) []*Node { } rdcl = append(rdcl, n) } - sort.Sort(byNodeName(rdcl)) return rdcl } -func cmpNodeName(a, b *Node) bool { - aart := 0 - if strings.HasPrefix(a.Sym.Name, "~") { - aart = 1 - } - bart := 0 - if strings.HasPrefix(b.Sym.Name, "~") { - bart = 1 - } - if aart != bart { - return aart < bart - } - - aname := unversion(a.Sym.Name) - bname := unversion(b.Sym.Name) - return aname < bname -} - -// byNodeName implements sort.Interface for []*Node using cmpNodeName. -type byNodeName []*Node - -func (s byNodeName) Len() int { return len(s) } -func (s byNodeName) Less(i, j int) bool { return cmpNodeName(s[i], s[j]) } -func (s byNodeName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - // stackOffset returns the stack location of a LocalSlot relative to the // stack pointer, suitable for use in a DWARF location entry. This has nothing // to do with its offset in the user variable. @@ -634,7 +608,8 @@ func stackOffset(slot ssa.LocalSlot) int32 { if Ctxt.FixedFrameSize() == 0 { base -= int64(Widthptr) } - if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) || objabi.GOARCH == "arm64" { + // There is a word space for FP on ARM64 even if the frame pointer is disabled base -= int64(Widthptr) } case PPARAM, PPARAMOUT: diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go index 88b4380637..e070a5cd1a 100644 --- a/src/cmd/compile/internal/gc/plive.go +++ b/src/cmd/compile/internal/gc/plive.go @@ -671,7 +671,7 @@ func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) { // markUnsafePoints finds unsafe points and computes lv.unsafePoints. func (lv *Liveness) markUnsafePoints() { - if compiling_runtime || lv.f.NoSplit { + if compiling_runtime || lv.f.NoSplit || objabi.Clobberdead_enabled != 0 { // No complex analysis necessary. Do this on the fly // in issafepoint. return @@ -692,6 +692,11 @@ func (lv *Liveness) markUnsafePoints() { lv.f.Fatalf("expected branch at write barrier block %v", wbBlock) } s0, s1 := wbBlock.Succs[0].Block(), wbBlock.Succs[1].Block() + if s0 == s1 { + // There's no difference between write barrier on and off. + // Thus there's no unsafe locations. See issue 26024. + continue + } if s0.Kind != ssa.BlockPlain || s1.Kind != ssa.BlockPlain { lv.f.Fatalf("expected successors of write barrier block %v to be plain", wbBlock) } @@ -825,7 +830,7 @@ func (lv *Liveness) issafepoint(v *ssa.Value) bool { // go:nosplit functions are similar. Since safe points used to // be coupled with stack checks, go:nosplit often actually // means "no safe points in this function". - if compiling_runtime || lv.f.NoSplit { + if compiling_runtime || lv.f.NoSplit || objabi.Clobberdead_enabled != 0 { return v.Op.IsCall() } switch v.Op { @@ -1198,13 +1203,16 @@ func (lv *Liveness) clobber() { } fmt.Printf("\t\t\tCLOBBERDEAD %s\n", lv.fn.funcname()) } - if lv.f.Name == "forkAndExecInChild" { + if lv.f.Name == "forkAndExecInChild" || lv.f.Name == "wbBufFlush" { // forkAndExecInChild calls vfork (on linux/amd64, anyway). // The code we add here clobbers parts of the stack in the child. // When the parent resumes, it is using the same stack frame. But the // child has clobbered stack variables that the parent needs. Boom! // In particular, the sys argument gets clobbered. // Note to self: GOCLOBBERDEADHASH=011100101110 + // + // runtime.wbBufFlush must not modify its arguments. See the comments + // in runtime/mwbbuf.go:wbBufFlush. return } diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go index df0e5f4059..e8c7fb5b14 100644 --- a/src/cmd/compile/internal/gc/racewalk.go +++ b/src/cmd/compile/internal/gc/racewalk.go @@ -10,7 +10,7 @@ import ( "cmd/internal/sys" ) -// The racewalk pass is currently handled in two parts. +// The racewalk pass is currently handled in three parts. // // First, for flag_race, it inserts calls to racefuncenter and // racefuncexit at the start and end (respectively) of each @@ -22,6 +22,10 @@ import ( // the Func.InstrumentBody flag as needed. For background on why this // is done during SSA construction rather than a separate SSA pass, // see issue #19054. +// +// Third we remove calls to racefuncenter and racefuncexit, for leaf +// functions without instrumented operations. This is done as part of +// ssa opt pass via special rule. // TODO(dvyukov): do not instrument initialization as writes: // a := make([]int, 10) diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index 591bd06368..13f45e164d 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -580,8 +580,7 @@ func arrayClear(n, v1, v2, a *Node) bool { tmp := nod(OINDEX, a, nodintconst(0)) tmp.SetBounded(true) tmp = nod(OADDR, tmp, nil) - tmp = nod(OCONVNOP, tmp, nil) - tmp.Type = types.Types[TUNSAFEPTR] + tmp = convnop(tmp, types.Types[TUNSAFEPTR]) n.Nbody.Append(nod(OAS, hp, tmp)) // hn = len(a) * sizeof(elem(a)) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index b948b45bb0..ffaaae428c 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -34,8 +34,9 @@ type ptabEntry struct { // runtime interface and reflection data structures var ( - signatsetmu sync.Mutex // protects signatset + signatmu sync.Mutex // protects signatset and signatslice signatset = make(map[*types.Type]struct{}) + signatslice []*types.Type itabs []itabEntry ptabs []ptabEntry @@ -958,6 +959,12 @@ func typesymprefix(prefix string, t *types.Type) *types.Sym { p := prefix + "." + t.ShortString() s := typeLookup(p) + // This function is for looking up type-related generated functions + // (e.g. eq and hash). Make sure they are indeed generated. + signatmu.Lock() + addsignat(t) + signatmu.Unlock() + //print("algsym: %s -> %+S\n", p, s); return s @@ -968,9 +975,9 @@ func typenamesym(t *types.Type) *types.Sym { Fatalf("typenamesym %v", t) } s := typesym(t) - signatsetmu.Lock() + signatmu.Lock() addsignat(t) - signatsetmu.Unlock() + signatmu.Unlock() return s } @@ -1468,7 +1475,10 @@ func itabsym(it *obj.LSym, offset int64) *obj.LSym { // addsignat ensures that a runtime type descriptor is emitted for t. func addsignat(t *types.Type) { - signatset[t] = struct{}{} + if _, ok := signatset[t]; !ok { + signatset[t] = struct{}{} + signatslice = append(signatslice, t) + } } func addsignats(dcls []*Node) { @@ -1483,14 +1493,15 @@ func addsignats(dcls []*Node) { func dumpsignats() { // Process signatset. Use a loop, as dtypesym adds // entries to signatset while it is being processed. - signats := make([]typeAndStr, len(signatset)) - for len(signatset) > 0 { + signats := make([]typeAndStr, len(signatslice)) + for len(signatslice) > 0 { signats = signats[:0] // Transfer entries to a slice and sort, for reproducible builds. - for t := range signatset { + for _, t := range signatslice { signats = append(signats, typeAndStr{t: t, short: typesymname(t), regular: t.String()}) delete(signatset, t) } + signatslice = signatslice[:0] sort.Sort(typesByString(signats)) for _, ts := range signats { t := ts.t diff --git a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go index b5f318e761..9173f80ee3 100644 --- a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go +++ b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go @@ -15,34 +15,45 @@ import ( ) func TestReproducibleBuilds(t *testing.T) { + tests := []string{ + "issue20272.go", + "issue27013.go", + } + testenv.MustHaveGoBuild(t) iters := 10 if testing.Short() { iters = 4 } t.Parallel() - var want []byte - tmp, err := ioutil.TempFile("", "") - if err != nil { - t.Fatalf("temp file creation failed: %v", err) - } - defer os.Remove(tmp.Name()) - defer tmp.Close() - for i := 0; i < iters; i++ { - out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", "issue20272.go")).CombinedOutput() - if err != nil { - t.Fatalf("failed to compile: %v\n%s", err, out) - } - obj, err := ioutil.ReadFile(tmp.Name()) - if err != nil { - t.Fatalf("failed to read object file: %v", err) - } - if i == 0 { - want = obj - } else { - if !bytes.Equal(want, obj) { - t.Fatalf("builds produced different output after %d iters (%d bytes vs %d bytes)", i, len(want), len(obj)) + for _, test := range tests { + test := test + t.Run(test, func(t *testing.T) { + t.Parallel() + var want []byte + tmp, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("temp file creation failed: %v", err) } - } + defer os.Remove(tmp.Name()) + defer tmp.Close() + for i := 0; i < iters; i++ { + out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", test)).CombinedOutput() + if err != nil { + t.Fatalf("failed to compile: %v\n%s", err, out) + } + obj, err := ioutil.ReadFile(tmp.Name()) + if err != nil { + t.Fatalf("failed to read object file: %v", err) + } + if i == 0 { + want = obj + } else { + if !bytes.Equal(want, obj) { + t.Fatalf("builds produced different output after %d iters (%d bytes vs %d bytes)", i, len(want), len(obj)) + } + } + } + }) } } diff --git a/src/cmd/compile/internal/gc/scope_test.go b/src/cmd/compile/internal/gc/scope_test.go index 944a81e670..e327dc02af 100644 --- a/src/cmd/compile/internal/gc/scope_test.go +++ b/src/cmd/compile/internal/gc/scope_test.go @@ -350,7 +350,6 @@ type scopexplainContext struct { dwarfData *dwarf.Data dwarfReader *dwarf.Reader scopegen int - lines map[line][]int } // readScope reads the DW_TAG_lexical_block or the DW_TAG_subprogram in diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go index 4445edbe92..c7f3908888 100644 --- a/src/cmd/compile/internal/gc/select.go +++ b/src/cmd/compile/internal/gc/select.go @@ -316,13 +316,11 @@ func walkselectcases(cases *Nodes) []*Node { setField("kind", nodintconst(kind)) if c != nil { - c = nod(OCONVNOP, c, nil) - c.Type = types.Types[TUNSAFEPTR] + c = convnop(c, types.Types[TUNSAFEPTR]) setField("c", c) } if elem != nil { - elem = nod(OCONVNOP, elem, nil) - elem.Type = types.Types[TUNSAFEPTR] + elem = convnop(elem, types.Types[TUNSAFEPTR]) setField("elem", elem) } @@ -375,10 +373,9 @@ func walkselectcases(cases *Nodes) []*Node { // bytePtrToIndex returns a Node representing "(*byte)(&n[i])". func bytePtrToIndex(n *Node, i int64) *Node { - s := nod(OCONVNOP, nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil), nil) - s.Type = types.NewPtr(types.Types[TUINT8]) - s = typecheck(s, Erv) - return s + s := nod(OADDR, nod(OINDEX, n, nodintconst(i)), nil) + t := types.NewPtr(types.Types[TUINT8]) + return convnop(s, t) } var scase *types.Type diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index ff2b93d3d4..00ff7d4bd5 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5,6 +5,7 @@ package gc import ( + "bufio" "bytes" "encoding/binary" "fmt" @@ -22,6 +23,13 @@ import ( var ssaConfig *ssa.Config var ssaCaches []ssa.Cache +var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output for +var ssaDumpStdout bool // whether to dump to stdout +const ssaDumpFile = "ssa.html" + +// ssaDumpInlined holds all inlined functions when ssaDump contains a function name. +var ssaDumpInlined []*Node + func initssaconfig() { types_ := ssa.NewTypes() @@ -49,6 +57,7 @@ func initssaconfig() { ssaConfig.Set387(thearch.Use387) } ssaConfig.SoftFloat = thearch.SoftFloat + ssaConfig.Race = flag_race ssaCaches = make([]ssa.Cache, nBackendWorkers) // Set up some runtime functions we'll need to call. @@ -56,7 +65,7 @@ func initssaconfig() { assertE2I2 = sysfunc("assertE2I2") assertI2I = sysfunc("assertI2I") assertI2I2 = sysfunc("assertI2I2") - Deferproc = sysfunc("deferproc") + deferproc = sysfunc("deferproc") Deferreturn = sysfunc("deferreturn") Duffcopy = sysfunc("duffcopy") Duffzero = sysfunc("duffzero") @@ -65,7 +74,7 @@ func initssaconfig() { growslice = sysfunc("growslice") msanread = sysfunc("msanread") msanwrite = sysfunc("msanwrite") - Newproc = sysfunc("newproc") + newproc = sysfunc("newproc") panicdivide = sysfunc("panicdivide") panicdottypeE = sysfunc("panicdottypeE") panicdottypeI = sysfunc("panicdottypeI") @@ -101,12 +110,17 @@ func initssaconfig() { // worker indicates which of the backend workers is doing the processing. func buildssa(fn *Node, worker int) *ssa.Func { name := fn.funcname() - printssa := name == os.Getenv("GOSSAFUNC") + printssa := name == ssaDump + var astBuf *bytes.Buffer if printssa { - fmt.Println("generating SSA for", name) - dumplist("buildssa-enter", fn.Func.Enter) - dumplist("buildssa-body", fn.Nbody) - dumplist("buildssa-exit", fn.Func.Exit) + astBuf = &bytes.Buffer{} + fdumplist(astBuf, "buildssa-enter", fn.Func.Enter) + fdumplist(astBuf, "buildssa-body", fn.Nbody) + fdumplist(astBuf, "buildssa-exit", fn.Func.Exit) + if ssaDumpStdout { + fmt.Println("generating SSA for", name) + fmt.Print(astBuf.String()) + } } var s state @@ -120,7 +134,7 @@ func buildssa(fn *Node, worker int) *ssa.Func { fe := ssafn{ curfn: fn, - log: printssa, + log: printssa && ssaDumpStdout, } s.curfn = fn @@ -138,9 +152,11 @@ func buildssa(fn *Node, worker int) *ssa.Func { s.panics = map[funcLine]*ssa.Block{} s.softFloat = s.config.SoftFloat - if name == os.Getenv("GOSSAFUNC") { - s.f.HTMLWriter = ssa.NewHTMLWriter("ssa.html", s.f.Frontend(), name) + if printssa { + s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDumpFile, s.f.Frontend(), name) // TODO: generate and print a mapping from nodes to values and blocks + dumpSourcesColumn(s.f.HTMLWriter, fn) + s.f.HTMLWriter.WriteAST("AST", astBuf) } // Allocate starting block @@ -162,7 +178,7 @@ func buildssa(fn *Node, worker int) *ssa.Func { for _, n := range fn.Func.Dcl { switch n.Class() { case PPARAM, PPARAMOUT: - s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), n, s.sp) + s.decladdrs[n] = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(n.Type), n, s.sp, s.startmem) if n.Class() == PPARAMOUT && s.canSSA(n) { // Save ssa-able PPARAMOUT variables so we can // store them back to the stack at the end of @@ -212,6 +228,59 @@ func buildssa(fn *Node, worker int) *ssa.Func { return s.f } +func dumpSourcesColumn(writer *ssa.HTMLWriter, fn *Node) { + // Read sources of target function fn. + fname := Ctxt.PosTable.Pos(fn.Pos).Filename() + targetFn, err := readFuncLines(fname, fn.Pos.Line(), fn.Func.Endlineno.Line()) + if err != nil { + writer.Logger.Logf("cannot read sources for function %v: %v", fn, err) + } + + // Read sources of inlined functions. + var inlFns []*ssa.FuncLines + for _, fi := range ssaDumpInlined { + var elno src.XPos + if fi.Name.Defn == nil { + // Endlineno is filled from exported data. + elno = fi.Func.Endlineno + } else { + elno = fi.Name.Defn.Func.Endlineno + } + fname := Ctxt.PosTable.Pos(fi.Pos).Filename() + fnLines, err := readFuncLines(fname, fi.Pos.Line(), elno.Line()) + if err != nil { + writer.Logger.Logf("cannot read sources for function %v: %v", fi, err) + continue + } + inlFns = append(inlFns, fnLines) + } + + sort.Sort(ssa.ByTopo(inlFns)) + if targetFn != nil { + inlFns = append([]*ssa.FuncLines{targetFn}, inlFns...) + } + + writer.WriteSources("sources", inlFns) +} + +func readFuncLines(file string, start, end uint) (*ssa.FuncLines, error) { + f, err := os.Open(os.ExpandEnv(file)) + if err != nil { + return nil, err + } + defer f.Close() + var lines []string + ln := uint(1) + scanner := bufio.NewScanner(f) + for scanner.Scan() && ln <= end { + if ln >= start { + lines = append(lines, scanner.Text()) + } + ln++ + } + return &ssa.FuncLines{Filename: file, StartLineno: start, Lines: lines}, nil +} + // updateUnsetPredPos propagates the earliest-value position information for b // towards all of b's predecessors that need a position, and recurs on that // predecessor if its position is updated. B should have a non-empty position. @@ -454,6 +523,16 @@ func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa. return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1) } +// newValue2Apos adds a new value with two arguments and an aux value to the current block. +// isStmt determines whether the created values may be a statement or not +// (i.e., false means never, yes means maybe). +func (s *state) newValue2Apos(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value, isStmt bool) *ssa.Value { + if isStmt { + return s.curBlock.NewValue2A(s.peekPos(), op, t, aux, arg0, arg1) + } + return s.curBlock.NewValue2A(s.peekPos().WithNotStmt(), op, t, aux, arg0, arg1) +} + // newValue2I adds a new value with two arguments and an auxint value to the current block. func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value { return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1) @@ -519,6 +598,11 @@ func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) return s.f.Entry.NewValue2(src.NoXPos, op, t, arg0, arg1) } +// entryNewValue2A adds a new value with two arguments and an aux value to the entry block. +func (s *state) entryNewValue2A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value { + return s.f.Entry.NewValue2A(src.NoXPos, op, t, aux, arg0, arg1) +} + // const* routines add a new const value to the entry block. func (s *state) constSlice(t *types.Type) *ssa.Value { return s.f.ConstSlice(t) @@ -2584,10 +2668,10 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) return } // Left is not ssa-able. Compute its address. - addr := s.addr(left, false) if left.Op == ONAME && left.Class() != PEXTERN && skip == 0 { s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, left, s.mem(), !left.IsAutoTmp()) } + addr := s.addr(left, false) if isReflectHeaderDataField(left) { // Package unsafe's documentation says storing pointers into // reflect.SliceHeader and reflect.StringHeader's Data fields @@ -3263,6 +3347,28 @@ func init() { return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0]) }, sys.ARM64) + addF("math/bits", "RotateLeft8", + func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return s.newValue2(ssa.OpRotateLeft8, types.Types[TUINT8], args[0], args[1]) + }, + sys.AMD64) + addF("math/bits", "RotateLeft16", + func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return s.newValue2(ssa.OpRotateLeft16, types.Types[TUINT16], args[0], args[1]) + }, + sys.AMD64) + addF("math/bits", "RotateLeft32", + func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return s.newValue2(ssa.OpRotateLeft32, types.Types[TUINT32], args[0], args[1]) + }, + sys.AMD64, sys.S390X) + addF("math/bits", "RotateLeft64", + func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return s.newValue2(ssa.OpRotateLeft64, types.Types[TUINT64], args[0], args[1]) + }, + sys.AMD64, sys.S390X) + alias("math/bits", "RotateLeft", "math/bits", "RotateLeft64", p8...) + makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value { return func(s *state, n *Node, args []*ssa.Value) *ssa.Value { addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), supportPopcnt, s.sb) @@ -3304,7 +3410,7 @@ func init() { func(s *state, n *Node, args []*ssa.Value) *ssa.Value { return s.newValue1(ssa.OpPopCount64, types.Types[TINT], args[0]) }, - sys.PPC64, sys.ARM64) + sys.PPC64, sys.ARM64, sys.S390X) addF("math/bits", "OnesCount32", makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32), sys.AMD64) @@ -3312,7 +3418,7 @@ func init() { func(s *state, n *Node, args []*ssa.Value) *ssa.Value { return s.newValue1(ssa.OpPopCount32, types.Types[TINT], args[0]) }, - sys.PPC64, sys.ARM64) + sys.PPC64, sys.ARM64, sys.S390X) addF("math/bits", "OnesCount16", makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16), sys.AMD64) @@ -3320,8 +3426,12 @@ func init() { func(s *state, n *Node, args []*ssa.Value) *ssa.Value { return s.newValue1(ssa.OpPopCount16, types.Types[TINT], args[0]) }, - sys.ARM64) - // Note: no OnesCount8, the Go implementation is faster - just a table load. + sys.ARM64, sys.S390X) + addF("math/bits", "OnesCount8", + func(s *state, n *Node, args []*ssa.Value) *ssa.Value { + return s.newValue1(ssa.OpPopCount8, types.Types[TINT], args[0]) + }, + sys.S390X) addF("math/bits", "OnesCount", makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32), sys.AMD64) @@ -3500,6 +3610,10 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { break } closure = s.expr(fn) + if thearch.LinkArch.Family == sys.Wasm { + // TODO(neelance): On other architectures this should be eliminated by the optimization steps + s.nilCheck(closure) + } case OCALLMETH: if fn.Op != ODOTMETH { Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn) @@ -3558,7 +3672,7 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { // Defer/go args if k != callNormal { - // Write argsize and closure (args to Newproc/Deferproc). + // Write argsize and closure (args to newproc/deferproc). argStart := Ctxt.FixedFrameSize() argsize := s.constInt32(types.Types[TUINT32], int32(stksize)) addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart) @@ -3572,9 +3686,9 @@ func (s *state) call(n *Node, k callKind) *ssa.Value { var call *ssa.Value switch { case k == callDefer: - call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Deferproc, s.mem()) + call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, deferproc, s.mem()) case k == callGo: - call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Newproc, s.mem()) + call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, newproc, s.mem()) case closure != nil: // rawLoad because loading the code pointer from a // closure is always safe, but IsSanitizerSafeAddr @@ -3655,16 +3769,17 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { } if n == nodfp { // Special arg that points to the frame pointer (Used by ORECOVER). - return s.entryNewValue1A(ssa.OpAddr, t, n, s.sp) + return s.entryNewValue2A(ssa.OpLocalAddr, t, n, s.sp, s.startmem) } s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) return nil case PAUTO: - return s.newValue1Apos(ssa.OpAddr, t, n, s.sp, !n.IsAutoTmp()) + return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), !n.IsAutoTmp()) + case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early. // ensure that we reuse symbols for out parameters so // that cse works on their addresses - return s.newValue1A(ssa.OpAddr, t, n, s.sp) + return s.newValue2Apos(ssa.OpLocalAddr, t, n, s.sp, s.mem(), true) default: s.Fatalf("variable address class %v not implemented", n.Class()) return nil @@ -4578,8 +4693,8 @@ func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { // unSSAable type, use temporary. // TODO: get rid of some of these temporaries. tmp = tempAt(n.Pos, s.curfn, n.Type) - addr = s.addr(tmp, false) s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem()) + addr = s.addr(tmp, false) } cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab) @@ -4827,7 +4942,8 @@ func genssa(f *ssa.Func, pp *Progs) { var progToBlock map[*obj.Prog]*ssa.Block var valueToProgAfter []*obj.Prog // The first Prog following computation of a value v; v is visible at this point. var logProgs = e.log - if logProgs { + if f.HTMLWriter != nil { + // logProgs can be false, meaning that we do not dump to the Stdout. progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues()) progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks()) f.Logf("genssa %s\n", f.Name) @@ -4996,42 +5112,36 @@ func genssa(f *ssa.Func, pp *Progs) { } f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString()) } - if f.HTMLWriter != nil { - // LineHist is defunct now - this code won't do - // anything. - // TODO: fix this (ideally without a global variable) - // saved := pp.Text.Ctxt.LineHist.PrintFilenameOnly - // pp.Text.Ctxt.LineHist.PrintFilenameOnly = true - var buf bytes.Buffer - buf.WriteString("") - buf.WriteString("
    ") - filename := "" - for p := pp.Text; p != nil; p = p.Link { - // Don't spam every line with the file name, which is often huge. - // Only print changes, and "unknown" is not a change. - if p.Pos.IsKnown() && p.InnermostFilename() != filename { - filename = p.InnermostFilename() - buf.WriteString("
    ") - buf.WriteString(html.EscapeString("# " + filename)) - buf.WriteString("
    ") - } - - buf.WriteString("
    ") - if v, ok := progToValue[p]; ok { - buf.WriteString(v.HTML()) - } else if b, ok := progToBlock[p]; ok { - buf.WriteString("" + b.HTML() + "") - } - buf.WriteString("
    ") - buf.WriteString("
    ") - buf.WriteString(fmt.Sprintf("%.5d (%s) %s", p.Pc, p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))) + } + if f.HTMLWriter != nil { + var buf bytes.Buffer + buf.WriteString("") + buf.WriteString("
    ") + filename := "" + for p := pp.Text; p != nil; p = p.Link { + // Don't spam every line with the file name, which is often huge. + // Only print changes, and "unknown" is not a change. + if p.Pos.IsKnown() && p.InnermostFilename() != filename { + filename = p.InnermostFilename() + buf.WriteString("
    ") + buf.WriteString(html.EscapeString("# " + filename)) buf.WriteString("
    ") } - buf.WriteString("
    ") - buf.WriteString("
    ") - f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) - // pp.Text.Ctxt.LineHist.PrintFilenameOnly = saved + + buf.WriteString("
    ") + if v, ok := progToValue[p]; ok { + buf.WriteString(v.HTML()) + } else if b, ok := progToBlock[p]; ok { + buf.WriteString("" + b.HTML() + "") + } + buf.WriteString("
    ") + buf.WriteString("
    ") + buf.WriteString(fmt.Sprintf("%.5d (%s) %s", p.Pc, p.InnermostLineNumber(), p.InnermostLineNumberHTML(), html.EscapeString(p.InstructionString()))) + buf.WriteString("
    ") } + buf.WriteString("
    ") + buf.WriteString("
    ") + f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) } defframe(&s, e) @@ -5389,7 +5499,7 @@ type ssafn struct { scratchFpMem *Node // temp for floating point register / memory moves on some architectures stksize int64 // stack size for current frame stkptrsize int64 // prefix of stack containing pointers - log bool + log bool // print ssa debug to the stdout } // StringData returns a symbol (a *types.Sym wrapped in an interface) which @@ -5581,7 +5691,8 @@ func (e *ssafn) Log() bool { // Fatal reports a compiler error and exits. func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) { lineno = pos - Fatalf(msg, args...) + nargs := append([]interface{}{e.curfn.funcname()}, args...) + Fatalf("'%s': "+msg, nargs...) } // Warnl reports a "warning", which is usually flag-triggered @@ -5631,7 +5742,7 @@ func (n *Node) StorageClass() ssa.StorageClass { case PAUTO: return ssa.ClassAuto default: - Fatalf("untranslateable storage class for %v: %s", n, n.Class()) + Fatalf("untranslatable storage class for %v: %s", n, n.Class()) return 0 } } diff --git a/src/cmd/compile/internal/gc/ssa_test.go b/src/cmd/compile/internal/gc/ssa_test.go index 2aa923f9f4..7f7c9464d4 100644 --- a/src/cmd/compile/internal/gc/ssa_test.go +++ b/src/cmd/compile/internal/gc/ssa_test.go @@ -6,6 +6,10 @@ package gc import ( "bytes" + "fmt" + "go/ast" + "go/parser" + "go/token" "internal/testenv" "io/ioutil" "os" @@ -16,43 +20,6 @@ import ( "testing" ) -// TODO: move all these tests elsewhere? -// Perhaps teach test/run.go how to run them with a new action verb. -func runTest(t *testing.T, filename string, flags ...string) { - t.Parallel() - doTest(t, filename, "run", flags...) -} -func buildTest(t *testing.T, filename string, flags ...string) { - t.Parallel() - doTest(t, filename, "build", flags...) -} -func doTest(t *testing.T, filename string, kind string, flags ...string) { - testenv.MustHaveGoBuild(t) - gotool := testenv.GoToolPath(t) - - var stdout, stderr bytes.Buffer - args := []string{kind} - if len(flags) == 0 { - args = append(args, "-gcflags=-d=ssa/check/on") - } else { - args = append(args, flags...) - } - args = append(args, filepath.Join("testdata", filename)) - cmd := exec.Command(gotool, args...) - cmd.Stdout = &stdout - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - t.Fatalf("Failed: %v:\nOut: %s\nStderr: %s\n", err, &stdout, &stderr) - } - if s := stdout.String(); s != "" { - t.Errorf("Stdout = %s\nWant empty", s) - } - if s := stderr.String(); strings.Contains(s, "SSA unimplemented") { - t.Errorf("Unimplemented message found in stderr:\n%s", s) - } -} - // runGenTest runs a test-generator, then runs the generated test. // Generated test can either fail in compilation or execution. // The environment variable parameter(s) is passed to the run @@ -99,77 +66,126 @@ func runGenTest(t *testing.T, filename, tmpname string, ev ...string) { } func TestGenFlowGraph(t *testing.T) { + if testing.Short() { + t.Skip("not run in short mode.") + } runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp1") - if runtime.GOOS != "windows" { - runGenTest(t, "flowgraph_generator1.go", "ssa_fg_tmp2", "GO_SSA_PHI_LOC_CUTOFF=0") +} + +// TestCode runs all the tests in the testdata directory as subtests. +// These tests are special because we want to run them with different +// compiler flags set (and thus they can't just be _test.go files in +// this directory). +func TestCode(t *testing.T) { + testenv.MustHaveGoBuild(t) + gotool := testenv.GoToolPath(t) + + // Make a temporary directory to work in. + tmpdir, err := ioutil.TempDir("", "TestCode") + if err != nil { + t.Fatalf("Failed to create temporary directory: %v", err) + } + defer os.RemoveAll(tmpdir) + + // Find all the test functions (and the files containing them). + var srcs []string // files containing Test functions + type test struct { + name string // TestFoo + usesFloat bool // might use float operations + } + var tests []test + files, err := ioutil.ReadDir("testdata") + if err != nil { + t.Fatalf("can't read testdata directory: %v", err) + } + for _, f := range files { + if !strings.HasSuffix(f.Name(), "_test.go") { + continue + } + text, err := ioutil.ReadFile(filepath.Join("testdata", f.Name())) + if err != nil { + t.Fatalf("can't read testdata/%s: %v", f.Name(), err) + } + fset := token.NewFileSet() + code, err := parser.ParseFile(fset, f.Name(), text, 0) + if err != nil { + t.Fatalf("can't parse testdata/%s: %v", f.Name(), err) + } + srcs = append(srcs, filepath.Join("testdata", f.Name())) + foundTest := false + for _, d := range code.Decls { + fd, ok := d.(*ast.FuncDecl) + if !ok { + continue + } + if !strings.HasPrefix(fd.Name.Name, "Test") { + continue + } + if fd.Recv != nil { + continue + } + if fd.Type.Results != nil { + continue + } + if len(fd.Type.Params.List) != 1 { + continue + } + p := fd.Type.Params.List[0] + if len(p.Names) != 1 { + continue + } + s, ok := p.Type.(*ast.StarExpr) + if !ok { + continue + } + sel, ok := s.X.(*ast.SelectorExpr) + if !ok { + continue + } + base, ok := sel.X.(*ast.Ident) + if !ok { + continue + } + if base.Name != "testing" { + continue + } + if sel.Sel.Name != "T" { + continue + } + // Found a testing function. + tests = append(tests, test{name: fd.Name.Name, usesFloat: bytes.Contains(text, []byte("float"))}) + foundTest = true + } + if !foundTest { + t.Fatalf("test file testdata/%s has no tests in it", f.Name()) + } + } + + flags := []string{""} + if runtime.GOARCH == "arm" || runtime.GOARCH == "mips" || runtime.GOARCH == "mips64" { + flags = append(flags, ",softfloat") + } + for _, flag := range flags { + args := []string{"test", "-c", "-gcflags=-d=ssa/check/on" + flag, "-o", filepath.Join(tmpdir, "code.test")} + args = append(args, srcs...) + out, err := exec.Command(gotool, args...).CombinedOutput() + if err != nil || len(out) != 0 { + t.Fatalf("Build failed: %v\n%s\n", err, out) + } + + // Now we have a test binary. Run it with all the tests as subtests of this one. + for _, test := range tests { + test := test + if flag == ",softfloat" && !test.usesFloat { + // No point in running the soft float version if the test doesn't use floats. + continue + } + t.Run(fmt.Sprintf("%s%s", test.name[4:], flag), func(t *testing.T) { + out, err := exec.Command(filepath.Join(tmpdir, "code.test"), "-test.run="+test.name).CombinedOutput() + if err != nil || string(out) != "PASS\n" { + t.Errorf("Failed:\n%s\n", out) + } + }) + } } } - -// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting. -func TestShortCircuit(t *testing.T) { runTest(t, "short.go") } - -// TestBreakContinue tests that continue and break statements do what they say. -func TestBreakContinue(t *testing.T) { runTest(t, "break.go") } - -// TestTypeAssertion tests type assertions. -func TestTypeAssertion(t *testing.T) { runTest(t, "assert.go") } - -// TestArithmetic tests that both backends have the same result for arithmetic expressions. -func TestArithmetic(t *testing.T) { runTest(t, "arith.go") } - -// TestFP tests that both backends have the same result for floating point expressions. -func TestFP(t *testing.T) { runTest(t, "fp.go") } - -func TestFPSoftFloat(t *testing.T) { - runTest(t, "fp.go", "-gcflags=-d=softfloat,ssa/check/on") -} - -// TestArithmeticBoundary tests boundary results for arithmetic operations. -func TestArithmeticBoundary(t *testing.T) { runTest(t, "arithBoundary.go") } - -// TestArithmeticConst tests results for arithmetic operations against constants. -func TestArithmeticConst(t *testing.T) { runTest(t, "arithConst.go") } - -func TestChan(t *testing.T) { runTest(t, "chan.go") } - -// TestComparisonsConst tests results for comparison operations against constants. -func TestComparisonsConst(t *testing.T) { runTest(t, "cmpConst.go") } - -func TestCompound(t *testing.T) { runTest(t, "compound.go") } - -func TestCtl(t *testing.T) { runTest(t, "ctl.go") } - -func TestLoadStore(t *testing.T) { runTest(t, "loadstore.go") } - -func TestMap(t *testing.T) { runTest(t, "map.go") } - -func TestRegalloc(t *testing.T) { runTest(t, "regalloc.go") } - -func TestString(t *testing.T) { runTest(t, "string.go") } - -func TestDeferNoReturn(t *testing.T) { buildTest(t, "deferNoReturn.go") } - -// TestClosure tests closure related behavior. -func TestClosure(t *testing.T) { runTest(t, "closure.go") } - -func TestArray(t *testing.T) { runTest(t, "array.go") } - -func TestAppend(t *testing.T) { runTest(t, "append.go") } - -func TestZero(t *testing.T) { runTest(t, "zero.go") } - -func TestAddressed(t *testing.T) { runTest(t, "addressed.go") } - -func TestCopy(t *testing.T) { runTest(t, "copy.go") } - -func TestUnsafe(t *testing.T) { runTest(t, "unsafe.go") } - -func TestPhi(t *testing.T) { runTest(t, "phi.go") } - -func TestSlice(t *testing.T) { runTest(t, "slice.go") } - -func TestNamedReturn(t *testing.T) { runTest(t, "namedReturn.go") } - -func TestDuplicateLoad(t *testing.T) { runTest(t, "dupLoad.go") } - -func TestSqrt(t *testing.T) { runTest(t, "sqrt_const.go") } diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 0af0ff82c4..61a3b2385d 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -1674,8 +1674,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { if !dotlist[0].field.Type.IsPtr() { dot = nod(OADDR, dot, nil) } - as := nod(OAS, nthis, nod(OCONVNOP, dot, nil)) - as.Right.Type = rcvr + as := nod(OAS, nthis, convnop(dot, rcvr)) fn.Nbody.Append(as) fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym))) } else { diff --git a/src/cmd/compile/internal/gc/testdata/addressed.go b/src/cmd/compile/internal/gc/testdata/addressed_test.go similarity index 83% rename from src/cmd/compile/internal/gc/testdata/addressed.go rename to src/cmd/compile/internal/gc/testdata/addressed_test.go index 59cf238c74..cdabf978f0 100644 --- a/src/cmd/compile/internal/gc/testdata/addressed.go +++ b/src/cmd/compile/internal/gc/testdata/addressed_test.go @@ -4,48 +4,51 @@ package main -import "fmt" +import ( + "fmt" + "testing" +) var output string -func mypanic(s string) { - fmt.Printf(output) - panic(s) +func mypanic(t *testing.T, s string) { + t.Fatalf(s + "\n" + output) + } -func assertEqual(x, y int) { +func assertEqual(t *testing.T, x, y int) { if x != y { - mypanic("assertEqual failed") + mypanic(t, fmt.Sprintf("assertEqual failed got %d, want %d", x, y)) } } -func main() { +func TestAddressed(t *testing.T) { x := f1_ssa(2, 3) output += fmt.Sprintln("*x is", *x) output += fmt.Sprintln("Gratuitously use some stack") output += fmt.Sprintln("*x is", *x) - assertEqual(*x, 9) + assertEqual(t, *x, 9) w := f3a_ssa(6) output += fmt.Sprintln("*w is", *w) output += fmt.Sprintln("Gratuitously use some stack") output += fmt.Sprintln("*w is", *w) - assertEqual(*w, 6) + assertEqual(t, *w, 6) y := f3b_ssa(12) output += fmt.Sprintln("*y.(*int) is", *y.(*int)) output += fmt.Sprintln("Gratuitously use some stack") output += fmt.Sprintln("*y.(*int) is", *y.(*int)) - assertEqual(*y.(*int), 12) + assertEqual(t, *y.(*int), 12) z := f3c_ssa(8) output += fmt.Sprintln("*z.(*int) is", *z.(*int)) output += fmt.Sprintln("Gratuitously use some stack") output += fmt.Sprintln("*z.(*int) is", *z.(*int)) - assertEqual(*z.(*int), 8) + assertEqual(t, *z.(*int), 8) - args() - test_autos() + args(t) + test_autos(t) } //go:noinline @@ -75,13 +78,13 @@ type V struct { w, x int64 } -func args() { +func args(t *testing.T) { v := V{p: nil, w: 1, x: 1} a := V{p: &v, w: 2, x: 2} b := V{p: &v, w: 0, x: 0} i := v.args_ssa(a, b) output += fmt.Sprintln("i=", i) - assertEqual(int(i), 2) + assertEqual(t, int(i), 2) } //go:noinline @@ -100,32 +103,32 @@ func (v V) args_ssa(a, b V) int64 { return -1 } -func test_autos() { - test(11) - test(12) - test(13) - test(21) - test(22) - test(23) - test(31) - test(32) +func test_autos(t *testing.T) { + test(t, 11) + test(t, 12) + test(t, 13) + test(t, 21) + test(t, 22) + test(t, 23) + test(t, 31) + test(t, 32) } -func test(which int64) { +func test(t *testing.T, which int64) { output += fmt.Sprintln("test", which) v1 := V{w: 30, x: 3, p: nil} v2, v3 := v1.autos_ssa(which, 10, 1, 20, 2) if which != v2.val() { output += fmt.Sprintln("Expected which=", which, "got v2.val()=", v2.val()) - mypanic("Failure of expected V value") + mypanic(t, "Failure of expected V value") } if v2.p.val() != v3.val() { output += fmt.Sprintln("Expected v2.p.val()=", v2.p.val(), "got v3.val()=", v3.val()) - mypanic("Failure of expected V.p value") + mypanic(t, "Failure of expected V.p value") } if which != v3.p.p.p.p.p.p.p.val() { output += fmt.Sprintln("Expected which=", which, "got v3.p.p.p.p.p.p.p.val()=", v3.p.p.p.p.p.p.p.val()) - mypanic("Failure of expected V.p value") + mypanic(t, "Failure of expected V.p value") } } diff --git a/src/cmd/compile/internal/gc/testdata/append.go b/src/cmd/compile/internal/gc/testdata/append_test.go similarity index 60% rename from src/cmd/compile/internal/gc/testdata/append.go rename to src/cmd/compile/internal/gc/testdata/append_test.go index 03cd219c32..6663ce75fa 100644 --- a/src/cmd/compile/internal/gc/testdata/append.go +++ b/src/cmd/compile/internal/gc/testdata/append_test.go @@ -5,9 +5,7 @@ // append_ssa.go tests append operations. package main -import "fmt" - -var failed = false +import "testing" //go:noinline func appendOne_ssa(a []int, x int) []int { @@ -19,7 +17,7 @@ func appendThree_ssa(a []int, x, y, z int) []int { return append(a, x, y, z) } -func eq(a, b []int) bool { +func eqBytes(a, b []int) bool { if len(a) != len(b) { return false } @@ -31,40 +29,33 @@ func eq(a, b []int) bool { return true } -func expect(got, want []int) { - if eq(got, want) { +func expect(t *testing.T, got, want []int) { + if eqBytes(got, want) { return } - fmt.Printf("expected %v, got %v\n", want, got) - failed = true + t.Errorf("expected %v, got %v\n", want, got) } -func testAppend() { +func testAppend(t *testing.T) { var store [7]int a := store[:0] a = appendOne_ssa(a, 1) - expect(a, []int{1}) + expect(t, a, []int{1}) a = appendThree_ssa(a, 2, 3, 4) - expect(a, []int{1, 2, 3, 4}) + expect(t, a, []int{1, 2, 3, 4}) a = appendThree_ssa(a, 5, 6, 7) - expect(a, []int{1, 2, 3, 4, 5, 6, 7}) + expect(t, a, []int{1, 2, 3, 4, 5, 6, 7}) if &a[0] != &store[0] { - fmt.Println("unnecessary grow") - failed = true + t.Errorf("unnecessary grow") } a = appendOne_ssa(a, 8) - expect(a, []int{1, 2, 3, 4, 5, 6, 7, 8}) + expect(t, a, []int{1, 2, 3, 4, 5, 6, 7, 8}) if &a[0] == &store[0] { - fmt.Println("didn't grow") - failed = true + t.Errorf("didn't grow") } } -func main() { - testAppend() - - if failed { - panic("failed") - } +func TestAppend(t *testing.T) { + testAppend(t) } diff --git a/src/cmd/compile/internal/gc/testdata/arithBoundary.go b/src/cmd/compile/internal/gc/testdata/arithBoundary_test.go similarity index 88% rename from src/cmd/compile/internal/gc/testdata/arithBoundary.go rename to src/cmd/compile/internal/gc/testdata/arithBoundary_test.go index 4a7afe690f..777b7cdd60 100644 --- a/src/cmd/compile/internal/gc/testdata/arithBoundary.go +++ b/src/cmd/compile/internal/gc/testdata/arithBoundary_test.go @@ -1,9 +1,8 @@ -// run // Code generated by gen/arithBoundaryGen.go. DO NOT EDIT. package main -import "fmt" +import "testing" type utd64 struct { a, b uint64 @@ -504,235 +503,192 @@ var int8_data []itd8 = []itd8{itd8{a: -128, b: -128, add: 0, sub: 0, mul: 0, div itd8{a: 127, b: 126, add: -3, sub: 1, mul: -126, div: 1, mod: 1}, itd8{a: 127, b: 127, add: -2, sub: 0, mul: 1, div: 1, mod: 0}, } -var failed bool -func main() { +//TestArithmeticBoundary tests boundary results for arithmetic operations. +func TestArithmeticBoundary(t *testing.T) { for _, v := range uint64_data { if got := add_uint64_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_uint64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_uint64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_uint64_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_uint64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_uint64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_uint64_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_uint64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_uint64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_uint64_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_uint64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_uint64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_uint64_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_uint64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_uint64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range int64_data { if got := add_int64_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_int64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_int64 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_int64_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_int64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_int64 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_int64_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_int64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_int64 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_int64_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_int64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_int64 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_int64_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_int64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_int64 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range uint32_data { if got := add_uint32_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_uint32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_uint32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_uint32_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_uint32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_uint32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_uint32_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_uint32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_uint32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_uint32_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_uint32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_uint32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_uint32_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_uint32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_uint32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range int32_data { if got := add_int32_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_int32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_int32 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_int32_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_int32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_int32 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_int32_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_int32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_int32 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_int32_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_int32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_int32 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_int32_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_int32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_int32 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range uint16_data { if got := add_uint16_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_uint16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_uint16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_uint16_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_uint16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_uint16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_uint16_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_uint16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_uint16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_uint16_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_uint16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_uint16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_uint16_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_uint16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_uint16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range int16_data { if got := add_int16_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_int16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_int16 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_int16_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_int16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_int16 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_int16_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_int16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_int16 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_int16_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_int16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_int16 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_int16_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_int16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_int16 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range uint8_data { if got := add_uint8_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_uint8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_uint8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_uint8_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_uint8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_uint8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_uint8_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_uint8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_uint8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_uint8_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_uint8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_uint8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_uint8_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_uint8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_uint8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } for _, v := range int8_data { if got := add_int8_ssa(v.a, v.b); got != v.add { - fmt.Printf("add_int8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) - failed = true + t.Errorf("add_int8 %d+%d = %d, wanted %d\n", v.a, v.b, got, v.add) } if got := sub_int8_ssa(v.a, v.b); got != v.sub { - fmt.Printf("sub_int8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) - failed = true + t.Errorf("sub_int8 %d-%d = %d, wanted %d\n", v.a, v.b, got, v.sub) } if v.b != 0 { if got := div_int8_ssa(v.a, v.b); got != v.div { - fmt.Printf("div_int8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) - failed = true + t.Errorf("div_int8 %d/%d = %d, wanted %d\n", v.a, v.b, got, v.div) } } if v.b != 0 { if got := mod_int8_ssa(v.a, v.b); got != v.mod { - fmt.Printf("mod_int8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) - failed = true + t.Errorf("mod_int8 %d%%%d = %d, wanted %d\n", v.a, v.b, got, v.mod) } } if got := mul_int8_ssa(v.a, v.b); got != v.mul { - fmt.Printf("mul_int8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) - failed = true + t.Errorf("mul_int8 %d*%d = %d, wanted %d\n", v.a, v.b, got, v.mul) } } - if failed { - panic("tests failed") - } } diff --git a/src/cmd/compile/internal/gc/testdata/arithConst.go b/src/cmd/compile/internal/gc/testdata/arithConst_test.go similarity index 99% rename from src/cmd/compile/internal/gc/testdata/arithConst.go rename to src/cmd/compile/internal/gc/testdata/arithConst_test.go index 4ece5a9cb6..9f5ac61427 100644 --- a/src/cmd/compile/internal/gc/testdata/arithConst.go +++ b/src/cmd/compile/internal/gc/testdata/arithConst_test.go @@ -1,10 +1,8 @@ -// run // Code generated by gen/arithConstGen.go. DO NOT EDIT. package main -import "fmt" -import "os" +import "testing" //go:noinline func add_uint64_0(a uint64) uint64 { return a + 0 } @@ -9506,83 +9504,67 @@ var tests_int8 = []test_int8{ test_int8{fn: xor_127_int8, fnname: "xor_127_int8", in: 127, want: 0}, test_int8{fn: xor_int8_127, fnname: "xor_int8_127", in: 127, want: 0}} -var failed bool - -func main() { +// TestArithmeticConst tests results for arithmetic operations against constants. +func TestArithmeticConst(t *testing.T) { for _, test := range tests_uint64 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_uint64mul { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int64 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int64mul { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_uint32 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_uint32mul { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int32 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int32mul { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_uint16 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int16 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_uint8 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } for _, test := range tests_int8 { if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } - if failed { - os.Exit(1) - } } diff --git a/src/cmd/compile/internal/gc/testdata/arith.go b/src/cmd/compile/internal/gc/testdata/arith_test.go similarity index 68% rename from src/cmd/compile/internal/gc/testdata/arith.go rename to src/cmd/compile/internal/gc/testdata/arith_test.go index d850ce27b2..d30d660b34 100644 --- a/src/cmd/compile/internal/gc/testdata/arith.go +++ b/src/cmd/compile/internal/gc/testdata/arith_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,7 +6,9 @@ package main -import "fmt" +import ( + "testing" +) const ( y = 0x0fffFFFF @@ -56,39 +56,31 @@ func rshNotNop(x uint64) uint64 { return (((x >> 5) << 2) >> 1) } -func testShiftRemoval() { +func testShiftRemoval(t *testing.T) { allSet := ^uint64(0) if want, got := uint64(0x7ffffffffffffff), rshNop1(allSet); want != got { - println("testShiftRemoval rshNop1 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval rshNop1 failed, wanted %d got %d", want, got) } if want, got := uint64(0x3ffffffffffffff), rshNop2(allSet); want != got { - println("testShiftRemoval rshNop2 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval rshNop2 failed, wanted %d got %d", want, got) } if want, got := uint64(0x7fffffffffffff), rshNop3(allSet); want != got { - println("testShiftRemoval rshNop3 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval rshNop3 failed, wanted %d got %d", want, got) } if want, got := uint64(0xffffffffffffffe), rshNotNop(allSet); want != got { - println("testShiftRemoval rshNotNop failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval rshNotNop failed, wanted %d got %d", want, got) } if want, got := uint64(0xffffffffffffffe0), lshNop1(allSet); want != got { - println("testShiftRemoval lshNop1 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval lshNop1 failed, wanted %d got %d", want, got) } if want, got := uint64(0xffffffffffffffc0), lshNop2(allSet); want != got { - println("testShiftRemoval lshNop2 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval lshNop2 failed, wanted %d got %d", want, got) } if want, got := uint64(0xfffffffffffffe00), lshNop3(allSet); want != got { - println("testShiftRemoval lshNop3 failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval lshNop3 failed, wanted %d got %d", want, got) } if want, got := uint64(0x7ffffffffffffff0), lshNotNop(allSet); want != got { - println("testShiftRemoval lshNotNop failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftRemoval lshNotNop failed, wanted %d got %d", want, got) } } @@ -110,37 +102,32 @@ func parseLE16(b []byte) uint16 { } // testLoadCombine tests for issue #14694 where load combining didn't respect the pointer offset. -func testLoadCombine() { +func testLoadCombine(t *testing.T) { testData := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09} if want, got := uint64(0x0908070605040302), parseLE64(testData); want != got { - println("testLoadCombine failed, wanted", want, "got", got) - failed = true + t.Errorf("testLoadCombine failed, wanted %d got %d", want, got) } if want, got := uint32(0x05040302), parseLE32(testData); want != got { - println("testLoadCombine failed, wanted", want, "got", got) - failed = true + t.Errorf("testLoadCombine failed, wanted %d got %d", want, got) } if want, got := uint16(0x0302), parseLE16(testData); want != got { - println("testLoadCombine failed, wanted", want, "got", got) - failed = true + t.Errorf("testLoadCombine failed, wanted %d got %d", want, got) } } var loadSymData = [...]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} -func testLoadSymCombine() { +func testLoadSymCombine(t *testing.T) { w2 := uint16(0x0201) g2 := uint16(loadSymData[0]) | uint16(loadSymData[1])<<8 if g2 != w2 { - println("testLoadSymCombine failed, wanted", w2, "got", g2) - failed = true + t.Errorf("testLoadSymCombine failed, wanted %d got %d", w2, g2) } w4 := uint32(0x04030201) g4 := uint32(loadSymData[0]) | uint32(loadSymData[1])<<8 | uint32(loadSymData[2])<<16 | uint32(loadSymData[3])<<24 if g4 != w4 { - println("testLoadSymCombine failed, wanted", w4, "got", g4) - failed = true + t.Errorf("testLoadSymCombine failed, wanted %d got %d", w4, g4) } w8 := uint64(0x0807060504030201) g8 := uint64(loadSymData[0]) | uint64(loadSymData[1])<<8 | @@ -148,8 +135,7 @@ func testLoadSymCombine() { uint64(loadSymData[4])<<32 | uint64(loadSymData[5])<<40 | uint64(loadSymData[6])<<48 | uint64(loadSymData[7])<<56 if g8 != w8 { - println("testLoadSymCombine failed, wanted", w8, "got", g8) - failed = true + t.Errorf("testLoadSymCombine failed, wanted %d got %d", w8, g8) } } @@ -170,34 +156,29 @@ func invalidMul_ssa(x uint32) uint32 { // testLargeConst tests a situation where larger than 32 bit consts were passed to ADDL // causing an invalid instruction error. -func testLargeConst() { +func testLargeConst(t *testing.T) { if want, got := uint32(268435440), invalidAdd_ssa(1); want != got { - println("testLargeConst add failed, wanted", want, "got", got) - failed = true + t.Errorf("testLargeConst add failed, wanted %d got %d", want, got) } if want, got := uint32(4026531858), invalidSub_ssa(1); want != got { - println("testLargeConst sub failed, wanted", want, "got", got) - failed = true + t.Errorf("testLargeConst sub failed, wanted %d got %d", want, got) } if want, got := uint32(268435455), invalidMul_ssa(1); want != got { - println("testLargeConst mul failed, wanted", want, "got", got) - failed = true + t.Errorf("testLargeConst mul failed, wanted %d got %d", want, got) } } // testArithRshConst ensures that "const >> const" right shifts correctly perform // sign extension on the lhs constant -func testArithRshConst() { +func testArithRshConst(t *testing.T) { wantu := uint64(0x4000000000000000) if got := arithRshuConst_ssa(); got != wantu { - println("arithRshuConst failed, wanted", wantu, "got", got) - failed = true + t.Errorf("arithRshuConst failed, wanted %d got %d", wantu, got) } wants := int64(-0x4000000000000000) if got := arithRshConst_ssa(); got != wants { - println("arithRshuConst failed, wanted", wants, "got", got) - failed = true + t.Errorf("arithRshConst failed, wanted %d got %d", wants, got) } } @@ -222,16 +203,14 @@ func arithConstShift_ssa(x int64) int64 { // testArithConstShift tests that right shift by large constants preserve // the sign of the input. -func testArithConstShift() { +func testArithConstShift(t *testing.T) { want := int64(-1) if got := arithConstShift_ssa(-1); want != got { - println("arithConstShift_ssa(-1) failed, wanted", want, "got", got) - failed = true + t.Errorf("arithConstShift_ssa(-1) failed, wanted %d got %d", want, got) } want = 0 if got := arithConstShift_ssa(1); want != got { - println("arithConstShift_ssa(1) failed, wanted", want, "got", got) - failed = true + t.Errorf("arithConstShift_ssa(1) failed, wanted %d got %d", want, got) } } @@ -257,35 +236,34 @@ func overflowConstShift8_ssa(x int64) int8 { return int8(x) << uint8(0xff) << uint8(1) } -func testOverflowConstShift() { +func testOverflowConstShift(t *testing.T) { want := int64(0) for x := int64(-127); x < int64(127); x++ { got := overflowConstShift64_ssa(x) if want != got { - fmt.Printf("overflowShift64 failed, wanted %d got %d\n", want, got) + t.Errorf("overflowShift64 failed, wanted %d got %d", want, got) } got = int64(overflowConstShift32_ssa(x)) if want != got { - fmt.Printf("overflowShift32 failed, wanted %d got %d\n", want, got) + t.Errorf("overflowShift32 failed, wanted %d got %d", want, got) } got = int64(overflowConstShift16_ssa(x)) if want != got { - fmt.Printf("overflowShift16 failed, wanted %d got %d\n", want, got) + t.Errorf("overflowShift16 failed, wanted %d got %d", want, got) } got = int64(overflowConstShift8_ssa(x)) if want != got { - fmt.Printf("overflowShift8 failed, wanted %d got %d\n", want, got) + t.Errorf("overflowShift8 failed, wanted %d got %d", want, got) } } } // test64BitConstMult tests that rewrite rules don't fold 64 bit constants // into multiply instructions. -func test64BitConstMult() { +func test64BitConstMult(t *testing.T) { want := int64(103079215109) if got := test64BitConstMult_ssa(1, 2); want != got { - println("test64BitConstMult failed, wanted", want, "got", got) - failed = true + t.Errorf("test64BitConstMult failed, wanted %d got %d", want, got) } } @@ -296,11 +274,10 @@ func test64BitConstMult_ssa(a, b int64) int64 { // test64BitConstAdd tests that rewrite rules don't fold 64 bit constants // into add instructions. -func test64BitConstAdd() { +func test64BitConstAdd(t *testing.T) { want := int64(3567671782835376650) if got := test64BitConstAdd_ssa(1, 2); want != got { - println("test64BitConstAdd failed, wanted", want, "got", got) - failed = true + t.Errorf("test64BitConstAdd failed, wanted %d got %d", want, got) } } @@ -311,11 +288,10 @@ func test64BitConstAdd_ssa(a, b int64) int64 { // testRegallocCVSpill tests that regalloc spills a value whose last use is the // current value. -func testRegallocCVSpill() { +func testRegallocCVSpill(t *testing.T) { want := int8(-9) if got := testRegallocCVSpill_ssa(1, 2, 3, 4); want != got { - println("testRegallocCVSpill failed, wanted", want, "got", got) - failed = true + t.Errorf("testRegallocCVSpill failed, wanted %d got %d", want, got) } } @@ -324,55 +300,43 @@ func testRegallocCVSpill_ssa(a, b, c, d int8) int8 { return a + -32 + b + 63*c*-87*d } -func testBitwiseLogic() { +func testBitwiseLogic(t *testing.T) { a, b := uint32(57623283), uint32(1314713839) if want, got := uint32(38551779), testBitwiseAnd_ssa(a, b); want != got { - println("testBitwiseAnd failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseAnd failed, wanted %d got %d", want, got) } if want, got := uint32(1333785343), testBitwiseOr_ssa(a, b); want != got { - println("testBitwiseOr failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseOr failed, wanted %d got %d", want, got) } if want, got := uint32(1295233564), testBitwiseXor_ssa(a, b); want != got { - println("testBitwiseXor failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseXor failed, wanted %d got %d", want, got) } if want, got := int32(832), testBitwiseLsh_ssa(13, 4, 2); want != got { - println("testBitwiseLsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got) } if want, got := int32(0), testBitwiseLsh_ssa(13, 25, 15); want != got { - println("testBitwiseLsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got) } if want, got := int32(0), testBitwiseLsh_ssa(-13, 25, 15); want != got { - println("testBitwiseLsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseLsh failed, wanted %d got %d", want, got) } if want, got := int32(-13), testBitwiseRsh_ssa(-832, 4, 2); want != got { - println("testBitwiseRsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got) } if want, got := int32(0), testBitwiseRsh_ssa(13, 25, 15); want != got { - println("testBitwiseRsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got) } if want, got := int32(-1), testBitwiseRsh_ssa(-13, 25, 15); want != got { - println("testBitwiseRsh failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRsh failed, wanted %d got %d", want, got) } if want, got := uint32(0x3ffffff), testBitwiseRshU_ssa(0xffffffff, 4, 2); want != got { - println("testBitwiseRshU failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got) } if want, got := uint32(0), testBitwiseRshU_ssa(13, 25, 15); want != got { - println("testBitwiseRshU failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got) } if want, got := uint32(0), testBitwiseRshU_ssa(0x8aaaaaaa, 25, 15); want != got { - println("testBitwiseRshU failed, wanted", want, "got", got) - failed = true + t.Errorf("testBitwiseRshU failed, wanted %d got %d", want, got) } } @@ -419,20 +383,18 @@ func testShiftCX_ssa() int { return int(uint64(2*1)<<(3-2)<>v7)-2)&v11 | v11 - int(2)<<0>>(2-1)*(v11*0&v11<<1<<(uint8(2)+v4)) } -func testShiftCX() { +func testShiftCX(t *testing.T) { want := 141 if got := testShiftCX_ssa(); want != got { - println("testShiftCX failed, wanted", want, "got", got) - failed = true + t.Errorf("testShiftCX failed, wanted %d got %d", want, got) } } // testSubqToNegq ensures that the SUBQ -> NEGQ translation works correctly. -func testSubqToNegq() { +func testSubqToNegq(t *testing.T) { want := int64(-318294940372190156) if got := testSubqToNegq_ssa(1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2); want != got { - println("testSubqToNegq failed, wanted", want, "got", got) - failed = true + t.Errorf("testSubqToNegq failed, wanted %d got %d", want, got) } } @@ -441,12 +403,10 @@ func testSubqToNegq_ssa(a, b, c, d, e, f, g, h, i, j, k int64) int64 { return a + 8207351403619448057 - b - 1779494519303207690 + c*8810076340510052032*d - 4465874067674546219 - e*4361839741470334295 - f + 8688847565426072650*g*8065564729145417479 } -func testOcom() { +func testOcom(t *testing.T) { want1, want2 := int32(0x55555555), int32(-0x55555556) if got1, got2 := testOcom_ssa(0x55555555, 0x55555555); want1 != got1 || want2 != got2 { - println("testSubqToNegq failed, wanted", want1, "and", want2, - "got", got1, "and", got2) - failed = true + t.Errorf("testOcom failed, wanted %d and %d got %d and %d", want1, want2, got1, got2) } } @@ -479,27 +439,21 @@ func lrot3_ssa(w uint32) uint32 { return (w << 32) | (w >> (32 - 32)) } -func testLrot() { +func testLrot(t *testing.T) { wantA, wantB, wantC, wantD := uint8(0xe1), uint16(0xe001), uint32(0xe0000001), uint64(0xe000000000000001) a, b, c, d := lrot1_ssa(0xf, 0xf, 0xf, 0xf) if a != wantA || b != wantB || c != wantC || d != wantD { - println("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=", - wantA, wantB, wantC, wantD, ", got", a, b, c, d) - failed = true + t.Errorf("lrot1_ssa(0xf, 0xf, 0xf, 0xf)=%d %d %d %d, got %d %d %d %d", wantA, wantB, wantC, wantD, a, b, c, d) } x := lrot2_ssa(0xb0000001, 32) wantX := uint32(0xb0000001) if x != wantX { - println("lrot2_ssa(0xb0000001, 32)=", - wantX, ", got", x) - failed = true + t.Errorf("lrot2_ssa(0xb0000001, 32)=%d, got %d", wantX, x) } x = lrot3_ssa(0xb0000001) if x != wantX { - println("lrot3_ssa(0xb0000001)=", - wantX, ", got", x) - failed = true + t.Errorf("lrot3_ssa(0xb0000001)=%d, got %d", wantX, x) } } @@ -518,18 +472,16 @@ func sub2_ssa() uint8 { return v1 ^ v1*v1 - v3 } -func testSubConst() { +func testSubConst(t *testing.T) { x1 := sub1_ssa() want1 := uint64(6) if x1 != want1 { - println("sub1_ssa()=", want1, ", got", x1) - failed = true + t.Errorf("sub1_ssa()=%d, got %d", want1, x1) } x2 := sub2_ssa() want2 := uint8(251) if x2 != want2 { - println("sub2_ssa()=", want2, ", got", x2) - failed = true + t.Errorf("sub2_ssa()=%d, got %d", want2, x2) } } @@ -544,12 +496,12 @@ func orPhi_ssa(a bool, x int) int { return x | v } -func testOrPhi() { +func testOrPhi(t *testing.T) { if want, got := -1, orPhi_ssa(true, 4); got != want { - println("orPhi_ssa(true, 4)=", got, " want ", want) + t.Errorf("orPhi_ssa(true, 4)=%d, want %d", got, want) } if want, got := -1, orPhi_ssa(false, 0); got != want { - println("orPhi_ssa(false, 0)=", got, " want ", want) + t.Errorf("orPhi_ssa(false, 0)=%d, want %d", got, want) } } @@ -794,227 +746,173 @@ func notshiftRAreg_ssa(a int32, s uint8) int32 { } // test ARM shifted ops -func testShiftedOps() { +func testShiftedOps(t *testing.T) { a, b := uint32(10), uint32(42) if want, got := a+b<<3, addshiftLL_ssa(a, b); got != want { - println("addshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("addshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a-b<<3, subshiftLL_ssa(a, b); got != want { - println("subshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("subshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a<<3-b, rsbshiftLL_ssa(a, b); got != want { - println("rsbshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("rsbshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a&(b<<3), andshiftLL_ssa(a, b); got != want { - println("andshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("andshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a|b<<3, orshiftLL_ssa(a, b); got != want { - println("orshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("orshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a^b<<3, xorshiftLL_ssa(a, b); got != want { - println("xorshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("xorshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := a&^(b<<3), bicshiftLL_ssa(a, b); got != want { - println("bicshiftLL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("bicshiftLL_ssa(10, 42) = %d want %d", got, want) } if want, got := ^(a << 3), notshiftLL_ssa(a); got != want { - println("notshiftLL_ssa(10) =", got, " want ", want) - failed = true + t.Errorf("notshiftLL_ssa(10) = %d want %d", got, want) } if want, got := a+b>>3, addshiftRL_ssa(a, b); got != want { - println("addshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("addshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a-b>>3, subshiftRL_ssa(a, b); got != want { - println("subshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("subshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a>>3-b, rsbshiftRL_ssa(a, b); got != want { - println("rsbshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("rsbshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a&(b>>3), andshiftRL_ssa(a, b); got != want { - println("andshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("andshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a|b>>3, orshiftRL_ssa(a, b); got != want { - println("orshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("orshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a^b>>3, xorshiftRL_ssa(a, b); got != want { - println("xorshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("xorshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := a&^(b>>3), bicshiftRL_ssa(a, b); got != want { - println("bicshiftRL_ssa(10, 42) =", got, " want ", want) - failed = true + t.Errorf("bicshiftRL_ssa(10, 42) = %d want %d", got, want) } if want, got := ^(a >> 3), notshiftRL_ssa(a); got != want { - println("notshiftRL_ssa(10) =", got, " want ", want) - failed = true + t.Errorf("notshiftRL_ssa(10) = %d want %d", got, want) } c, d := int32(10), int32(-42) if want, got := c+d>>3, addshiftRA_ssa(c, d); got != want { - println("addshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("addshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c-d>>3, subshiftRA_ssa(c, d); got != want { - println("subshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("subshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c>>3-d, rsbshiftRA_ssa(c, d); got != want { - println("rsbshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("rsbshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c&(d>>3), andshiftRA_ssa(c, d); got != want { - println("andshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("andshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c|d>>3, orshiftRA_ssa(c, d); got != want { - println("orshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("orshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c^d>>3, xorshiftRA_ssa(c, d); got != want { - println("xorshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("xorshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := c&^(d>>3), bicshiftRA_ssa(c, d); got != want { - println("bicshiftRA_ssa(10, -42) =", got, " want ", want) - failed = true + t.Errorf("bicshiftRA_ssa(10, -42) = %d want %d", got, want) } if want, got := ^(d >> 3), notshiftRA_ssa(d); got != want { - println("notshiftRA_ssa(-42) =", got, " want ", want) - failed = true + t.Errorf("notshiftRA_ssa(-42) = %d want %d", got, want) } s := uint8(3) if want, got := a+b<>s, addshiftRLreg_ssa(a, b, s); got != want { - println("addshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("addshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a-b>>s, subshiftRLreg_ssa(a, b, s); got != want { - println("subshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("subshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a>>s-b, rsbshiftRLreg_ssa(a, b, s); got != want { - println("rsbshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("rsbshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a&(b>>s), andshiftRLreg_ssa(a, b, s); got != want { - println("andshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("andshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a|b>>s, orshiftRLreg_ssa(a, b, s); got != want { - println("orshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("orshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a^b>>s, xorshiftRLreg_ssa(a, b, s); got != want { - println("xorshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("xorshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := a&^(b>>s), bicshiftRLreg_ssa(a, b, s); got != want { - println("bicshiftRLreg_ssa(10, 42, 3) =", got, " want ", want) - failed = true + t.Errorf("bicshiftRLreg_ssa(10, 42, 3) = %d want %d", got, want) } if want, got := ^(a >> s), notshiftRLreg_ssa(a, s); got != want { - println("notshiftRLreg_ssa(10) =", got, " want ", want) - failed = true + t.Errorf("notshiftRLreg_ssa(10) = %d want %d", got, want) } if want, got := c+d>>s, addshiftRAreg_ssa(c, d, s); got != want { - println("addshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("addshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c-d>>s, subshiftRAreg_ssa(c, d, s); got != want { - println("subshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("subshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c>>s-d, rsbshiftRAreg_ssa(c, d, s); got != want { - println("rsbshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("rsbshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c&(d>>s), andshiftRAreg_ssa(c, d, s); got != want { - println("andshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("andshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c|d>>s, orshiftRAreg_ssa(c, d, s); got != want { - println("orshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("orshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c^d>>s, xorshiftRAreg_ssa(c, d, s); got != want { - println("xorshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("xorshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := c&^(d>>s), bicshiftRAreg_ssa(c, d, s); got != want { - println("bicshiftRAreg_ssa(10, -42, 3) =", got, " want ", want) - failed = true + t.Errorf("bicshiftRAreg_ssa(10, -42, 3) = %d want %d", got, want) } if want, got := ^(d >> s), notshiftRAreg_ssa(d, s); got != want { - println("notshiftRAreg_ssa(-42, 3) =", got, " want ", want) - failed = true + t.Errorf("notshiftRAreg_ssa(-42, 3) = %d want %d", got, want) } } -var failed = false - -func main() { - - test64BitConstMult() - test64BitConstAdd() - testRegallocCVSpill() - testSubqToNegq() - testBitwiseLogic() - testOcom() - testLrot() - testShiftCX() - testSubConst() - testOverflowConstShift() - testArithConstShift() - testArithRshConst() - testLargeConst() - testLoadCombine() - testLoadSymCombine() - testShiftRemoval() - testShiftedOps() - - if failed { - panic("failed") - } +// TestArithmetic tests that both backends have the same result for arithmetic expressions. +func TestArithmetic(t *testing.T) { + test64BitConstMult(t) + test64BitConstAdd(t) + testRegallocCVSpill(t) + testSubqToNegq(t) + testBitwiseLogic(t) + testOcom(t) + testLrot(t) + testShiftCX(t) + testSubConst(t) + testOverflowConstShift(t) + testArithConstShift(t) + testArithRshConst(t) + testLargeConst(t) + testLoadCombine(t) + testLoadSymCombine(t) + testShiftRemoval(t) + testShiftedOps(t) } diff --git a/src/cmd/compile/internal/gc/testdata/array.go b/src/cmd/compile/internal/gc/testdata/array_test.go similarity index 62% rename from src/cmd/compile/internal/gc/testdata/array.go rename to src/cmd/compile/internal/gc/testdata/array_test.go index 6be8d9155b..efa00d0520 100644 --- a/src/cmd/compile/internal/gc/testdata/array.go +++ b/src/cmd/compile/internal/gc/testdata/array_test.go @@ -1,6 +1,6 @@ package main -var failed = false +import "testing" //go:noinline func testSliceLenCap12_ssa(a [10]int, i, j int) (int, int) { @@ -20,7 +20,7 @@ func testSliceLenCap2_ssa(a [10]int, i, j int) (int, int) { return len(b), cap(b) } -func testSliceLenCap() { +func testSliceLenCap(t *testing.T) { a := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} tests := [...]struct { fn func(a [10]int, i, j int) (int, int) @@ -43,11 +43,9 @@ func testSliceLenCap() { {testSliceLenCap2_ssa, -1, 10, 10, 10}, } - for i, t := range tests { - if l, c := t.fn(a, t.i, t.j); l != t.l && c != t.c { - println("#", i, " len(a[", t.i, ":", t.j, "]), cap(a[", t.i, ":", t.j, "]) =", l, c, - ", want", t.l, t.c) - failed = true + for i, test := range tests { + if l, c := test.fn(a, test.i, test.j); l != test.l && c != test.c { + t.Errorf("#%d len(a[%d:%d]), cap(a[%d:%d]) = %d %d, want %d %d", i, test.i, test.j, test.i, test.j, l, c, test.l, test.c) } } } @@ -57,7 +55,7 @@ func testSliceGetElement_ssa(a [10]int, i, j, p int) int { return a[i:j][p] } -func testSliceGetElement() { +func testSliceGetElement(t *testing.T) { a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90} tests := [...]struct { i, j, p int @@ -69,10 +67,9 @@ func testSliceGetElement() { {1, 9, 7, 80}, } - for i, t := range tests { - if got := testSliceGetElement_ssa(a, t.i, t.j, t.p); got != t.want { - println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want) - failed = true + for i, test := range tests { + if got := testSliceGetElement_ssa(a, test.i, test.j, test.p); got != test.want { + t.Errorf("#%d a[%d:%d][%d] = %d, wanted %d", i, test.i, test.j, test.p, got, test.want) } } } @@ -82,7 +79,7 @@ func testSliceSetElement_ssa(a *[10]int, i, j, p, x int) { (*a)[i:j][p] = x } -func testSliceSetElement() { +func testSliceSetElement(t *testing.T) { a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90} tests := [...]struct { i, j, p int @@ -94,49 +91,42 @@ func testSliceSetElement() { {1, 9, 7, 99}, } - for i, t := range tests { - testSliceSetElement_ssa(&a, t.i, t.j, t.p, t.want) - if got := a[t.i+t.p]; got != t.want { - println("#", i, " a[", t.i, ":", t.j, "][", t.p, "] = ", got, " wanted ", t.want) - failed = true + for i, test := range tests { + testSliceSetElement_ssa(&a, test.i, test.j, test.p, test.want) + if got := a[test.i+test.p]; got != test.want { + t.Errorf("#%d a[%d:%d][%d] = %d, wanted %d", i, test.i, test.j, test.p, got, test.want) } } } -func testSlicePanic1() { +func testSlicePanic1(t *testing.T) { defer func() { if r := recover(); r != nil { - println("panicked as expected") + //println("panicked as expected") } }() a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90} testSliceLenCap12_ssa(a, 3, 12) - println("expected to panic, but didn't") - failed = true + t.Errorf("expected to panic, but didn't") } -func testSlicePanic2() { +func testSlicePanic2(t *testing.T) { defer func() { if r := recover(); r != nil { - println("panicked as expected") + //println("panicked as expected") } }() a := [10]int{0, 10, 20, 30, 40, 50, 60, 70, 80, 90} testSliceGetElement_ssa(a, 3, 7, 4) - println("expected to panic, but didn't") - failed = true + t.Errorf("expected to panic, but didn't") } -func main() { - testSliceLenCap() - testSliceGetElement() - testSliceSetElement() - testSlicePanic1() - testSlicePanic2() - - if failed { - panic("failed") - } +func TestArray(t *testing.T) { + testSliceLenCap(t) + testSliceGetElement(t) + testSliceSetElement(t) + testSlicePanic1(t) + testSlicePanic2(t) } diff --git a/src/cmd/compile/internal/gc/testdata/assert.go b/src/cmd/compile/internal/gc/testdata/assert.go deleted file mode 100644 index d64d4fc35a..0000000000 --- a/src/cmd/compile/internal/gc/testdata/assert.go +++ /dev/null @@ -1,147 +0,0 @@ -// run - -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Tests type assertion expressions and statements - -package main - -import ( - "fmt" - "runtime" -) - -type ( - S struct{} - T struct{} - - I interface { - F() - } -) - -var ( - s *S - t *T -) - -func (s *S) F() {} -func (t *T) F() {} - -func e2t_ssa(e interface{}) *T { - return e.(*T) -} - -func i2t_ssa(i I) *T { - return i.(*T) -} - -func testAssertE2TOk() { - if got := e2t_ssa(t); got != t { - fmt.Printf("e2t_ssa(t)=%v want %v", got, t) - failed = true - } -} - -func testAssertE2TPanic() { - var got *T - defer func() { - if got != nil { - fmt.Printf("e2t_ssa(s)=%v want nil", got) - failed = true - } - e := recover() - err, ok := e.(*runtime.TypeAssertionError) - if !ok { - fmt.Printf("e2t_ssa(s) panic type %T", e) - failed = true - } - want := "interface conversion: interface {} is *main.S, not *main.T" - if err.Error() != want { - fmt.Printf("e2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error()) - failed = true - } - }() - got = e2t_ssa(s) - fmt.Printf("e2t_ssa(s) should panic") - failed = true -} - -func testAssertI2TOk() { - if got := i2t_ssa(t); got != t { - fmt.Printf("i2t_ssa(t)=%v want %v", got, t) - failed = true - } -} - -func testAssertI2TPanic() { - var got *T - defer func() { - if got != nil { - fmt.Printf("i2t_ssa(s)=%v want nil", got) - failed = true - } - e := recover() - err, ok := e.(*runtime.TypeAssertionError) - if !ok { - fmt.Printf("i2t_ssa(s) panic type %T", e) - failed = true - } - want := "interface conversion: main.I is *main.S, not *main.T" - if err.Error() != want { - fmt.Printf("i2t_ssa(s) wrong error, want '%s', got '%s'\n", want, err.Error()) - failed = true - } - }() - got = i2t_ssa(s) - fmt.Printf("i2t_ssa(s) should panic") - failed = true -} - -func e2t2_ssa(e interface{}) (*T, bool) { - t, ok := e.(*T) - return t, ok -} - -func i2t2_ssa(i I) (*T, bool) { - t, ok := i.(*T) - return t, ok -} - -func testAssertE2T2() { - if got, ok := e2t2_ssa(t); !ok || got != t { - fmt.Printf("e2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true) - failed = true - } - if got, ok := e2t2_ssa(s); ok || got != nil { - fmt.Printf("e2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false) - failed = true - } -} - -func testAssertI2T2() { - if got, ok := i2t2_ssa(t); !ok || got != t { - fmt.Printf("i2t2_ssa(t)=(%v, %v) want (%v, %v)", got, ok, t, true) - failed = true - } - if got, ok := i2t2_ssa(s); ok || got != nil { - fmt.Printf("i2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false) - failed = true - } -} - -var failed = false - -func main() { - testAssertE2TOk() - testAssertE2TPanic() - testAssertI2TOk() - testAssertI2TPanic() - testAssertE2T2() - testAssertI2T2() - if failed { - panic("failed") - } -} diff --git a/src/cmd/compile/internal/gc/testdata/assert_test.go b/src/cmd/compile/internal/gc/testdata/assert_test.go new file mode 100644 index 0000000000..4326be8079 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/assert_test.go @@ -0,0 +1,128 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Tests type assertion expressions and statements + +package main + +import ( + "runtime" + "testing" +) + +type ( + S struct{} + U struct{} + + I interface { + F() + } +) + +var ( + s *S + u *U +) + +func (s *S) F() {} +func (u *U) F() {} + +func e2t_ssa(e interface{}) *U { + return e.(*U) +} + +func i2t_ssa(i I) *U { + return i.(*U) +} + +func testAssertE2TOk(t *testing.T) { + if got := e2t_ssa(u); got != u { + t.Errorf("e2t_ssa(u)=%v want %v", got, u) + } +} + +func testAssertE2TPanic(t *testing.T) { + var got *U + defer func() { + if got != nil { + t.Errorf("e2t_ssa(s)=%v want nil", got) + } + e := recover() + err, ok := e.(*runtime.TypeAssertionError) + if !ok { + t.Errorf("e2t_ssa(s) panic type %T", e) + } + want := "interface conversion: interface {} is *main.S, not *main.U" + if err.Error() != want { + t.Errorf("e2t_ssa(s) wrong error, want '%s', got '%s'", want, err.Error()) + } + }() + got = e2t_ssa(s) + t.Errorf("e2t_ssa(s) should panic") + +} + +func testAssertI2TOk(t *testing.T) { + if got := i2t_ssa(u); got != u { + t.Errorf("i2t_ssa(u)=%v want %v", got, u) + } +} + +func testAssertI2TPanic(t *testing.T) { + var got *U + defer func() { + if got != nil { + t.Errorf("i2t_ssa(s)=%v want nil", got) + } + e := recover() + err, ok := e.(*runtime.TypeAssertionError) + if !ok { + t.Errorf("i2t_ssa(s) panic type %T", e) + } + want := "interface conversion: main.I is *main.S, not *main.U" + if err.Error() != want { + t.Errorf("i2t_ssa(s) wrong error, want '%s', got '%s'", want, err.Error()) + } + }() + got = i2t_ssa(s) + t.Errorf("i2t_ssa(s) should panic") +} + +func e2t2_ssa(e interface{}) (*U, bool) { + u, ok := e.(*U) + return u, ok +} + +func i2t2_ssa(i I) (*U, bool) { + u, ok := i.(*U) + return u, ok +} + +func testAssertE2T2(t *testing.T) { + if got, ok := e2t2_ssa(u); !ok || got != u { + t.Errorf("e2t2_ssa(u)=(%v, %v) want (%v, %v)", got, ok, u, true) + } + if got, ok := e2t2_ssa(s); ok || got != nil { + t.Errorf("e2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false) + } +} + +func testAssertI2T2(t *testing.T) { + if got, ok := i2t2_ssa(u); !ok || got != u { + t.Errorf("i2t2_ssa(u)=(%v, %v) want (%v, %v)", got, ok, u, true) + } + if got, ok := i2t2_ssa(s); ok || got != nil { + t.Errorf("i2t2_ssa(s)=(%v, %v) want (%v, %v)", got, ok, nil, false) + } +} + +// TestTypeAssertion tests type assertions. +func TestTypeAssertion(t *testing.T) { + testAssertE2TOk(t) + testAssertE2TPanic(t) + testAssertI2TOk(t) + testAssertI2TPanic(t) + testAssertE2T2(t) + testAssertI2T2(t) +} diff --git a/src/cmd/compile/internal/gc/testdata/break.go b/src/cmd/compile/internal/gc/testdata/break_test.go similarity index 93% rename from src/cmd/compile/internal/gc/testdata/break.go rename to src/cmd/compile/internal/gc/testdata/break_test.go index 855ef70049..50245dfd31 100644 --- a/src/cmd/compile/internal/gc/testdata/break.go +++ b/src/cmd/compile/internal/gc/testdata/break_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,6 +6,8 @@ package main +import "testing" + func continuePlain_ssa() int { var n int for i := 0; i < 10; i++ { @@ -214,7 +214,8 @@ Done: return n } -func main() { +// TestBreakContinue tests that continue and break statements do what they say. +func TestBreakContinue(t *testing.T) { tests := [...]struct { name string fn func() int @@ -241,15 +242,9 @@ func main() { // no select tests; they're identical to switch } - var failed bool for _, test := range tests { - if got := test.fn(); test.fn() != test.want { - print(test.name, "()=", got, ", want ", test.want, "\n") - failed = true + if got := test.fn(); got != test.want { + t.Errorf("%s()=%d, want %d", test.name, got, test.want) } } - - if failed { - panic("failed") - } } diff --git a/src/cmd/compile/internal/gc/testdata/chan.go b/src/cmd/compile/internal/gc/testdata/chan_test.go similarity index 53% rename from src/cmd/compile/internal/gc/testdata/chan.go rename to src/cmd/compile/internal/gc/testdata/chan_test.go index 0766fcda5b..628bd8f7f7 100644 --- a/src/cmd/compile/internal/gc/testdata/chan.go +++ b/src/cmd/compile/internal/gc/testdata/chan_test.go @@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// chan_ssa.go tests chan operations. +// chan.go tests chan operations. package main -import "fmt" - -var failed = false +import "testing" //go:noinline func lenChan_ssa(v chan int) int { @@ -19,7 +17,7 @@ func capChan_ssa(v chan int) int { return cap(v) } -func testLenChan() { +func testLenChan(t *testing.T) { v := make(chan int, 10) v <- 1 @@ -27,47 +25,39 @@ func testLenChan() { v <- 1 if want, got := 3, lenChan_ssa(v); got != want { - fmt.Printf("expected len(chan) = %d, got %d", want, got) - failed = true + t.Errorf("expected len(chan) = %d, got %d", want, got) } } -func testLenNilChan() { +func testLenNilChan(t *testing.T) { var v chan int if want, got := 0, lenChan_ssa(v); got != want { - fmt.Printf("expected len(nil) = %d, got %d", want, got) - failed = true + t.Errorf("expected len(nil) = %d, got %d", want, got) } } -func testCapChan() { +func testCapChan(t *testing.T) { v := make(chan int, 25) if want, got := 25, capChan_ssa(v); got != want { - fmt.Printf("expected cap(chan) = %d, got %d", want, got) - failed = true + t.Errorf("expected cap(chan) = %d, got %d", want, got) } } -func testCapNilChan() { +func testCapNilChan(t *testing.T) { var v chan int if want, got := 0, capChan_ssa(v); got != want { - fmt.Printf("expected cap(nil) = %d, got %d", want, got) - failed = true + t.Errorf("expected cap(nil) = %d, got %d", want, got) } } -func main() { - testLenChan() - testLenNilChan() +func TestChan(t *testing.T) { + testLenChan(t) + testLenNilChan(t) - testCapChan() - testCapNilChan() - - if failed { - panic("failed") - } + testCapChan(t) + testCapNilChan(t) } diff --git a/src/cmd/compile/internal/gc/testdata/closure.go b/src/cmd/compile/internal/gc/testdata/closure_test.go similarity index 60% rename from src/cmd/compile/internal/gc/testdata/closure.go rename to src/cmd/compile/internal/gc/testdata/closure_test.go index 70181bc24b..6cddc2d167 100644 --- a/src/cmd/compile/internal/gc/testdata/closure.go +++ b/src/cmd/compile/internal/gc/testdata/closure_test.go @@ -2,12 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// map_ssa.go tests map operations. +// closure.go tests closure operations. package main -import "fmt" - -var failed = false +import "testing" //go:noinline func testCFunc_ssa() int { @@ -22,17 +20,13 @@ func testCFunc_ssa() int { return a } -func testCFunc() { +func testCFunc(t *testing.T) { if want, got := 2, testCFunc_ssa(); got != want { - fmt.Printf("expected %d, got %d", want, got) - failed = true + t.Errorf("expected %d, got %d", want, got) } } -func main() { - testCFunc() - - if failed { - panic("failed") - } +// TestClosure tests closure related behavior. +func TestClosure(t *testing.T) { + testCFunc(t) } diff --git a/src/cmd/compile/internal/gc/testdata/cmpConst.go b/src/cmd/compile/internal/gc/testdata/cmpConst_test.go similarity index 99% rename from src/cmd/compile/internal/gc/testdata/cmpConst.go rename to src/cmd/compile/internal/gc/testdata/cmpConst_test.go index f7067bea2a..9400ef40ae 100644 --- a/src/cmd/compile/internal/gc/testdata/cmpConst.go +++ b/src/cmd/compile/internal/gc/testdata/cmpConst_test.go @@ -1,12 +1,11 @@ -// run // Code generated by gen/cmpConstGen.go. DO NOT EDIT. package main import ( - "fmt" "reflect" "runtime" + "testing" ) // results show the expected result for the elements left of, equal to and right of the index. @@ -2093,7 +2092,8 @@ var int8_tests = []struct { {idx: 6, exp: ne, fn: ne_127_int8}, } -func main() { +// TestComparisonsConst tests results for comparison operations against constants. +func TestComparisonsConst(t *testing.T) { for i, test := range uint64_tests { for j, x := range uint64_vals { want := test.exp.l @@ -2104,8 +2104,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=uint64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=uint64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2119,8 +2118,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=uint32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=uint32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2134,8 +2132,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=uint16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=uint16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2149,8 +2146,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=uint8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=uint8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2164,8 +2160,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=int64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=int64 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2179,8 +2174,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=int32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=int32 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2194,8 +2188,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=int16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=int16 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } @@ -2209,8 +2202,7 @@ func main() { } if test.fn(x) != want { fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name() - msg := fmt.Sprintf("test failed: %v(%v) != %v [type=int8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) - panic(msg) + t.Errorf("test failed: %v(%v) != %v [type=int8 i=%v j=%v idx=%v]", fn, x, want, i, j, test.idx) } } } diff --git a/src/cmd/compile/internal/gc/testdata/cmp.go b/src/cmd/compile/internal/gc/testdata/cmp_test.go similarity index 58% rename from src/cmd/compile/internal/gc/testdata/cmp.go rename to src/cmd/compile/internal/gc/testdata/cmp_test.go index ba420f2e4e..06b58f2a02 100644 --- a/src/cmd/compile/internal/gc/testdata/cmp.go +++ b/src/cmd/compile/internal/gc/testdata/cmp_test.go @@ -5,9 +5,7 @@ // cmp_ssa.go tests compare simplification operations. package main -import "fmt" - -var failed = false +import "testing" //go:noinline func eq_ssa(a int64) bool { @@ -19,30 +17,21 @@ func neq_ssa(a int64) bool { return 10 != a+4 } -func testCmp() { +func testCmp(t *testing.T) { if wanted, got := true, eq_ssa(6); wanted != got { - fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got) - failed = true + t.Errorf("eq_ssa: expected %v, got %v\n", wanted, got) } if wanted, got := false, eq_ssa(7); wanted != got { - fmt.Printf("eq_ssa: expected %v, got %v\n", wanted, got) - failed = true + t.Errorf("eq_ssa: expected %v, got %v\n", wanted, got) } - if wanted, got := false, neq_ssa(6); wanted != got { - fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got) - failed = true + t.Errorf("neq_ssa: expected %v, got %v\n", wanted, got) } if wanted, got := true, neq_ssa(7); wanted != got { - fmt.Printf("neq_ssa: expected %v, got %v\n", wanted, got) - failed = true + t.Errorf("neq_ssa: expected %v, got %v\n", wanted, got) } } -func main() { - testCmp() - - if failed { - panic("failed") - } +func TestCmp(t *testing.T) { + testCmp(t) } diff --git a/src/cmd/compile/internal/gc/testdata/compound.go b/src/cmd/compile/internal/gc/testdata/compound_test.go similarity index 59% rename from src/cmd/compile/internal/gc/testdata/compound.go rename to src/cmd/compile/internal/gc/testdata/compound_test.go index de10cdc779..4ae464dbe3 100644 --- a/src/cmd/compile/internal/gc/testdata/compound.go +++ b/src/cmd/compile/internal/gc/testdata/compound_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,7 +6,9 @@ package main -import "fmt" +import ( + "testing" +) func string_ssa(a, b string, x bool) string { s := "" @@ -20,16 +20,14 @@ func string_ssa(a, b string, x bool) string { return s } -func testString() { +func testString(t *testing.T) { a := "foo" b := "barz" if want, got := a, string_ssa(a, b, true); got != want { - fmt.Printf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } if want, got := b, string_ssa(a, b, false); got != want { - fmt.Printf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) } } @@ -55,31 +53,27 @@ func complex128_ssa(a, b complex128, x bool) complex128 { return c } -func testComplex64() { +func testComplex64(t *testing.T) { var a complex64 = 1 + 2i var b complex64 = 3 + 4i if want, got := a, complex64_ssa(a, b, true); got != want { - fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } if want, got := b, complex64_ssa(a, b, false); got != want { - fmt.Printf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("complex64_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } } -func testComplex128() { +func testComplex128(t *testing.T) { var a complex128 = 1 + 2i var b complex128 = 3 + 4i if want, got := a, complex128_ssa(a, b, true); got != want { - fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } if want, got := b, complex128_ssa(a, b, false); got != want { - fmt.Printf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("complex128_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } } @@ -93,16 +87,14 @@ func slice_ssa(a, b []byte, x bool) []byte { return s } -func testSlice() { +func testSlice(t *testing.T) { a := []byte{3, 4, 5} b := []byte{7, 8, 9} if want, got := byte(3), slice_ssa(a, b, true)[0]; got != want { - fmt.Printf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } if want, got := byte(7), slice_ssa(a, b, false)[0]; got != want { - fmt.Printf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) } } @@ -116,28 +108,21 @@ func interface_ssa(a, b interface{}, x bool) interface{} { return s } -func testInterface() { +func testInterface(t *testing.T) { a := interface{}(3) b := interface{}(4) if want, got := 3, interface_ssa(a, b, true).(int); got != want { - fmt.Printf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want) } if want, got := 4, interface_ssa(a, b, false).(int); got != want { - fmt.Printf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) - failed = true + t.Errorf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want) } } -var failed = false - -func main() { - testString() - testSlice() - testInterface() - testComplex64() - testComplex128() - if failed { - panic("failed") - } +func TestCompound(t *testing.T) { + testString(t) + testSlice(t) + testInterface(t) + testComplex64(t) + testComplex128(t) } diff --git a/src/cmd/compile/internal/gc/testdata/copy.go b/src/cmd/compile/internal/gc/testdata/copy_test.go similarity index 97% rename from src/cmd/compile/internal/gc/testdata/copy.go rename to src/cmd/compile/internal/gc/testdata/copy_test.go index d8bb26634e..c29611d32a 100644 --- a/src/cmd/compile/internal/gc/testdata/copy.go +++ b/src/cmd/compile/internal/gc/testdata/copy_test.go @@ -1,9 +1,8 @@ -// run // Code generated by gen/copyGen.go. DO NOT EDIT. package main -import "fmt" +import "testing" type T1 struct { pre [8]byte @@ -15,14 +14,13 @@ type T1 struct { func t1copy_ssa(y, x *[1]byte) { *y = *x } -func testCopy1() { +func testCopy1(t *testing.T) { a := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{0}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1]byte{100} t1copy_ssa(&a.mid, &x) want := T1{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1]byte{100}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1copy got=%v, want %v\n", a, want) } } @@ -36,14 +34,13 @@ type T2 struct { func t2copy_ssa(y, x *[2]byte) { *y = *x } -func testCopy2() { +func testCopy2(t *testing.T) { a := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{0, 1}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [2]byte{100, 101} t2copy_ssa(&a.mid, &x) want := T2{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [2]byte{100, 101}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t2copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t2copy got=%v, want %v\n", a, want) } } @@ -57,14 +54,13 @@ type T3 struct { func t3copy_ssa(y, x *[3]byte) { *y = *x } -func testCopy3() { +func testCopy3(t *testing.T) { a := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{0, 1, 2}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [3]byte{100, 101, 102} t3copy_ssa(&a.mid, &x) want := T3{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [3]byte{100, 101, 102}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t3copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t3copy got=%v, want %v\n", a, want) } } @@ -78,14 +74,13 @@ type T4 struct { func t4copy_ssa(y, x *[4]byte) { *y = *x } -func testCopy4() { +func testCopy4(t *testing.T) { a := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{0, 1, 2, 3}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [4]byte{100, 101, 102, 103} t4copy_ssa(&a.mid, &x) want := T4{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [4]byte{100, 101, 102, 103}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t4copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t4copy got=%v, want %v\n", a, want) } } @@ -99,14 +94,13 @@ type T5 struct { func t5copy_ssa(y, x *[5]byte) { *y = *x } -func testCopy5() { +func testCopy5(t *testing.T) { a := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{0, 1, 2, 3, 4}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [5]byte{100, 101, 102, 103, 104} t5copy_ssa(&a.mid, &x) want := T5{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [5]byte{100, 101, 102, 103, 104}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t5copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t5copy got=%v, want %v\n", a, want) } } @@ -120,14 +114,13 @@ type T6 struct { func t6copy_ssa(y, x *[6]byte) { *y = *x } -func testCopy6() { +func testCopy6(t *testing.T) { a := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{0, 1, 2, 3, 4, 5}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [6]byte{100, 101, 102, 103, 104, 105} t6copy_ssa(&a.mid, &x) want := T6{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [6]byte{100, 101, 102, 103, 104, 105}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t6copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t6copy got=%v, want %v\n", a, want) } } @@ -141,14 +134,13 @@ type T7 struct { func t7copy_ssa(y, x *[7]byte) { *y = *x } -func testCopy7() { +func testCopy7(t *testing.T) { a := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{0, 1, 2, 3, 4, 5, 6}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [7]byte{100, 101, 102, 103, 104, 105, 106} t7copy_ssa(&a.mid, &x) want := T7{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [7]byte{100, 101, 102, 103, 104, 105, 106}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t7copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t7copy got=%v, want %v\n", a, want) } } @@ -162,14 +154,13 @@ type T8 struct { func t8copy_ssa(y, x *[8]byte) { *y = *x } -func testCopy8() { +func testCopy8(t *testing.T) { a := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{0, 1, 2, 3, 4, 5, 6, 7}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [8]byte{100, 101, 102, 103, 104, 105, 106, 107} t8copy_ssa(&a.mid, &x) want := T8{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [8]byte{100, 101, 102, 103, 104, 105, 106, 107}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t8copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t8copy got=%v, want %v\n", a, want) } } @@ -183,14 +174,13 @@ type T9 struct { func t9copy_ssa(y, x *[9]byte) { *y = *x } -func testCopy9() { +func testCopy9(t *testing.T) { a := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{0, 1, 2, 3, 4, 5, 6, 7, 8}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108} t9copy_ssa(&a.mid, &x) want := T9{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [9]byte{100, 101, 102, 103, 104, 105, 106, 107, 108}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t9copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t9copy got=%v, want %v\n", a, want) } } @@ -204,14 +194,13 @@ type T10 struct { func t10copy_ssa(y, x *[10]byte) { *y = *x } -func testCopy10() { +func testCopy10(t *testing.T) { a := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109} t10copy_ssa(&a.mid, &x) want := T10{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [10]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t10copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t10copy got=%v, want %v\n", a, want) } } @@ -225,14 +214,13 @@ type T15 struct { func t15copy_ssa(y, x *[15]byte) { *y = *x } -func testCopy15() { +func testCopy15(t *testing.T) { a := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114} t15copy_ssa(&a.mid, &x) want := T15{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [15]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t15copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t15copy got=%v, want %v\n", a, want) } } @@ -246,14 +234,13 @@ type T16 struct { func t16copy_ssa(y, x *[16]byte) { *y = *x } -func testCopy16() { +func testCopy16(t *testing.T) { a := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115} t16copy_ssa(&a.mid, &x) want := T16{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [16]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t16copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t16copy got=%v, want %v\n", a, want) } } @@ -267,14 +254,13 @@ type T17 struct { func t17copy_ssa(y, x *[17]byte) { *y = *x } -func testCopy17() { +func testCopy17(t *testing.T) { a := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116} t17copy_ssa(&a.mid, &x) want := T17{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [17]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t17copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t17copy got=%v, want %v\n", a, want) } } @@ -288,14 +274,13 @@ type T23 struct { func t23copy_ssa(y, x *[23]byte) { *y = *x } -func testCopy23() { +func testCopy23(t *testing.T) { a := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122} t23copy_ssa(&a.mid, &x) want := T23{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [23]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t23copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t23copy got=%v, want %v\n", a, want) } } @@ -309,14 +294,13 @@ type T24 struct { func t24copy_ssa(y, x *[24]byte) { *y = *x } -func testCopy24() { +func testCopy24(t *testing.T) { a := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123} t24copy_ssa(&a.mid, &x) want := T24{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [24]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t24copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t24copy got=%v, want %v\n", a, want) } } @@ -330,14 +314,13 @@ type T25 struct { func t25copy_ssa(y, x *[25]byte) { *y = *x } -func testCopy25() { +func testCopy25(t *testing.T) { a := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124} t25copy_ssa(&a.mid, &x) want := T25{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [25]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t25copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t25copy got=%v, want %v\n", a, want) } } @@ -351,14 +334,13 @@ type T31 struct { func t31copy_ssa(y, x *[31]byte) { *y = *x } -func testCopy31() { +func testCopy31(t *testing.T) { a := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130} t31copy_ssa(&a.mid, &x) want := T31{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [31]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t31copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t31copy got=%v, want %v\n", a, want) } } @@ -372,14 +354,13 @@ type T32 struct { func t32copy_ssa(y, x *[32]byte) { *y = *x } -func testCopy32() { +func testCopy32(t *testing.T) { a := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131} t32copy_ssa(&a.mid, &x) want := T32{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [32]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t32copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t32copy got=%v, want %v\n", a, want) } } @@ -393,14 +374,13 @@ type T33 struct { func t33copy_ssa(y, x *[33]byte) { *y = *x } -func testCopy33() { +func testCopy33(t *testing.T) { a := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132} t33copy_ssa(&a.mid, &x) want := T33{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [33]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t33copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t33copy got=%v, want %v\n", a, want) } } @@ -414,14 +394,13 @@ type T63 struct { func t63copy_ssa(y, x *[63]byte) { *y = *x } -func testCopy63() { +func testCopy63(t *testing.T) { a := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162} t63copy_ssa(&a.mid, &x) want := T63{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [63]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t63copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t63copy got=%v, want %v\n", a, want) } } @@ -435,14 +414,13 @@ type T64 struct { func t64copy_ssa(y, x *[64]byte) { *y = *x } -func testCopy64() { +func testCopy64(t *testing.T) { a := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163} t64copy_ssa(&a.mid, &x) want := T64{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [64]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t64copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t64copy got=%v, want %v\n", a, want) } } @@ -456,14 +434,13 @@ type T65 struct { func t65copy_ssa(y, x *[65]byte) { *y = *x } -func testCopy65() { +func testCopy65(t *testing.T) { a := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164} t65copy_ssa(&a.mid, &x) want := T65{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [65]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t65copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t65copy got=%v, want %v\n", a, want) } } @@ -477,14 +454,13 @@ type T1023 struct { func t1023copy_ssa(y, x *[1023]byte) { *y = *x } -func testCopy1023() { +func testCopy1023(t *testing.T) { a := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122} t1023copy_ssa(&a.mid, &x) want := T1023{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1023]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1023copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1023copy got=%v, want %v\n", a, want) } } @@ -498,14 +474,13 @@ type T1024 struct { func t1024copy_ssa(y, x *[1024]byte) { *y = *x } -func testCopy1024() { +func testCopy1024(t *testing.T) { a := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123} t1024copy_ssa(&a.mid, &x) want := T1024{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1024]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1024copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1024copy got=%v, want %v\n", a, want) } } @@ -519,14 +494,13 @@ type T1025 struct { func t1025copy_ssa(y, x *[1025]byte) { *y = *x } -func testCopy1025() { +func testCopy1025(t *testing.T) { a := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124} t1025copy_ssa(&a.mid, &x) want := T1025{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1025]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1025copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1025copy got=%v, want %v\n", a, want) } } @@ -540,14 +514,13 @@ type T1031 struct { func t1031copy_ssa(y, x *[1031]byte) { *y = *x } -func testCopy1031() { +func testCopy1031(t *testing.T) { a := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130} t1031copy_ssa(&a.mid, &x) want := T1031{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1031]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1031copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1031copy got=%v, want %v\n", a, want) } } @@ -561,14 +534,13 @@ type T1032 struct { func t1032copy_ssa(y, x *[1032]byte) { *y = *x } -func testCopy1032() { +func testCopy1032(t *testing.T) { a := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131} t1032copy_ssa(&a.mid, &x) want := T1032{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1032]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1032copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1032copy got=%v, want %v\n", a, want) } } @@ -582,14 +554,13 @@ type T1033 struct { func t1033copy_ssa(y, x *[1033]byte) { *y = *x } -func testCopy1033() { +func testCopy1033(t *testing.T) { a := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132} t1033copy_ssa(&a.mid, &x) want := T1033{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1033]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1033copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1033copy got=%v, want %v\n", a, want) } } @@ -603,14 +574,13 @@ type T1039 struct { func t1039copy_ssa(y, x *[1039]byte) { *y = *x } -func testCopy1039() { +func testCopy1039(t *testing.T) { a := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138} t1039copy_ssa(&a.mid, &x) want := T1039{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1039]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1039copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1039copy got=%v, want %v\n", a, want) } } @@ -624,14 +594,13 @@ type T1040 struct { func t1040copy_ssa(y, x *[1040]byte) { *y = *x } -func testCopy1040() { +func testCopy1040(t *testing.T) { a := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139} t1040copy_ssa(&a.mid, &x) want := T1040{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1040]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1040copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1040copy got=%v, want %v\n", a, want) } } @@ -645,14 +614,13 @@ type T1041 struct { func t1041copy_ssa(y, x *[1041]byte) { *y = *x } -func testCopy1041() { +func testCopy1041(t *testing.T) { a := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} x := [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140} t1041copy_ssa(&a.mid, &x) want := T1041{[8]byte{201, 202, 203, 204, 205, 206, 207, 208}, [1041]byte{100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140}, [8]byte{211, 212, 213, 214, 215, 216, 217, 218}} if a != want { - fmt.Printf("t1041copy got=%v, want %v\n", a, want) - failed = true + t.Errorf("t1041copy got=%v, want %v\n", a, want) } } @@ -662,14 +630,13 @@ func tu2copy_ssa(docopy bool, data [2]byte, x *[2]byte) { *x = data } } -func testUnalignedCopy2() { +func testUnalignedCopy2(t *testing.T) { var a [2]byte t2 := [2]byte{2, 3} tu2copy_ssa(true, t2, &a) want2 := [2]byte{2, 3} if a != want2 { - fmt.Printf("tu2copy got=%v, want %v\n", a, want2) - failed = true + t.Errorf("tu2copy got=%v, want %v\n", a, want2) } } @@ -679,14 +646,13 @@ func tu3copy_ssa(docopy bool, data [3]byte, x *[3]byte) { *x = data } } -func testUnalignedCopy3() { +func testUnalignedCopy3(t *testing.T) { var a [3]byte t3 := [3]byte{3, 4, 5} tu3copy_ssa(true, t3, &a) want3 := [3]byte{3, 4, 5} if a != want3 { - fmt.Printf("tu3copy got=%v, want %v\n", a, want3) - failed = true + t.Errorf("tu3copy got=%v, want %v\n", a, want3) } } @@ -696,14 +662,13 @@ func tu4copy_ssa(docopy bool, data [4]byte, x *[4]byte) { *x = data } } -func testUnalignedCopy4() { +func testUnalignedCopy4(t *testing.T) { var a [4]byte t4 := [4]byte{4, 5, 6, 7} tu4copy_ssa(true, t4, &a) want4 := [4]byte{4, 5, 6, 7} if a != want4 { - fmt.Printf("tu4copy got=%v, want %v\n", a, want4) - failed = true + t.Errorf("tu4copy got=%v, want %v\n", a, want4) } } @@ -713,14 +678,13 @@ func tu5copy_ssa(docopy bool, data [5]byte, x *[5]byte) { *x = data } } -func testUnalignedCopy5() { +func testUnalignedCopy5(t *testing.T) { var a [5]byte t5 := [5]byte{5, 6, 7, 8, 9} tu5copy_ssa(true, t5, &a) want5 := [5]byte{5, 6, 7, 8, 9} if a != want5 { - fmt.Printf("tu5copy got=%v, want %v\n", a, want5) - failed = true + t.Errorf("tu5copy got=%v, want %v\n", a, want5) } } @@ -730,14 +694,13 @@ func tu6copy_ssa(docopy bool, data [6]byte, x *[6]byte) { *x = data } } -func testUnalignedCopy6() { +func testUnalignedCopy6(t *testing.T) { var a [6]byte t6 := [6]byte{6, 7, 8, 9, 10, 11} tu6copy_ssa(true, t6, &a) want6 := [6]byte{6, 7, 8, 9, 10, 11} if a != want6 { - fmt.Printf("tu6copy got=%v, want %v\n", a, want6) - failed = true + t.Errorf("tu6copy got=%v, want %v\n", a, want6) } } @@ -747,58 +710,51 @@ func tu7copy_ssa(docopy bool, data [7]byte, x *[7]byte) { *x = data } } -func testUnalignedCopy7() { +func testUnalignedCopy7(t *testing.T) { var a [7]byte t7 := [7]byte{7, 8, 9, 10, 11, 12, 13} tu7copy_ssa(true, t7, &a) want7 := [7]byte{7, 8, 9, 10, 11, 12, 13} if a != want7 { - fmt.Printf("tu7copy got=%v, want %v\n", a, want7) - failed = true + t.Errorf("tu7copy got=%v, want %v\n", a, want7) } } - -var failed bool - -func main() { - testCopy1() - testCopy2() - testCopy3() - testCopy4() - testCopy5() - testCopy6() - testCopy7() - testCopy8() - testCopy9() - testCopy10() - testCopy15() - testCopy16() - testCopy17() - testCopy23() - testCopy24() - testCopy25() - testCopy31() - testCopy32() - testCopy33() - testCopy63() - testCopy64() - testCopy65() - testCopy1023() - testCopy1024() - testCopy1025() - testCopy1031() - testCopy1032() - testCopy1033() - testCopy1039() - testCopy1040() - testCopy1041() - testUnalignedCopy2() - testUnalignedCopy3() - testUnalignedCopy4() - testUnalignedCopy5() - testUnalignedCopy6() - testUnalignedCopy7() - if failed { - panic("failed") - } +func TestCopy(t *testing.T) { + testCopy1(t) + testCopy2(t) + testCopy3(t) + testCopy4(t) + testCopy5(t) + testCopy6(t) + testCopy7(t) + testCopy8(t) + testCopy9(t) + testCopy10(t) + testCopy15(t) + testCopy16(t) + testCopy17(t) + testCopy23(t) + testCopy24(t) + testCopy25(t) + testCopy31(t) + testCopy32(t) + testCopy33(t) + testCopy63(t) + testCopy64(t) + testCopy65(t) + testCopy1023(t) + testCopy1024(t) + testCopy1025(t) + testCopy1031(t) + testCopy1032(t) + testCopy1033(t) + testCopy1039(t) + testCopy1040(t) + testCopy1041(t) + testUnalignedCopy2(t) + testUnalignedCopy3(t) + testUnalignedCopy4(t) + testUnalignedCopy5(t) + testUnalignedCopy6(t) + testUnalignedCopy7(t) } diff --git a/src/cmd/compile/internal/gc/testdata/ctl.go b/src/cmd/compile/internal/gc/testdata/ctl_test.go similarity index 73% rename from src/cmd/compile/internal/gc/testdata/ctl.go rename to src/cmd/compile/internal/gc/testdata/ctl_test.go index 0656cb4ddb..16d571ce2c 100644 --- a/src/cmd/compile/internal/gc/testdata/ctl.go +++ b/src/cmd/compile/internal/gc/testdata/ctl_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,6 +6,8 @@ package main +import "testing" + // nor_ssa calculates NOR(a, b). // It is implemented in a way that generates // phi control values. @@ -25,7 +25,7 @@ func nor_ssa(a, b bool) bool { return true } -func testPhiControl() { +func testPhiControl(t *testing.T) { tests := [...][3]bool{ // a, b, want {false, false, true}, {true, false, false}, @@ -37,8 +37,7 @@ func testPhiControl() { got := nor_ssa(a, b) want := test[2] if want != got { - print("nor(", a, ", ", b, ")=", want, " got ", got, "\n") - failed = true + t.Errorf("nor(%t, %t)=%t got %t", a, b, want, got) } } } @@ -50,10 +49,9 @@ func emptyRange_ssa(b []byte) bool { return true } -func testEmptyRange() { +func testEmptyRange(t *testing.T) { if !emptyRange_ssa([]byte{}) { - println("emptyRange_ssa([]byte{})=false, want true") - failed = true + t.Errorf("emptyRange_ssa([]byte{})=false, want true") } } @@ -97,20 +95,18 @@ func fallthrough_ssa(a int) int { } -func testFallthrough() { +func testFallthrough(t *testing.T) { for i := 0; i < 6; i++ { if got := fallthrough_ssa(i); got != i { - println("fallthrough_ssa(i) =", got, "wanted", i) - failed = true + t.Errorf("fallthrough_ssa(i) = %d, wanted %d", got, i) } } } -func testSwitch() { +func testSwitch(t *testing.T) { for i := 0; i < 6; i++ { if got := switch_ssa(i); got != i { - println("switch_ssa(i) =", got, "wanted", i) - failed = true + t.Errorf("switch_ssa(i) = %d, wanted %d", got, i) } } } @@ -135,26 +131,19 @@ func flagOverwrite_ssa(s *junk, c int) int { return 3 } -func testFlagOverwrite() { +func testFlagOverwrite(t *testing.T) { j := junk{} if got := flagOverwrite_ssa(&j, ' '); got != 3 { - println("flagOverwrite_ssa =", got, "wanted 3") - failed = true + t.Errorf("flagOverwrite_ssa = %d, wanted 3", got) } } -var failed = false +func TestCtl(t *testing.T) { + testPhiControl(t) + testEmptyRange(t) -func main() { - testPhiControl() - testEmptyRange() + testSwitch(t) + testFallthrough(t) - testSwitch() - testFallthrough() - - testFlagOverwrite() - - if failed { - panic("failed") - } + testFlagOverwrite(t) } diff --git a/src/cmd/compile/internal/gc/testdata/deferNoReturn.go b/src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go similarity index 72% rename from src/cmd/compile/internal/gc/testdata/deferNoReturn.go rename to src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go index 7578dd56f2..308e897607 100644 --- a/src/cmd/compile/internal/gc/testdata/deferNoReturn.go +++ b/src/cmd/compile/internal/gc/testdata/deferNoReturn_test.go @@ -1,5 +1,3 @@ -// compile - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -7,7 +5,9 @@ // Test that a defer in a function with no return // statement will compile correctly. -package foo +package main + +import "testing" func deferNoReturn_ssa() { defer func() { println("returned") }() @@ -15,3 +15,7 @@ func deferNoReturn_ssa() { println("loop") } } + +func TestDeferNoReturn(t *testing.T) { + // This is a compile-time test, no runtime testing required. +} diff --git a/src/cmd/compile/internal/gc/testdata/divbyzero.go b/src/cmd/compile/internal/gc/testdata/divbyzero.go deleted file mode 100644 index 2165a1912d..0000000000 --- a/src/cmd/compile/internal/gc/testdata/divbyzero.go +++ /dev/null @@ -1,58 +0,0 @@ -package main - -import ( - "fmt" - "runtime" -) - -var failed = false - -func checkDivByZero(f func()) (divByZero bool) { - defer func() { - if r := recover(); r != nil { - if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: integer divide by zero" { - divByZero = true - } - } - }() - f() - return false -} - -//go:noinline -func a(i uint, s []int) int { - return s[i%uint(len(s))] -} - -//go:noinline -func b(i uint, j uint) uint { - return i / j -} - -//go:noinline -func c(i int) int { - return 7 / (i - i) -} - -func main() { - if got := checkDivByZero(func() { b(7, 0) }); !got { - fmt.Printf("expected div by zero for b(7, 0), got no error\n") - failed = true - } - if got := checkDivByZero(func() { b(7, 7) }); got { - fmt.Printf("expected no error for b(7, 7), got div by zero\n") - failed = true - } - if got := checkDivByZero(func() { a(4, nil) }); !got { - fmt.Printf("expected div by zero for a(4, nil), got no error\n") - failed = true - } - if got := checkDivByZero(func() { c(5) }); !got { - fmt.Printf("expected div by zero for c(5), got no error\n") - failed = true - } - - if failed { - panic("tests failed") - } -} diff --git a/src/cmd/compile/internal/gc/testdata/divbyzero_test.go b/src/cmd/compile/internal/gc/testdata/divbyzero_test.go new file mode 100644 index 0000000000..ee848b3cc0 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/divbyzero_test.go @@ -0,0 +1,48 @@ +package main + +import ( + "runtime" + "testing" +) + +func checkDivByZero(f func()) (divByZero bool) { + defer func() { + if r := recover(); r != nil { + if e, ok := r.(runtime.Error); ok && e.Error() == "runtime error: integer divide by zero" { + divByZero = true + } + } + }() + f() + return false +} + +//go:noinline +func div_a(i uint, s []int) int { + return s[i%uint(len(s))] +} + +//go:noinline +func div_b(i uint, j uint) uint { + return i / j +} + +//go:noinline +func div_c(i int) int { + return 7 / (i - i) +} + +func TestDivByZero(t *testing.T) { + if got := checkDivByZero(func() { div_b(7, 0) }); !got { + t.Errorf("expected div by zero for b(7, 0), got no error\n") + } + if got := checkDivByZero(func() { div_b(7, 7) }); got { + t.Errorf("expected no error for b(7, 7), got div by zero\n") + } + if got := checkDivByZero(func() { div_a(4, nil) }); !got { + t.Errorf("expected div by zero for a(4, nil), got no error\n") + } + if got := checkDivByZero(func() { div_c(5) }); !got { + t.Errorf("expected div by zero for c(5), got no error\n") + } +} diff --git a/src/cmd/compile/internal/gc/testdata/dupLoad.go b/src/cmd/compile/internal/gc/testdata/dupLoad_test.go similarity index 84% rename from src/cmd/compile/internal/gc/testdata/dupLoad.go rename to src/cmd/compile/internal/gc/testdata/dupLoad_test.go index d18dc733e1..9d65f54946 100644 --- a/src/cmd/compile/internal/gc/testdata/dupLoad.go +++ b/src/cmd/compile/internal/gc/testdata/dupLoad_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -9,7 +7,7 @@ package main -import "fmt" +import "testing" //go:noinline func read1(b []byte) (uint16, uint16) { @@ -19,9 +17,8 @@ func read1(b []byte) (uint16, uint16) { return uint16(v), uint16(v) | uint16(b[1])<<8 } -const N = 100000 - -func main1() { +func main1(t *testing.T) { + const N = 100000 done := make(chan struct{}) b := make([]byte, 2) go func() { @@ -35,8 +32,7 @@ func main1() { for i := 0; i < N; i++ { x, y := read1(b) if byte(x) != byte(y) { - fmt.Printf("x=%x y=%x\n", x, y) - panic("bad") + t.Fatalf("x=%x y=%x\n", x, y) } } done <- struct{}{} @@ -53,7 +49,8 @@ func read2(b []byte) (uint16, uint16) { return v, uint16(b[0]) | v } -func main2() { +func main2(t *testing.T) { + const N = 100000 done := make(chan struct{}) b := make([]byte, 2) go func() { @@ -67,8 +64,7 @@ func main2() { for i := 0; i < N; i++ { x, y := read2(b) if x&0xff00 != y&0xff00 { - fmt.Printf("x=%x y=%x\n", x, y) - panic("bad") + t.Fatalf("x=%x y=%x\n", x, y) } } done <- struct{}{} @@ -77,7 +73,7 @@ func main2() { <-done } -func main() { - main1() - main2() +func TestDupLoad(t *testing.T) { + main1(t) + main2(t) } diff --git a/src/cmd/compile/internal/gc/testdata/fp.go b/src/cmd/compile/internal/gc/testdata/fp_test.go similarity index 64% rename from src/cmd/compile/internal/gc/testdata/fp.go rename to src/cmd/compile/internal/gc/testdata/fp_test.go index 18082c5634..daed2b417a 100644 --- a/src/cmd/compile/internal/gc/testdata/fp.go +++ b/src/cmd/compile/internal/gc/testdata/fp_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,7 +6,10 @@ package main -import "fmt" +import ( + "fmt" + "testing" +) // manysub_ssa is designed to tickle bugs that depend on register // pressure or unfriendly operand ordering in registers (and at @@ -159,81 +160,78 @@ func conv2Float32_ssa(a int8, b uint8, c int16, d uint16, return } -func integer2floatConversions() int { - fails := 0 +func integer2floatConversions(t *testing.T) { { a, b, c, d, e, f, g, h, i := conv2Float64_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0) - fails += expectAll64("zero64", 0, a, b, c, d, e, f, g, h, i) + expectAll64(t, "zero64", 0, a, b, c, d, e, f, g, h, i) } { a, b, c, d, e, f, g, h, i := conv2Float64_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1) - fails += expectAll64("one64", 1, a, b, c, d, e, f, g, h, i) + expectAll64(t, "one64", 1, a, b, c, d, e, f, g, h, i) } { a, b, c, d, e, f, g, h, i := conv2Float32_ssa(0, 0, 0, 0, 0, 0, 0, 0, 0) - fails += expectAll32("zero32", 0, a, b, c, d, e, f, g, h, i) + expectAll32(t, "zero32", 0, a, b, c, d, e, f, g, h, i) } { a, b, c, d, e, f, g, h, i := conv2Float32_ssa(1, 1, 1, 1, 1, 1, 1, 1, 1) - fails += expectAll32("one32", 1, a, b, c, d, e, f, g, h, i) + expectAll32(t, "one32", 1, a, b, c, d, e, f, g, h, i) } { // Check maximum values a, b, c, d, e, f, g, h, i := conv2Float64_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823E38) - fails += expect64("a", a, 127) - fails += expect64("b", b, 255) - fails += expect64("c", c, 32767) - fails += expect64("d", d, 65535) - fails += expect64("e", e, float64(int32(0x7fffffff))) - fails += expect64("f", f, float64(uint32(0xffffffff))) - fails += expect64("g", g, float64(int64(0x7fffffffffffffff))) - fails += expect64("h", h, float64(uint64(0xffffffffffffffff))) - fails += expect64("i", i, float64(float32(3.402823E38))) + expect64(t, "a", a, 127) + expect64(t, "b", b, 255) + expect64(t, "c", c, 32767) + expect64(t, "d", d, 65535) + expect64(t, "e", e, float64(int32(0x7fffffff))) + expect64(t, "f", f, float64(uint32(0xffffffff))) + expect64(t, "g", g, float64(int64(0x7fffffffffffffff))) + expect64(t, "h", h, float64(uint64(0xffffffffffffffff))) + expect64(t, "i", i, float64(float32(3.402823E38))) } { // Check minimum values (and tweaks for unsigned) a, b, c, d, e, f, g, h, i := conv2Float64_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5E-45) - fails += expect64("a", a, -128) - fails += expect64("b", b, 254) - fails += expect64("c", c, -32768) - fails += expect64("d", d, 65534) - fails += expect64("e", e, float64(^int32(0x7fffffff))) - fails += expect64("f", f, float64(uint32(0xfffffffe))) - fails += expect64("g", g, float64(^int64(0x7fffffffffffffff))) - fails += expect64("h", h, float64(uint64(0xfffffffffffff401))) - fails += expect64("i", i, float64(float32(1.5E-45))) + expect64(t, "a", a, -128) + expect64(t, "b", b, 254) + expect64(t, "c", c, -32768) + expect64(t, "d", d, 65534) + expect64(t, "e", e, float64(^int32(0x7fffffff))) + expect64(t, "f", f, float64(uint32(0xfffffffe))) + expect64(t, "g", g, float64(^int64(0x7fffffffffffffff))) + expect64(t, "h", h, float64(uint64(0xfffffffffffff401))) + expect64(t, "i", i, float64(float32(1.5E-45))) } { // Check maximum values a, b, c, d, e, f, g, h, i := conv2Float32_ssa(127, 255, 32767, 65535, 0x7fffffff, 0xffffffff, 0x7fffFFFFffffFFFF, 0xffffFFFFffffFFFF, 3.402823E38) - fails += expect32("a", a, 127) - fails += expect32("b", b, 255) - fails += expect32("c", c, 32767) - fails += expect32("d", d, 65535) - fails += expect32("e", e, float32(int32(0x7fffffff))) - fails += expect32("f", f, float32(uint32(0xffffffff))) - fails += expect32("g", g, float32(int64(0x7fffffffffffffff))) - fails += expect32("h", h, float32(uint64(0xffffffffffffffff))) - fails += expect32("i", i, float32(float64(3.402823E38))) + expect32(t, "a", a, 127) + expect32(t, "b", b, 255) + expect32(t, "c", c, 32767) + expect32(t, "d", d, 65535) + expect32(t, "e", e, float32(int32(0x7fffffff))) + expect32(t, "f", f, float32(uint32(0xffffffff))) + expect32(t, "g", g, float32(int64(0x7fffffffffffffff))) + expect32(t, "h", h, float32(uint64(0xffffffffffffffff))) + expect32(t, "i", i, float32(float64(3.402823E38))) } { // Check minimum values (and tweaks for unsigned) a, b, c, d, e, f, g, h, i := conv2Float32_ssa(-128, 254, -32768, 65534, ^0x7fffffff, 0xfffffffe, ^0x7fffFFFFffffFFFF, 0xffffFFFFffffF401, 1.5E-45) - fails += expect32("a", a, -128) - fails += expect32("b", b, 254) - fails += expect32("c", c, -32768) - fails += expect32("d", d, 65534) - fails += expect32("e", e, float32(^int32(0x7fffffff))) - fails += expect32("f", f, float32(uint32(0xfffffffe))) - fails += expect32("g", g, float32(^int64(0x7fffffffffffffff))) - fails += expect32("h", h, float32(uint64(0xfffffffffffff401))) - fails += expect32("i", i, float32(float64(1.5E-45))) + expect32(t, "a", a, -128) + expect32(t, "b", b, 254) + expect32(t, "c", c, -32768) + expect32(t, "d", d, 65534) + expect32(t, "e", e, float32(^int32(0x7fffffff))) + expect32(t, "f", f, float32(uint32(0xfffffffe))) + expect32(t, "g", g, float32(^int64(0x7fffffffffffffff))) + expect32(t, "h", h, float32(uint64(0xfffffffffffff401))) + expect32(t, "i", i, float32(float64(1.5E-45))) } - return fails } -func multiplyAdd() int { - fails := 0 +func multiplyAdd(t *testing.T) { { // Test that a multiply-accumulate operation with intermediate // rounding forced by a float32() cast produces the expected @@ -252,22 +250,20 @@ func multiplyAdd() int { {0.6280982, 0.12675293, 0.2813303, 0.36094356}, // fused multiply-add result: 0.3609436 {0.29400632, 0.75316125, 0.15096405, 0.3723982}, // fused multiply-add result: 0.37239823 } - check := func(s string, got, expected float32) int { + check := func(s string, got, expected float32) { if got != expected { fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got) - return 1 } - return 0 } for _, t := range tests { - fails += check( + check( fmt.Sprintf("float32(%v * %v) + %v", t.x, t.y, t.z), func(x, y, z float32) float32 { return float32(x*y) + z }(t.x, t.y, t.z), t.res) - fails += check( + check( fmt.Sprintf("%v += float32(%v * %v)", t.z, t.x, t.y), func(x, y, z float32) float32 { z += float32(x * y) @@ -294,22 +290,20 @@ func multiplyAdd() int { {0.3691117091643448, 0.826454125634742, 0.34768170859156955, 0.6527356034505334}, // fused multiply-add result: 0.6527356034505333 {0.16867966833433606, 0.33136826030698385, 0.8279280961505588, 0.8838231843956668}, // fused multiply-add result: 0.8838231843956669 } - check := func(s string, got, expected float64) int { + check := func(s string, got, expected float64) { if got != expected { fmt.Printf("multiplyAdd: %s, expected %g, got %g\n", s, expected, got) - return 1 } - return 0 } for _, t := range tests { - fails += check( + check( fmt.Sprintf("float64(%v * %v) + %v", t.x, t.y, t.z), func(x, y, z float64) float64 { return float64(x*y) + z }(t.x, t.y, t.z), t.res) - fails += check( + check( fmt.Sprintf("%v += float64(%v * %v)", t.z, t.x, t.y), func(x, y, z float64) float64 { z += float64(x * y) @@ -339,22 +333,20 @@ func multiplyAdd() int { {0.8963417453962161, 0.3220839705208817, (3.0111092067095298 + 3i)}, // fused multiply-add result: (3.01110920670953 + 3i) {0.39998376285699544, 0.497868113342702, (1.697819401913688 + 3i)}, // fused multiply-add result: (1.6978194019136883 + 3i) } - check := func(s string, got, expected complex128) int { + check := func(s string, got, expected complex128) { if got != expected { fmt.Printf("multiplyAdd: %s, expected %v, got %v\n", s, expected, got) - return 1 } - return 0 } for _, t := range tests { - fails += check( + check( fmt.Sprintf("complex128(complex(%v, 1)*3) + complex(%v, 0)", t.x, t.y), func(x, y float64) complex128 { return complex128(complex(x, 1)*3) + complex(y, 0) }(t.x, t.y), t.res) - fails += check( + check( fmt.Sprintf("z := complex(%v, 1); z += complex128(complex(%v, 1) * 3)", t.y, t.x), func(x, y float64) complex128 { z := complex(y, 0) @@ -364,7 +356,6 @@ func multiplyAdd() int { t.res) } } - return fails } const ( @@ -1256,48 +1247,43 @@ func F64toI64_ssa(x float64) int64 { return int64(x) } -func floatsToInts(x float64, expected int64) int { +func floatsToInts(t *testing.T, x float64, expected int64) { y := float32(x) - fails := 0 - fails += expectInt64("F64toI8", int64(F64toI8_ssa(x)), expected) - fails += expectInt64("F64toI16", int64(F64toI16_ssa(x)), expected) - fails += expectInt64("F64toI32", int64(F64toI32_ssa(x)), expected) - fails += expectInt64("F64toI64", int64(F64toI64_ssa(x)), expected) - fails += expectInt64("F32toI8", int64(F32toI8_ssa(y)), expected) - fails += expectInt64("F32toI16", int64(F32toI16_ssa(y)), expected) - fails += expectInt64("F32toI32", int64(F32toI32_ssa(y)), expected) - fails += expectInt64("F32toI64", int64(F32toI64_ssa(y)), expected) - return fails + expectInt64(t, "F64toI8", int64(F64toI8_ssa(x)), expected) + expectInt64(t, "F64toI16", int64(F64toI16_ssa(x)), expected) + expectInt64(t, "F64toI32", int64(F64toI32_ssa(x)), expected) + expectInt64(t, "F64toI64", int64(F64toI64_ssa(x)), expected) + expectInt64(t, "F32toI8", int64(F32toI8_ssa(y)), expected) + expectInt64(t, "F32toI16", int64(F32toI16_ssa(y)), expected) + expectInt64(t, "F32toI32", int64(F32toI32_ssa(y)), expected) + expectInt64(t, "F32toI64", int64(F32toI64_ssa(y)), expected) } -func floatsToUints(x float64, expected uint64) int { +func floatsToUints(t *testing.T, x float64, expected uint64) { y := float32(x) - fails := 0 - fails += expectUint64("F64toU8", uint64(F64toU8_ssa(x)), expected) - fails += expectUint64("F64toU16", uint64(F64toU16_ssa(x)), expected) - fails += expectUint64("F64toU32", uint64(F64toU32_ssa(x)), expected) - fails += expectUint64("F64toU64", uint64(F64toU64_ssa(x)), expected) - fails += expectUint64("F32toU8", uint64(F32toU8_ssa(y)), expected) - fails += expectUint64("F32toU16", uint64(F32toU16_ssa(y)), expected) - fails += expectUint64("F32toU32", uint64(F32toU32_ssa(y)), expected) - fails += expectUint64("F32toU64", uint64(F32toU64_ssa(y)), expected) - return fails + expectUint64(t, "F64toU8", uint64(F64toU8_ssa(x)), expected) + expectUint64(t, "F64toU16", uint64(F64toU16_ssa(x)), expected) + expectUint64(t, "F64toU32", uint64(F64toU32_ssa(x)), expected) + expectUint64(t, "F64toU64", uint64(F64toU64_ssa(x)), expected) + expectUint64(t, "F32toU8", uint64(F32toU8_ssa(y)), expected) + expectUint64(t, "F32toU16", uint64(F32toU16_ssa(y)), expected) + expectUint64(t, "F32toU32", uint64(F32toU32_ssa(y)), expected) + expectUint64(t, "F32toU64", uint64(F32toU64_ssa(y)), expected) } -func floatingToIntegerConversionsTest() int { - fails := 0 - fails += floatsToInts(0.0, 0) - fails += floatsToInts(0.5, 0) - fails += floatsToInts(0.9, 0) - fails += floatsToInts(1.0, 1) - fails += floatsToInts(1.5, 1) - fails += floatsToInts(127.0, 127) - fails += floatsToInts(-1.0, -1) - fails += floatsToInts(-128.0, -128) +func floatingToIntegerConversionsTest(t *testing.T) { + floatsToInts(t, 0.0, 0) + floatsToInts(t, 0.5, 0) + floatsToInts(t, 0.9, 0) + floatsToInts(t, 1.0, 1) + floatsToInts(t, 1.5, 1) + floatsToInts(t, 127.0, 127) + floatsToInts(t, -1.0, -1) + floatsToInts(t, -128.0, -128) - fails += floatsToUints(0.0, 0) - fails += floatsToUints(1.0, 1) - fails += floatsToUints(255.0, 255) + floatsToUints(t, 0.0, 0) + floatsToUints(t, 1.0, 1) + floatsToUints(t, 255.0, 255) for j := uint(0); j < 24; j++ { // Avoid hard cases in the construction @@ -1306,17 +1292,17 @@ func floatingToIntegerConversionsTest() int { w := uint64(v) f := float32(v) d := float64(v) - fails += expectUint64("2**62...", F32toU64_ssa(f), w) - fails += expectUint64("2**62...", F64toU64_ssa(d), w) - fails += expectInt64("2**62...", F32toI64_ssa(f), v) - fails += expectInt64("2**62...", F64toI64_ssa(d), v) - fails += expectInt64("2**62...", F32toI64_ssa(-f), -v) - fails += expectInt64("2**62...", F64toI64_ssa(-d), -v) + expectUint64(t, "2**62...", F32toU64_ssa(f), w) + expectUint64(t, "2**62...", F64toU64_ssa(d), w) + expectInt64(t, "2**62...", F32toI64_ssa(f), v) + expectInt64(t, "2**62...", F64toI64_ssa(d), v) + expectInt64(t, "2**62...", F32toI64_ssa(-f), -v) + expectInt64(t, "2**62...", F64toI64_ssa(-d), -v) w += w f += f d += d - fails += expectUint64("2**63...", F32toU64_ssa(f), w) - fails += expectUint64("2**63...", F64toU64_ssa(d), w) + expectUint64(t, "2**63...", F32toU64_ssa(f), w) + expectUint64(t, "2**63...", F64toU64_ssa(d), w) } for j := uint(0); j < 16; j++ { @@ -1326,17 +1312,17 @@ func floatingToIntegerConversionsTest() int { w := uint32(v) f := float32(v) d := float64(v) - fails += expectUint32("2**30...", F32toU32_ssa(f), w) - fails += expectUint32("2**30...", F64toU32_ssa(d), w) - fails += expectInt32("2**30...", F32toI32_ssa(f), v) - fails += expectInt32("2**30...", F64toI32_ssa(d), v) - fails += expectInt32("2**30...", F32toI32_ssa(-f), -v) - fails += expectInt32("2**30...", F64toI32_ssa(-d), -v) + expectUint32(t, "2**30...", F32toU32_ssa(f), w) + expectUint32(t, "2**30...", F64toU32_ssa(d), w) + expectInt32(t, "2**30...", F32toI32_ssa(f), v) + expectInt32(t, "2**30...", F64toI32_ssa(d), v) + expectInt32(t, "2**30...", F32toI32_ssa(-f), -v) + expectInt32(t, "2**30...", F64toI32_ssa(-d), -v) w += w f += f d += d - fails += expectUint32("2**31...", F32toU32_ssa(f), w) - fails += expectUint32("2**31...", F64toU32_ssa(d), w) + expectUint32(t, "2**31...", F32toU32_ssa(f), w) + expectUint32(t, "2**31...", F64toU32_ssa(d), w) } for j := uint(0); j < 15; j++ { @@ -1346,220 +1332,184 @@ func floatingToIntegerConversionsTest() int { w := uint16(v) f := float32(v) d := float64(v) - fails += expectUint16("2**14...", F32toU16_ssa(f), w) - fails += expectUint16("2**14...", F64toU16_ssa(d), w) - fails += expectInt16("2**14...", F32toI16_ssa(f), v) - fails += expectInt16("2**14...", F64toI16_ssa(d), v) - fails += expectInt16("2**14...", F32toI16_ssa(-f), -v) - fails += expectInt16("2**14...", F64toI16_ssa(-d), -v) + expectUint16(t, "2**14...", F32toU16_ssa(f), w) + expectUint16(t, "2**14...", F64toU16_ssa(d), w) + expectInt16(t, "2**14...", F32toI16_ssa(f), v) + expectInt16(t, "2**14...", F64toI16_ssa(d), v) + expectInt16(t, "2**14...", F32toI16_ssa(-f), -v) + expectInt16(t, "2**14...", F64toI16_ssa(-d), -v) w += w f += f d += d - fails += expectUint16("2**15...", F32toU16_ssa(f), w) - fails += expectUint16("2**15...", F64toU16_ssa(d), w) + expectUint16(t, "2**15...", F32toU16_ssa(f), w) + expectUint16(t, "2**15...", F64toU16_ssa(d), w) } - fails += expectInt32("-2147483648", F32toI32_ssa(-2147483648), -2147483648) + expectInt32(t, "-2147483648", F32toI32_ssa(-2147483648), -2147483648) - fails += expectInt32("-2147483648", F64toI32_ssa(-2147483648), -2147483648) - fails += expectInt32("-2147483647", F64toI32_ssa(-2147483647), -2147483647) - fails += expectUint32("4294967295", F64toU32_ssa(4294967295), 4294967295) + expectInt32(t, "-2147483648", F64toI32_ssa(-2147483648), -2147483648) + expectInt32(t, "-2147483647", F64toI32_ssa(-2147483647), -2147483647) + expectUint32(t, "4294967295", F64toU32_ssa(4294967295), 4294967295) - fails += expectInt16("-32768", F64toI16_ssa(-32768), -32768) - fails += expectInt16("-32768", F32toI16_ssa(-32768), -32768) + expectInt16(t, "-32768", F64toI16_ssa(-32768), -32768) + expectInt16(t, "-32768", F32toI16_ssa(-32768), -32768) // NB more of a pain to do these for 32-bit because of lost bits in Float32 mantissa - fails += expectInt16("32767", F64toI16_ssa(32767), 32767) - fails += expectInt16("32767", F32toI16_ssa(32767), 32767) - fails += expectUint16("32767", F64toU16_ssa(32767), 32767) - fails += expectUint16("32767", F32toU16_ssa(32767), 32767) - fails += expectUint16("65535", F64toU16_ssa(65535), 65535) - fails += expectUint16("65535", F32toU16_ssa(65535), 65535) - - return fails + expectInt16(t, "32767", F64toI16_ssa(32767), 32767) + expectInt16(t, "32767", F32toI16_ssa(32767), 32767) + expectUint16(t, "32767", F64toU16_ssa(32767), 32767) + expectUint16(t, "32767", F32toU16_ssa(32767), 32767) + expectUint16(t, "65535", F64toU16_ssa(65535), 65535) + expectUint16(t, "65535", F32toU16_ssa(65535), 65535) } -func fail64(s string, f func(a, b float64) float64, a, b, e float64) int { +func fail64(s string, f func(a, b float64) float64, a, b, e float64) { d := f(a, b) if d != e { fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d) - return 1 } - return 0 } -func fail64bool(s string, f func(a, b float64) bool, a, b float64, e bool) int { +func fail64bool(s string, f func(a, b float64) bool, a, b float64, e bool) { d := f(a, b) if d != e { fmt.Printf("For (float64) %v %v %v, expected %v, got %v\n", a, s, b, e, d) - return 1 } - return 0 } -func fail32(s string, f func(a, b float32) float32, a, b, e float32) int { +func fail32(s string, f func(a, b float32) float32, a, b, e float32) { d := f(a, b) if d != e { fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d) - return 1 } - return 0 } -func fail32bool(s string, f func(a, b float32) bool, a, b float32, e bool) int { +func fail32bool(s string, f func(a, b float32) bool, a, b float32, e bool) { d := f(a, b) if d != e { fmt.Printf("For (float32) %v %v %v, expected %v, got %v\n", a, s, b, e, d) - return 1 } - return 0 } -func expect64(s string, x, expected float64) int { +func expect64(t *testing.T, s string, x, expected float64) { if x != expected { println("F64 Expected", expected, "for", s, ", got", x) - return 1 } - return 0 } -func expect32(s string, x, expected float32) int { +func expect32(t *testing.T, s string, x, expected float32) { if x != expected { println("F32 Expected", expected, "for", s, ", got", x) - return 1 } - return 0 } -func expectUint64(s string, x, expected uint64) int { +func expectUint64(t *testing.T, s string, x, expected uint64) { if x != expected { fmt.Printf("U64 Expected 0x%016x for %s, got 0x%016x\n", expected, s, x) - return 1 } - return 0 } -func expectInt64(s string, x, expected int64) int { +func expectInt64(t *testing.T, s string, x, expected int64) { if x != expected { fmt.Printf("%s: Expected 0x%016x, got 0x%016x\n", s, expected, x) - return 1 } - return 0 } -func expectUint32(s string, x, expected uint32) int { +func expectUint32(t *testing.T, s string, x, expected uint32) { if x != expected { fmt.Printf("U32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x) - return 1 } - return 0 } -func expectInt32(s string, x, expected int32) int { +func expectInt32(t *testing.T, s string, x, expected int32) { if x != expected { fmt.Printf("I32 %s: Expected 0x%08x, got 0x%08x\n", s, expected, x) - return 1 } - return 0 } -func expectUint16(s string, x, expected uint16) int { +func expectUint16(t *testing.T, s string, x, expected uint16) { if x != expected { fmt.Printf("U16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x) - return 1 } - return 0 } -func expectInt16(s string, x, expected int16) int { +func expectInt16(t *testing.T, s string, x, expected int16) { if x != expected { fmt.Printf("I16 %s: Expected 0x%04x, got 0x%04x\n", s, expected, x) - return 1 } - return 0 } -func expectAll64(s string, expected, a, b, c, d, e, f, g, h, i float64) int { - fails := 0 - fails += expect64(s+":a", a, expected) - fails += expect64(s+":b", b, expected) - fails += expect64(s+":c", c, expected) - fails += expect64(s+":d", d, expected) - fails += expect64(s+":e", e, expected) - fails += expect64(s+":f", f, expected) - fails += expect64(s+":g", g, expected) - return fails +func expectAll64(t *testing.T, s string, expected, a, b, c, d, e, f, g, h, i float64) { + expect64(t, s+":a", a, expected) + expect64(t, s+":b", b, expected) + expect64(t, s+":c", c, expected) + expect64(t, s+":d", d, expected) + expect64(t, s+":e", e, expected) + expect64(t, s+":f", f, expected) + expect64(t, s+":g", g, expected) } -func expectAll32(s string, expected, a, b, c, d, e, f, g, h, i float32) int { - fails := 0 - fails += expect32(s+":a", a, expected) - fails += expect32(s+":b", b, expected) - fails += expect32(s+":c", c, expected) - fails += expect32(s+":d", d, expected) - fails += expect32(s+":e", e, expected) - fails += expect32(s+":f", f, expected) - fails += expect32(s+":g", g, expected) - return fails +func expectAll32(t *testing.T, s string, expected, a, b, c, d, e, f, g, h, i float32) { + expect32(t, s+":a", a, expected) + expect32(t, s+":b", b, expected) + expect32(t, s+":c", c, expected) + expect32(t, s+":d", d, expected) + expect32(t, s+":e", e, expected) + expect32(t, s+":f", f, expected) + expect32(t, s+":g", g, expected) } var ev64 [2]float64 = [2]float64{42.0, 17.0} var ev32 [2]float32 = [2]float32{42.0, 17.0} -func cmpOpTest(s string, +func cmpOpTest(t *testing.T, + s string, f func(a, b float64) bool, g func(a, b float64) float64, ff func(a, b float32) bool, gg func(a, b float32) float32, - zero, one, inf, nan float64, result uint) int { - fails := 0 - fails += fail64bool(s, f, zero, zero, result>>16&1 == 1) - fails += fail64bool(s, f, zero, one, result>>12&1 == 1) - fails += fail64bool(s, f, zero, inf, result>>8&1 == 1) - fails += fail64bool(s, f, zero, nan, result>>4&1 == 1) - fails += fail64bool(s, f, nan, nan, result&1 == 1) + zero, one, inf, nan float64, result uint) { + fail64bool(s, f, zero, zero, result>>16&1 == 1) + fail64bool(s, f, zero, one, result>>12&1 == 1) + fail64bool(s, f, zero, inf, result>>8&1 == 1) + fail64bool(s, f, zero, nan, result>>4&1 == 1) + fail64bool(s, f, nan, nan, result&1 == 1) - fails += fail64(s, g, zero, zero, ev64[result>>16&1]) - fails += fail64(s, g, zero, one, ev64[result>>12&1]) - fails += fail64(s, g, zero, inf, ev64[result>>8&1]) - fails += fail64(s, g, zero, nan, ev64[result>>4&1]) - fails += fail64(s, g, nan, nan, ev64[result>>0&1]) + fail64(s, g, zero, zero, ev64[result>>16&1]) + fail64(s, g, zero, one, ev64[result>>12&1]) + fail64(s, g, zero, inf, ev64[result>>8&1]) + fail64(s, g, zero, nan, ev64[result>>4&1]) + fail64(s, g, nan, nan, ev64[result>>0&1]) { zero := float32(zero) one := float32(one) inf := float32(inf) nan := float32(nan) - fails += fail32bool(s, ff, zero, zero, (result>>16)&1 == 1) - fails += fail32bool(s, ff, zero, one, (result>>12)&1 == 1) - fails += fail32bool(s, ff, zero, inf, (result>>8)&1 == 1) - fails += fail32bool(s, ff, zero, nan, (result>>4)&1 == 1) - fails += fail32bool(s, ff, nan, nan, result&1 == 1) + fail32bool(s, ff, zero, zero, (result>>16)&1 == 1) + fail32bool(s, ff, zero, one, (result>>12)&1 == 1) + fail32bool(s, ff, zero, inf, (result>>8)&1 == 1) + fail32bool(s, ff, zero, nan, (result>>4)&1 == 1) + fail32bool(s, ff, nan, nan, result&1 == 1) - fails += fail32(s, gg, zero, zero, ev32[(result>>16)&1]) - fails += fail32(s, gg, zero, one, ev32[(result>>12)&1]) - fails += fail32(s, gg, zero, inf, ev32[(result>>8)&1]) - fails += fail32(s, gg, zero, nan, ev32[(result>>4)&1]) - fails += fail32(s, gg, nan, nan, ev32[(result>>0)&1]) + fail32(s, gg, zero, zero, ev32[(result>>16)&1]) + fail32(s, gg, zero, one, ev32[(result>>12)&1]) + fail32(s, gg, zero, inf, ev32[(result>>8)&1]) + fail32(s, gg, zero, nan, ev32[(result>>4)&1]) + fail32(s, gg, nan, nan, ev32[(result>>0)&1]) } - - return fails } -func expectCx128(s string, x, expected complex128) int { +func expectCx128(t *testing.T, s string, x, expected complex128) { if x != expected { - println("Cx 128 Expected", expected, "for", s, ", got", x) - return 1 + t.Errorf("Cx 128 Expected %f for %s, got %f", expected, s, x) } - return 0 } -func expectCx64(s string, x, expected complex64) int { +func expectCx64(t *testing.T, s string, x, expected complex64) { if x != expected { - println("Cx 64 Expected", expected, "for", s, ", got", x) - return 1 + t.Errorf("Cx 64 Expected %f for %s, got %f", expected, s, x) } - return 0 } //go:noinline @@ -1658,23 +1608,18 @@ func cx64ne_ssa(a, b complex64) bool { return a != b } -func expectTrue(s string, b bool) int { +func expectTrue(t *testing.T, s string, b bool) { if !b { - println("expected true for", s, ", got false") - return 1 + t.Errorf("expected true for %s, got false", s) } - return 0 } -func expectFalse(s string, b bool) int { +func expectFalse(t *testing.T, s string, b bool) { if b { - println("expected false for", s, ", got true") - return 1 + t.Errorf("expected false for %s, got true", s) } - return 0 } -func complexTest128() int { - fails := 0 +func complexTest128(t *testing.T) { var a complex128 = 1 + 2i var b complex128 = 3 + 6i sum := cx128sum_ssa(b, a) @@ -1690,24 +1635,21 @@ func complexTest128() int { c3 := cx128ne_ssa(a, a) c4 := cx128ne_ssa(a, b) - fails += expectCx128("sum", sum, 4+8i) - fails += expectCx128("diff", diff, 2+4i) - fails += expectCx128("prod", prod, -9+12i) - fails += expectCx128("quot", quot, 3+0i) - fails += expectCx128("neg", neg, -1-2i) - fails += expect64("real", r, 1) - fails += expect64("imag", i, 2) - fails += expectCx128("cnst", cnst, -4+7i) - fails += expectTrue(fmt.Sprintf("%v==%v", a, a), c1) - fails += expectFalse(fmt.Sprintf("%v==%v", a, b), c2) - fails += expectFalse(fmt.Sprintf("%v!=%v", a, a), c3) - fails += expectTrue(fmt.Sprintf("%v!=%v", a, b), c4) - - return fails + expectCx128(t, "sum", sum, 4+8i) + expectCx128(t, "diff", diff, 2+4i) + expectCx128(t, "prod", prod, -9+12i) + expectCx128(t, "quot", quot, 3+0i) + expectCx128(t, "neg", neg, -1-2i) + expect64(t, "real", r, 1) + expect64(t, "imag", i, 2) + expectCx128(t, "cnst", cnst, -4+7i) + expectTrue(t, fmt.Sprintf("%v==%v", a, a), c1) + expectFalse(t, fmt.Sprintf("%v==%v", a, b), c2) + expectFalse(t, fmt.Sprintf("%v!=%v", a, a), c3) + expectTrue(t, fmt.Sprintf("%v!=%v", a, b), c4) } -func complexTest64() int { - fails := 0 +func complexTest64(t *testing.T) { var a complex64 = 1 + 2i var b complex64 = 3 + 6i sum := cx64sum_ssa(b, a) @@ -1722,23 +1664,21 @@ func complexTest64() int { c3 := cx64ne_ssa(a, a) c4 := cx64ne_ssa(a, b) - fails += expectCx64("sum", sum, 4+8i) - fails += expectCx64("diff", diff, 2+4i) - fails += expectCx64("prod", prod, -9+12i) - fails += expectCx64("quot", quot, 3+0i) - fails += expectCx64("neg", neg, -1-2i) - fails += expect32("real", r, 1) - fails += expect32("imag", i, 2) - fails += expectTrue(fmt.Sprintf("%v==%v", a, a), c1) - fails += expectFalse(fmt.Sprintf("%v==%v", a, b), c2) - fails += expectFalse(fmt.Sprintf("%v!=%v", a, a), c3) - fails += expectTrue(fmt.Sprintf("%v!=%v", a, b), c4) - - return fails + expectCx64(t, "sum", sum, 4+8i) + expectCx64(t, "diff", diff, 2+4i) + expectCx64(t, "prod", prod, -9+12i) + expectCx64(t, "quot", quot, 3+0i) + expectCx64(t, "neg", neg, -1-2i) + expect32(t, "real", r, 1) + expect32(t, "imag", i, 2) + expectTrue(t, fmt.Sprintf("%v==%v", a, a), c1) + expectFalse(t, fmt.Sprintf("%v==%v", a, b), c2) + expectFalse(t, fmt.Sprintf("%v!=%v", a, a), c3) + expectTrue(t, fmt.Sprintf("%v!=%v", a, b), c4) } -func main() { - +// TestFP tests that we get the right answer for floating point expressions. +func TestFP(t *testing.T) { a := 3.0 b := 4.0 @@ -1748,92 +1688,86 @@ func main() { tiny := float32(1.5E-45) // smallest f32 denorm = 2**(-149) dtiny := float64(tiny) // well within range of f64 - fails := 0 - fails += fail64("+", add64_ssa, a, b, 7.0) - fails += fail64("*", mul64_ssa, a, b, 12.0) - fails += fail64("-", sub64_ssa, a, b, -1.0) - fails += fail64("/", div64_ssa, a, b, 0.75) - fails += fail64("neg", neg64_ssa, a, b, -7) + fail64("+", add64_ssa, a, b, 7.0) + fail64("*", mul64_ssa, a, b, 12.0) + fail64("-", sub64_ssa, a, b, -1.0) + fail64("/", div64_ssa, a, b, 0.75) + fail64("neg", neg64_ssa, a, b, -7) - fails += fail32("+", add32_ssa, c, d, 7.0) - fails += fail32("*", mul32_ssa, c, d, 12.0) - fails += fail32("-", sub32_ssa, c, d, -1.0) - fails += fail32("/", div32_ssa, c, d, 0.75) - fails += fail32("neg", neg32_ssa, c, d, -7) + fail32("+", add32_ssa, c, d, 7.0) + fail32("*", mul32_ssa, c, d, 12.0) + fail32("-", sub32_ssa, c, d, -1.0) + fail32("/", div32_ssa, c, d, 0.75) + fail32("neg", neg32_ssa, c, d, -7) // denorm-squared should underflow to zero. - fails += fail32("*", mul32_ssa, tiny, tiny, 0) + fail32("*", mul32_ssa, tiny, tiny, 0) // but should not underflow in float and in fact is exactly representable. - fails += fail64("*", mul64_ssa, dtiny, dtiny, 1.9636373861190906e-90) + fail64("*", mul64_ssa, dtiny, dtiny, 1.9636373861190906e-90) // Intended to create register pressure which forces // asymmetric op into different code paths. aa, ab, ac, ad, ba, bb, bc, bd, ca, cb, cc, cd, da, db, dc, dd := manysub_ssa(1000.0, 100.0, 10.0, 1.0) - fails += expect64("aa", aa, 11.0) - fails += expect64("ab", ab, 900.0) - fails += expect64("ac", ac, 990.0) - fails += expect64("ad", ad, 999.0) + expect64(t, "aa", aa, 11.0) + expect64(t, "ab", ab, 900.0) + expect64(t, "ac", ac, 990.0) + expect64(t, "ad", ad, 999.0) - fails += expect64("ba", ba, -900.0) - fails += expect64("bb", bb, 22.0) - fails += expect64("bc", bc, 90.0) - fails += expect64("bd", bd, 99.0) + expect64(t, "ba", ba, -900.0) + expect64(t, "bb", bb, 22.0) + expect64(t, "bc", bc, 90.0) + expect64(t, "bd", bd, 99.0) - fails += expect64("ca", ca, -990.0) - fails += expect64("cb", cb, -90.0) - fails += expect64("cc", cc, 33.0) - fails += expect64("cd", cd, 9.0) + expect64(t, "ca", ca, -990.0) + expect64(t, "cb", cb, -90.0) + expect64(t, "cc", cc, 33.0) + expect64(t, "cd", cd, 9.0) - fails += expect64("da", da, -999.0) - fails += expect64("db", db, -99.0) - fails += expect64("dc", dc, -9.0) - fails += expect64("dd", dd, 44.0) + expect64(t, "da", da, -999.0) + expect64(t, "db", db, -99.0) + expect64(t, "dc", dc, -9.0) + expect64(t, "dd", dd, 44.0) - fails += integer2floatConversions() + integer2floatConversions(t) - fails += multiplyAdd() + multiplyAdd(t) var zero64 float64 = 0.0 var one64 float64 = 1.0 var inf64 float64 = 1.0 / zero64 var nan64 float64 = sub64_ssa(inf64, inf64) - fails += cmpOpTest("!=", ne64_ssa, nebr64_ssa, ne32_ssa, nebr32_ssa, zero64, one64, inf64, nan64, 0x01111) - fails += cmpOpTest("==", eq64_ssa, eqbr64_ssa, eq32_ssa, eqbr32_ssa, zero64, one64, inf64, nan64, 0x10000) - fails += cmpOpTest("<=", le64_ssa, lebr64_ssa, le32_ssa, lebr32_ssa, zero64, one64, inf64, nan64, 0x11100) - fails += cmpOpTest("<", lt64_ssa, ltbr64_ssa, lt32_ssa, ltbr32_ssa, zero64, one64, inf64, nan64, 0x01100) - fails += cmpOpTest(">", gt64_ssa, gtbr64_ssa, gt32_ssa, gtbr32_ssa, zero64, one64, inf64, nan64, 0x00000) - fails += cmpOpTest(">=", ge64_ssa, gebr64_ssa, ge32_ssa, gebr32_ssa, zero64, one64, inf64, nan64, 0x10000) + cmpOpTest(t, "!=", ne64_ssa, nebr64_ssa, ne32_ssa, nebr32_ssa, zero64, one64, inf64, nan64, 0x01111) + cmpOpTest(t, "==", eq64_ssa, eqbr64_ssa, eq32_ssa, eqbr32_ssa, zero64, one64, inf64, nan64, 0x10000) + cmpOpTest(t, "<=", le64_ssa, lebr64_ssa, le32_ssa, lebr32_ssa, zero64, one64, inf64, nan64, 0x11100) + cmpOpTest(t, "<", lt64_ssa, ltbr64_ssa, lt32_ssa, ltbr32_ssa, zero64, one64, inf64, nan64, 0x01100) + cmpOpTest(t, ">", gt64_ssa, gtbr64_ssa, gt32_ssa, gtbr32_ssa, zero64, one64, inf64, nan64, 0x00000) + cmpOpTest(t, ">=", ge64_ssa, gebr64_ssa, ge32_ssa, gebr32_ssa, zero64, one64, inf64, nan64, 0x10000) { lt, le, eq, ne, ge, gt := compares64_ssa(0.0, 1.0, inf64, nan64) - fails += expectUint64("lt", lt, 0x0110001000000000) - fails += expectUint64("le", le, 0x1110011000100000) - fails += expectUint64("eq", eq, 0x1000010000100000) - fails += expectUint64("ne", ne, 0x0111101111011111) - fails += expectUint64("ge", ge, 0x1000110011100000) - fails += expectUint64("gt", gt, 0x0000100011000000) + expectUint64(t, "lt", lt, 0x0110001000000000) + expectUint64(t, "le", le, 0x1110011000100000) + expectUint64(t, "eq", eq, 0x1000010000100000) + expectUint64(t, "ne", ne, 0x0111101111011111) + expectUint64(t, "ge", ge, 0x1000110011100000) + expectUint64(t, "gt", gt, 0x0000100011000000) // fmt.Printf("lt=0x%016x, le=0x%016x, eq=0x%016x, ne=0x%016x, ge=0x%016x, gt=0x%016x\n", // lt, le, eq, ne, ge, gt) } { lt, le, eq, ne, ge, gt := compares32_ssa(0.0, 1.0, float32(inf64), float32(nan64)) - fails += expectUint64("lt", lt, 0x0110001000000000) - fails += expectUint64("le", le, 0x1110011000100000) - fails += expectUint64("eq", eq, 0x1000010000100000) - fails += expectUint64("ne", ne, 0x0111101111011111) - fails += expectUint64("ge", ge, 0x1000110011100000) - fails += expectUint64("gt", gt, 0x0000100011000000) + expectUint64(t, "lt", lt, 0x0110001000000000) + expectUint64(t, "le", le, 0x1110011000100000) + expectUint64(t, "eq", eq, 0x1000010000100000) + expectUint64(t, "ne", ne, 0x0111101111011111) + expectUint64(t, "ge", ge, 0x1000110011100000) + expectUint64(t, "gt", gt, 0x0000100011000000) } - fails += floatingToIntegerConversionsTest() - fails += complexTest128() - fails += complexTest64() - - if fails > 0 { - fmt.Printf("Saw %v failures\n", fails) - panic("Failed.") - } + floatingToIntegerConversionsTest(t) + complexTest128(t) + complexTest64(t) } diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go index cbdd162636..21ad27e880 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/arithBoundaryGen.go @@ -91,10 +91,9 @@ var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, func main() { w := new(bytes.Buffer) - fmt.Fprintf(w, "// run\n") fmt.Fprintf(w, "// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.\n\n") fmt.Fprintf(w, "package main;\n") - fmt.Fprintf(w, "import \"fmt\"\n") + fmt.Fprintf(w, "import \"testing\"\n") for _, sz := range []int{64, 32, 16, 8} { fmt.Fprintf(w, "type utd%d struct {\n", sz) @@ -160,13 +159,12 @@ func main() { } } - fmt.Fprintf(w, "var failed bool\n\n") - fmt.Fprintf(w, "func main() {\n\n") + fmt.Fprintf(w, "//TestArithmeticBoundary tests boundary results for arithmetic operations.\n") + fmt.Fprintf(w, "func TestArithmeticBoundary(t *testing.T) {\n\n") verify, err := template.New("tst").Parse( `if got := {{.Name}}_{{.Stype}}_ssa(v.a, v.b); got != v.{{.Name}} { - fmt.Printf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}}) - failed = true + t.Errorf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}}) } `) @@ -193,10 +191,6 @@ func main() { fmt.Fprint(w, " }\n") } - fmt.Fprintf(w, `if failed { - panic("tests failed") - } -`) fmt.Fprintf(w, "}\n") // gofmt result @@ -208,7 +202,7 @@ func main() { } // write to file - err = ioutil.WriteFile("../arithBoundary.go", src, 0666) + err = ioutil.WriteFile("../arithBoundary_test.go", src, 0666) if err != nil { log.Fatalf("can't write output: %v\n", err) } diff --git a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go index 7fd5c31a13..41b2946480 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/arithConstGen.go @@ -148,11 +148,9 @@ func ansS(i, j int64, t, op string) string { func main() { w := new(bytes.Buffer) - fmt.Fprintf(w, "// run\n") fmt.Fprintf(w, "// Code generated by gen/arithConstGen.go. DO NOT EDIT.\n\n") fmt.Fprintf(w, "package main;\n") - fmt.Fprintf(w, "import \"fmt\"\n") - fmt.Fprintf(w, "import \"os\"\n") + fmt.Fprintf(w, "import \"testing\"\n") fncCnst1 := template.Must(template.New("fnc").Parse( `//go:noinline @@ -313,26 +311,22 @@ type test_%[1]s%[2]s struct { } fmt.Fprint(w, ` -var failed bool -func main() { +// TestArithmeticConst tests results for arithmetic operations against constants. +func TestArithmeticConst(t *testing.T) { `) for _, s := range szs { fmt.Fprintf(w, `for _, test := range tests_%s%s {`, s.name, s.oponly) // Use WriteString here to avoid a vet warning about formatting directives. w.WriteString(`if got := test.fn(test.in); got != test.want { - fmt.Printf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) - failed = true + t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) } } `) } fmt.Fprint(w, ` - if failed { - os.Exit(1) - } } `) @@ -345,7 +339,7 @@ func main() { } // write to file - err = ioutil.WriteFile("../arithConst.go", src, 0666) + err = ioutil.WriteFile("../arithConst_test.go", src, 0666) if err != nil { log.Fatalf("can't write output: %v\n", err) } diff --git a/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go b/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go index defa4a9f7b..5508e76be5 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go @@ -153,10 +153,9 @@ func main() { } w := new(bytes.Buffer) - fmt.Fprintf(w, "// run\n") fmt.Fprintf(w, "// Code generated by gen/cmpConstGen.go. DO NOT EDIT.\n\n") fmt.Fprintf(w, "package main;\n") - fmt.Fprintf(w, "import (\"fmt\"; \"reflect\"; \"runtime\";)\n") + fmt.Fprintf(w, "import (\"testing\"; \"reflect\"; \"runtime\";)\n") fmt.Fprintf(w, "// results show the expected result for the elements left of, equal to and right of the index.\n") fmt.Fprintf(w, "type result struct{l, e, r bool}\n") fmt.Fprintf(w, "var (\n") @@ -215,7 +214,8 @@ func main() { } // emit the main function, looping over all test cases - fmt.Fprintf(w, "func main() {\n") + fmt.Fprintf(w, "// TestComparisonsConst tests results for comparison operations against constants.\n") + fmt.Fprintf(w, "func TestComparisonsConst(t *testing.T) {\n") for _, typ := range types { fmt.Fprintf(w, "for i, test := range %v_tests {\n", typ) fmt.Fprintf(w, " for j, x := range %v_vals {\n", typ) @@ -224,8 +224,7 @@ func main() { fmt.Fprintf(w, " else if j > test.idx {\nwant = test.exp.r\n}\n") fmt.Fprintf(w, " if test.fn(x) != want {\n") fmt.Fprintf(w, " fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()\n") - fmt.Fprintf(w, " msg := fmt.Sprintf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ) - fmt.Fprintf(w, " panic(msg)\n") + fmt.Fprintf(w, " t.Errorf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ) fmt.Fprintf(w, " }\n") fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") @@ -241,7 +240,7 @@ func main() { } // write to file - err = ioutil.WriteFile("../cmpConst.go", src, 0666) + err = ioutil.WriteFile("../cmpConst_test.go", src, 0666) if err != nil { log.Fatalf("can't write output: %v\n", err) } diff --git a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go index 800d081cec..4567f2f97e 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/copyGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/copyGen.go @@ -24,10 +24,9 @@ var usizes = [...]int{2, 3, 4, 5, 6, 7} func main() { w := new(bytes.Buffer) - fmt.Fprintf(w, "// run\n") fmt.Fprintf(w, "// Code generated by gen/copyGen.go. DO NOT EDIT.\n\n") fmt.Fprintf(w, "package main\n") - fmt.Fprintf(w, "import \"fmt\"\n") + fmt.Fprintf(w, "import \"testing\"\n") for _, s := range sizes { // type for test @@ -44,7 +43,7 @@ func main() { fmt.Fprintf(w, "}\n") // testing harness - fmt.Fprintf(w, "func testCopy%d() {\n", s) + fmt.Fprintf(w, "func testCopy%d(t *testing.T) {\n", s) fmt.Fprintf(w, " a := T%d{[8]byte{201, 202, 203, 204, 205, 206, 207, 208},[%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "%d,", i%100) @@ -62,8 +61,7 @@ func main() { } fmt.Fprintf(w, "},[8]byte{211, 212, 213, 214, 215, 216, 217, 218}}\n") fmt.Fprintf(w, " if a != want {\n") - fmt.Fprintf(w, " fmt.Printf(\"t%dcopy got=%%v, want %%v\\n\", a, want)\n", s) - fmt.Fprintf(w, " failed=true\n") + fmt.Fprintf(w, " t.Errorf(\"t%dcopy got=%%v, want %%v\\n\", a, want)\n", s) fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") } @@ -78,7 +76,7 @@ func main() { fmt.Fprintf(w, "}\n") // testing harness - fmt.Fprintf(w, "func testUnalignedCopy%d() {\n", s) + fmt.Fprintf(w, "func testUnalignedCopy%d(t *testing.T) {\n", s) fmt.Fprintf(w, " var a [%d]byte\n", s) fmt.Fprintf(w, " t%d := [%d]byte{", s, s) for i := 0; i < s; i++ { @@ -92,24 +90,19 @@ func main() { } fmt.Fprintf(w, "}\n") fmt.Fprintf(w, " if a != want%d {\n", s) - fmt.Fprintf(w, " fmt.Printf(\"tu%dcopy got=%%v, want %%v\\n\", a, want%d)\n", s, s) - fmt.Fprintf(w, " failed=true\n") + fmt.Fprintf(w, " t.Errorf(\"tu%dcopy got=%%v, want %%v\\n\", a, want%d)\n", s, s) fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") } // boilerplate at end - fmt.Fprintf(w, "var failed bool\n") - fmt.Fprintf(w, "func main() {\n") + fmt.Fprintf(w, "func TestCopy(t *testing.T) {\n") for _, s := range sizes { - fmt.Fprintf(w, " testCopy%d()\n", s) + fmt.Fprintf(w, " testCopy%d(t)\n", s) } for _, s := range usizes { - fmt.Fprintf(w, " testUnalignedCopy%d()\n", s) + fmt.Fprintf(w, " testUnalignedCopy%d(t)\n", s) } - fmt.Fprintf(w, " if failed {\n") - fmt.Fprintf(w, " panic(\"failed\")\n") - fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") // gofmt result @@ -121,7 +114,7 @@ func main() { } // write to file - err = ioutil.WriteFile("../copy.go", src, 0666) + err = ioutil.WriteFile("../copy_test.go", src, 0666) if err != nil { log.Fatalf("can't write output: %v\n", err) } diff --git a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go index c764c369e6..7056730cb9 100644 --- a/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go +++ b/src/cmd/compile/internal/gc/testdata/gen/zeroGen.go @@ -23,14 +23,13 @@ var usizes = [...]int{8, 16, 24, 32, 64, 256} func main() { w := new(bytes.Buffer) - fmt.Fprintf(w, "// run\n") fmt.Fprintf(w, "// Code generated by gen/zeroGen.go. DO NOT EDIT.\n\n") fmt.Fprintf(w, "package main\n") - fmt.Fprintf(w, "import \"fmt\"\n") + fmt.Fprintf(w, "import \"testing\"\n") for _, s := range sizes { // type for test - fmt.Fprintf(w, "type T%d struct {\n", s) + fmt.Fprintf(w, "type Z%d struct {\n", s) fmt.Fprintf(w, " pre [8]byte\n") fmt.Fprintf(w, " mid [%d]byte\n", s) fmt.Fprintf(w, " post [8]byte\n") @@ -43,96 +42,89 @@ func main() { fmt.Fprintf(w, "}\n") // testing harness - fmt.Fprintf(w, "func testZero%d() {\n", s) - fmt.Fprintf(w, " a := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s) + fmt.Fprintf(w, "func testZero%d(t *testing.T) {\n", s) + fmt.Fprintf(w, " a := Z%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "255,") } fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n") fmt.Fprintf(w, " zero%d_ssa(&a.mid)\n", s) - fmt.Fprintf(w, " want := T%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s) + fmt.Fprintf(w, " want := Z%d{[8]byte{255,255,255,255,255,255,255,255},[%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "0,") } fmt.Fprintf(w, "},[8]byte{255,255,255,255,255,255,255,255}}\n") fmt.Fprintf(w, " if a != want {\n") - fmt.Fprintf(w, " fmt.Printf(\"zero%d got=%%v, want %%v\\n\", a, want)\n", s) - fmt.Fprintf(w, " failed=true\n") + fmt.Fprintf(w, " t.Errorf(\"zero%d got=%%v, want %%v\\n\", a, want)\n", s) fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") } for _, s := range usizes { // type for test - fmt.Fprintf(w, "type T%du1 struct {\n", s) + fmt.Fprintf(w, "type Z%du1 struct {\n", s) fmt.Fprintf(w, " b bool\n") fmt.Fprintf(w, " val [%d]byte\n", s) fmt.Fprintf(w, "}\n") - fmt.Fprintf(w, "type T%du2 struct {\n", s) + fmt.Fprintf(w, "type Z%du2 struct {\n", s) fmt.Fprintf(w, " i uint16\n") fmt.Fprintf(w, " val [%d]byte\n", s) fmt.Fprintf(w, "}\n") // function being tested fmt.Fprintf(w, "//go:noinline\n") - fmt.Fprintf(w, "func zero%du1_ssa(t *T%du1) {\n", s, s) + fmt.Fprintf(w, "func zero%du1_ssa(t *Z%du1) {\n", s, s) fmt.Fprintf(w, " t.val = [%d]byte{}\n", s) fmt.Fprintf(w, "}\n") // function being tested fmt.Fprintf(w, "//go:noinline\n") - fmt.Fprintf(w, "func zero%du2_ssa(t *T%du2) {\n", s, s) + fmt.Fprintf(w, "func zero%du2_ssa(t *Z%du2) {\n", s, s) fmt.Fprintf(w, " t.val = [%d]byte{}\n", s) fmt.Fprintf(w, "}\n") // testing harness - fmt.Fprintf(w, "func testZero%du() {\n", s) - fmt.Fprintf(w, " a := T%du1{false, [%d]byte{", s, s) + fmt.Fprintf(w, "func testZero%du(t *testing.T) {\n", s) + fmt.Fprintf(w, " a := Z%du1{false, [%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "255,") } fmt.Fprintf(w, "}}\n") fmt.Fprintf(w, " zero%du1_ssa(&a)\n", s) - fmt.Fprintf(w, " want := T%du1{false, [%d]byte{", s, s) + fmt.Fprintf(w, " want := Z%du1{false, [%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "0,") } fmt.Fprintf(w, "}}\n") fmt.Fprintf(w, " if a != want {\n") - fmt.Fprintf(w, " fmt.Printf(\"zero%du2 got=%%v, want %%v\\n\", a, want)\n", s) - fmt.Fprintf(w, " failed=true\n") + fmt.Fprintf(w, " t.Errorf(\"zero%du2 got=%%v, want %%v\\n\", a, want)\n", s) fmt.Fprintf(w, " }\n") - fmt.Fprintf(w, " b := T%du2{15, [%d]byte{", s, s) + fmt.Fprintf(w, " b := Z%du2{15, [%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "255,") } fmt.Fprintf(w, "}}\n") fmt.Fprintf(w, " zero%du2_ssa(&b)\n", s) - fmt.Fprintf(w, " wantb := T%du2{15, [%d]byte{", s, s) + fmt.Fprintf(w, " wantb := Z%du2{15, [%d]byte{", s, s) for i := 0; i < s; i++ { fmt.Fprintf(w, "0,") } fmt.Fprintf(w, "}}\n") fmt.Fprintf(w, " if b != wantb {\n") - fmt.Fprintf(w, " fmt.Printf(\"zero%du2 got=%%v, want %%v\\n\", b, wantb)\n", s) - fmt.Fprintf(w, " failed=true\n") + fmt.Fprintf(w, " t.Errorf(\"zero%du2 got=%%v, want %%v\\n\", b, wantb)\n", s) fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") } // boilerplate at end - fmt.Fprintf(w, "var failed bool\n") - fmt.Fprintf(w, "func main() {\n") + fmt.Fprintf(w, "func TestZero(t *testing.T) {\n") for _, s := range sizes { - fmt.Fprintf(w, " testZero%d()\n", s) + fmt.Fprintf(w, " testZero%d(t)\n", s) } for _, s := range usizes { - fmt.Fprintf(w, " testZero%du()\n", s) + fmt.Fprintf(w, " testZero%du(t)\n", s) } - fmt.Fprintf(w, " if failed {\n") - fmt.Fprintf(w, " panic(\"failed\")\n") - fmt.Fprintf(w, " }\n") fmt.Fprintf(w, "}\n") // gofmt result @@ -144,7 +136,7 @@ func main() { } // write to file - err = ioutil.WriteFile("../zero.go", src, 0666) + err = ioutil.WriteFile("../zero_test.go", src, 0666) if err != nil { log.Fatalf("can't write output: %v\n", err) } diff --git a/src/cmd/compile/internal/gc/testdata/loadstore.go b/src/cmd/compile/internal/gc/testdata/loadstore_test.go similarity index 75% rename from src/cmd/compile/internal/gc/testdata/loadstore.go rename to src/cmd/compile/internal/gc/testdata/loadstore_test.go index dcb61d4b7e..57571f5d17 100644 --- a/src/cmd/compile/internal/gc/testdata/loadstore.go +++ b/src/cmd/compile/internal/gc/testdata/loadstore_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,14 +6,13 @@ package main -import "fmt" +import "testing" // testLoadStoreOrder tests for reordering of stores/loads. -func testLoadStoreOrder() { +func testLoadStoreOrder(t *testing.T) { z := uint32(1000) if testLoadStoreOrder_ssa(&z, 100) == 0 { - println("testLoadStoreOrder failed") - failed = true + t.Errorf("testLoadStoreOrder failed") } } @@ -29,13 +26,12 @@ func testLoadStoreOrder_ssa(z *uint32, prec uint) int { return 0 } -func testStoreSize() { +func testStoreSize(t *testing.T) { a := [4]uint16{11, 22, 33, 44} testStoreSize_ssa(&a[0], &a[2], 77) want := [4]uint16{77, 22, 33, 44} if a != want { - fmt.Println("testStoreSize failed. want =", want, ", got =", a) - failed = true + t.Errorf("testStoreSize failed. want = %d, got = %d", want, a) } } @@ -55,8 +51,6 @@ func testStoreSize_ssa(p *uint16, q *uint16, v uint32) { } } -var failed = false - //go:noinline func testExtStore_ssa(p *byte, b bool) int { x := *p @@ -67,12 +61,11 @@ func testExtStore_ssa(p *byte, b bool) int { return 0 } -func testExtStore() { +func testExtStore(t *testing.T) { const start = 8 var b byte = start if got := testExtStore_ssa(&b, true); got != start { - fmt.Println("testExtStore failed. want =", start, ", got =", got) - failed = true + t.Errorf("testExtStore failed. want = %d, got = %d", start, got) } } @@ -95,10 +88,9 @@ func testDeadStorePanic_ssa(a int) (r int) { return } -func testDeadStorePanic() { +func testDeadStorePanic(t *testing.T) { if want, got := 2, testDeadStorePanic_ssa(1); want != got { - fmt.Println("testDeadStorePanic failed. want =", want, ", got =", got) - failed = true + t.Errorf("testDeadStorePanic failed. want = %d, got = %d", want, got) } } @@ -144,7 +136,7 @@ func loadHitStoreU32(x uint32, p *uint32) uint64 { return uint64(*p) // load and cast } -func testLoadHitStore() { +func testLoadHitStore(t *testing.T) { // Test that sign/zero extensions are kept when a load-hit-store // is replaced by a register-register move. { @@ -153,8 +145,7 @@ func testLoadHitStore() { got := loadHitStore8(in, &p) want := int32(in * in) if got != want { - fmt.Println("testLoadHitStore (int8) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (int8) failed. want = %d, got = %d", want, got) } } { @@ -163,8 +154,7 @@ func testLoadHitStore() { got := loadHitStoreU8(in, &p) want := uint32(in * in) if got != want { - fmt.Println("testLoadHitStore (uint8) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (uint8) failed. want = %d, got = %d", want, got) } } { @@ -173,8 +163,7 @@ func testLoadHitStore() { got := loadHitStore16(in, &p) want := int32(in * in) if got != want { - fmt.Println("testLoadHitStore (int16) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (int16) failed. want = %d, got = %d", want, got) } } { @@ -183,8 +172,7 @@ func testLoadHitStore() { got := loadHitStoreU16(in, &p) want := uint32(in * in) if got != want { - fmt.Println("testLoadHitStore (uint16) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (uint16) failed. want = %d, got = %d", want, got) } } { @@ -193,8 +181,7 @@ func testLoadHitStore() { got := loadHitStore32(in, &p) want := int64(in * in) if got != want { - fmt.Println("testLoadHitStore (int32) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (int32) failed. want = %d, got = %d", want, got) } } { @@ -203,21 +190,15 @@ func testLoadHitStore() { got := loadHitStoreU32(in, &p) want := uint64(in * in) if got != want { - fmt.Println("testLoadHitStore (uint32) failed. want =", want, ", got =", got) - failed = true + t.Errorf("testLoadHitStore (uint32) failed. want = %d, got = %d", want, got) } } } -func main() { - - testLoadStoreOrder() - testStoreSize() - testExtStore() - testDeadStorePanic() - testLoadHitStore() - - if failed { - panic("failed") - } +func TestLoadStore(t *testing.T) { + testLoadStoreOrder(t) + testStoreSize(t) + testExtStore(t) + testDeadStorePanic(t) + testLoadHitStore(t) } diff --git a/src/cmd/compile/internal/gc/testdata/map.go b/src/cmd/compile/internal/gc/testdata/map_test.go similarity index 55% rename from src/cmd/compile/internal/gc/testdata/map.go rename to src/cmd/compile/internal/gc/testdata/map_test.go index 4a466003c7..71dc820c1c 100644 --- a/src/cmd/compile/internal/gc/testdata/map.go +++ b/src/cmd/compile/internal/gc/testdata/map_test.go @@ -2,19 +2,17 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// map_ssa.go tests map operations. +// map.go tests map operations. package main -import "fmt" - -var failed = false +import "testing" //go:noinline func lenMap_ssa(v map[int]int) int { return len(v) } -func testLenMap() { +func testLenMap(t *testing.T) { v := make(map[int]int) v[0] = 0 @@ -22,24 +20,18 @@ func testLenMap() { v[2] = 0 if want, got := 3, lenMap_ssa(v); got != want { - fmt.Printf("expected len(map) = %d, got %d", want, got) - failed = true + t.Errorf("expected len(map) = %d, got %d", want, got) } } -func testLenNilMap() { +func testLenNilMap(t *testing.T) { var v map[int]int if want, got := 0, lenMap_ssa(v); got != want { - fmt.Printf("expected len(nil) = %d, got %d", want, got) - failed = true + t.Errorf("expected len(nil) = %d, got %d", want, got) } } -func main() { - testLenMap() - testLenNilMap() - - if failed { - panic("failed") - } +func TestMap(t *testing.T) { + testLenMap(t) + testLenNilMap(t) } diff --git a/src/cmd/compile/internal/gc/testdata/namedReturn.go b/src/cmd/compile/internal/gc/testdata/namedReturn_test.go similarity index 69% rename from src/cmd/compile/internal/gc/testdata/namedReturn.go rename to src/cmd/compile/internal/gc/testdata/namedReturn_test.go index 19ef8a7e43..b07e225c1c 100644 --- a/src/cmd/compile/internal/gc/testdata/namedReturn.go +++ b/src/cmd/compile/internal/gc/testdata/namedReturn_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -11,8 +9,8 @@ package main import ( - "fmt" "runtime" + "testing" ) // Our heap-allocated object that will be GC'd incorrectly. @@ -21,44 +19,44 @@ import ( type B [4]int // small (SSAable) array -type T1 [3]*B +type A1 [3]*B //go:noinline -func f1() (t T1) { +func f1() (t A1) { t[0] = &B{91, 92, 93, 94} runtime.GC() return t } // large (non-SSAable) array -type T2 [8]*B +type A2 [8]*B //go:noinline -func f2() (t T2) { +func f2() (t A2) { t[0] = &B{91, 92, 93, 94} runtime.GC() return t } // small (SSAable) struct -type T3 struct { +type A3 struct { a, b, c *B } //go:noinline -func f3() (t T3) { +func f3() (t A3) { t.a = &B{91, 92, 93, 94} runtime.GC() return t } // large (non-SSAable) struct -type T4 struct { +type A4 struct { a, b, c, d, e, f *B } //go:noinline -func f4() (t T4) { +func f4() (t A4) { t.a = &B{91, 92, 93, 94} runtime.GC() return t @@ -68,7 +66,7 @@ var sink *B func f5() int { b := &B{91, 92, 93, 94} - t := T4{b, nil, nil, nil, nil, nil} + t := A4{b, nil, nil, nil, nil, nil} sink = b // make sure b is heap allocated ... sink = nil // ... but not live runtime.GC() @@ -76,30 +74,20 @@ func f5() int { return t.a[1] } -func main() { - failed := false - +func TestNamedReturn(t *testing.T) { if v := f1()[0][1]; v != 92 { - fmt.Printf("f1()[0][1]=%d, want 92\n", v) - failed = true + t.Errorf("f1()[0][1]=%d, want 92\n", v) } if v := f2()[0][1]; v != 92 { - fmt.Printf("f2()[0][1]=%d, want 92\n", v) - failed = true + t.Errorf("f2()[0][1]=%d, want 92\n", v) } if v := f3().a[1]; v != 92 { - fmt.Printf("f3().a[1]=%d, want 92\n", v) - failed = true + t.Errorf("f3().a[1]=%d, want 92\n", v) } if v := f4().a[1]; v != 92 { - fmt.Printf("f4().a[1]=%d, want 92\n", v) - failed = true + t.Errorf("f4().a[1]=%d, want 92\n", v) } if v := f5(); v != 92 { - fmt.Printf("f5()=%d, want 92\n", v) - failed = true - } - if failed { - panic("bad") + t.Errorf("f5()=%d, want 92\n", v) } } diff --git a/src/cmd/compile/internal/gc/testdata/phi.go b/src/cmd/compile/internal/gc/testdata/phi_test.go similarity index 94% rename from src/cmd/compile/internal/gc/testdata/phi.go rename to src/cmd/compile/internal/gc/testdata/phi_test.go index 6469bfea44..c8a73ffd74 100644 --- a/src/cmd/compile/internal/gc/testdata/phi.go +++ b/src/cmd/compile/internal/gc/testdata/phi_test.go @@ -9,13 +9,10 @@ package main // of the post-shortened size. import ( - "fmt" "runtime" + "testing" ) -// unfoldable true -var true_ = true - var data1 [26]int32 var data2 [26]int64 @@ -29,7 +26,7 @@ func init() { func foo() int32 { var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z int32 - if true_ { + if always { a = data1[0] b = data1[1] c = data1[2] @@ -93,11 +90,10 @@ func foo() int32 { return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r + s + t + u + v + w + x + y + z } -func main() { +func TestPhi(t *testing.T) { want := int32(0) got := foo() if got != want { - fmt.Printf("want %d, got %d\n", want, got) - panic("bad") + t.Fatalf("want %d, got %d\n", want, got) } } diff --git a/src/cmd/compile/internal/gc/testdata/regalloc.go b/src/cmd/compile/internal/gc/testdata/regalloc_test.go similarity index 76% rename from src/cmd/compile/internal/gc/testdata/regalloc.go rename to src/cmd/compile/internal/gc/testdata/regalloc_test.go index f752692952..577f8e7684 100644 --- a/src/cmd/compile/internal/gc/testdata/regalloc.go +++ b/src/cmd/compile/internal/gc/testdata/regalloc_test.go @@ -1,5 +1,3 @@ -// run - // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. @@ -8,6 +6,8 @@ package main +import "testing" + func phiOverwrite_ssa() int { var n int for i := 0; i < 10; i++ { @@ -19,12 +19,11 @@ func phiOverwrite_ssa() int { return n } -func phiOverwrite() { +func phiOverwrite(t *testing.T) { want := 5 got := phiOverwrite_ssa() if got != want { - println("phiOverwrite_ssa()=", want, ", got", got) - failed = true + t.Errorf("phiOverwrite_ssa()= %d, got %d", want, got) } } @@ -37,21 +36,15 @@ func phiOverwriteBig_ssa() int { return a*1 + b*2 + c*3 + d*4 + e*5 + f*6 + g*7 + h*8 + i*9 + j*10 + k*11 + l*12 + m*13 + n*14 + o*15 + p*16 + q*17 + r*18 + s*19 + t*20 + u*21 + v*22 + w*23 + x*24 + y*25 + z*26 } -func phiOverwriteBig() { +func phiOverwriteBig(t *testing.T) { want := 1 got := phiOverwriteBig_ssa() if got != want { - println("phiOverwriteBig_ssa()=", want, ", got", got) - failed = true + t.Errorf("phiOverwriteBig_ssa()= %d, got %d", want, got) } } -var failed = false - -func main() { - phiOverwrite() - phiOverwriteBig() - if failed { - panic("failed") - } +func TestRegalloc(t *testing.T) { + phiOverwrite(t) + phiOverwriteBig(t) } diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go new file mode 100644 index 0000000000..817f4a640e --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue27013.go @@ -0,0 +1,15 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package p + +func A(arg interface{}) { + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) + _ = arg.(interface{ Func() int32 }) +} diff --git a/src/cmd/compile/internal/gc/testdata/short.go b/src/cmd/compile/internal/gc/testdata/short.go deleted file mode 100644 index fcec1baf09..0000000000 --- a/src/cmd/compile/internal/gc/testdata/short.go +++ /dev/null @@ -1,60 +0,0 @@ -// run - -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Tests short circuiting. - -package main - -func and_ssa(arg1, arg2 bool) bool { - return arg1 && rightCall(arg2) -} - -func or_ssa(arg1, arg2 bool) bool { - return arg1 || rightCall(arg2) -} - -var rightCalled bool - -//go:noinline -func rightCall(v bool) bool { - rightCalled = true - return v - panic("unreached") -} - -func testAnd(arg1, arg2, wantRes bool) { testShortCircuit("AND", arg1, arg2, and_ssa, arg1, wantRes) } -func testOr(arg1, arg2, wantRes bool) { testShortCircuit("OR", arg1, arg2, or_ssa, !arg1, wantRes) } - -func testShortCircuit(opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) { - rightCalled = false - got := fn(arg1, arg2) - if rightCalled != wantRightCall { - println("failed for", arg1, opName, arg2, "; rightCalled=", rightCalled, "want=", wantRightCall) - failed = true - } - if wantRes != got { - println("failed for", arg1, opName, arg2, "; res=", got, "want=", wantRes) - failed = true - } -} - -var failed = false - -func main() { - testAnd(false, false, false) - testAnd(false, true, false) - testAnd(true, false, false) - testAnd(true, true, true) - - testOr(false, false, false) - testOr(false, true, true) - testOr(true, false, true) - testOr(true, true, true) - - if failed { - panic("failed") - } -} diff --git a/src/cmd/compile/internal/gc/testdata/short_test.go b/src/cmd/compile/internal/gc/testdata/short_test.go new file mode 100644 index 0000000000..7a743b5d19 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/short_test.go @@ -0,0 +1,57 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Tests short circuiting. + +package main + +import "testing" + +func and_ssa(arg1, arg2 bool) bool { + return arg1 && rightCall(arg2) +} + +func or_ssa(arg1, arg2 bool) bool { + return arg1 || rightCall(arg2) +} + +var rightCalled bool + +//go:noinline +func rightCall(v bool) bool { + rightCalled = true + return v + panic("unreached") +} + +func testAnd(t *testing.T, arg1, arg2, wantRes bool) { + testShortCircuit(t, "AND", arg1, arg2, and_ssa, arg1, wantRes) +} +func testOr(t *testing.T, arg1, arg2, wantRes bool) { + testShortCircuit(t, "OR", arg1, arg2, or_ssa, !arg1, wantRes) +} + +func testShortCircuit(t *testing.T, opName string, arg1, arg2 bool, fn func(bool, bool) bool, wantRightCall, wantRes bool) { + rightCalled = false + got := fn(arg1, arg2) + if rightCalled != wantRightCall { + t.Errorf("failed for %t %s %t; rightCalled=%t want=%t", arg1, opName, arg2, rightCalled, wantRightCall) + } + if wantRes != got { + t.Errorf("failed for %t %s %t; res=%t want=%t", arg1, opName, arg2, got, wantRes) + } +} + +// TestShortCircuit tests OANDAND and OOROR expressions and short circuiting. +func TestShortCircuit(t *testing.T) { + testAnd(t, false, false, false) + testAnd(t, false, true, false) + testAnd(t, true, false, false) + testAnd(t, true, true, true) + + testOr(t, false, false, false) + testOr(t, false, true, true) + testOr(t, true, false, true) + testOr(t, true, true, true) +} diff --git a/src/cmd/compile/internal/gc/testdata/slice.go b/src/cmd/compile/internal/gc/testdata/slice.go deleted file mode 100644 index a02e4a442a..0000000000 --- a/src/cmd/compile/internal/gc/testdata/slice.go +++ /dev/null @@ -1,50 +0,0 @@ -// run - -// This test makes sure that t.s = t.s[0:x] doesn't write -// either the slice pointer or the capacity. -// See issue #14855. - -package main - -import "fmt" - -const N = 1000000 - -type T struct { - s []int -} - -func main() { - done := make(chan struct{}) - a := make([]int, N+10) - - t := &T{a} - - go func() { - for i := 0; i < N; i++ { - t.s = t.s[1:9] - } - done <- struct{}{} - }() - go func() { - for i := 0; i < N; i++ { - t.s = t.s[0:8] // should only write len - } - done <- struct{}{} - }() - <-done - <-done - - ok := true - if cap(t.s) != cap(a)-N { - fmt.Printf("wanted cap=%d, got %d\n", cap(a)-N, cap(t.s)) - ok = false - } - if &t.s[0] != &a[N] { - fmt.Printf("wanted ptr=%p, got %p\n", &a[N], &t.s[0]) - ok = false - } - if !ok { - panic("bad") - } -} diff --git a/src/cmd/compile/internal/gc/testdata/slice_test.go b/src/cmd/compile/internal/gc/testdata/slice_test.go new file mode 100644 index 0000000000..c134578034 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/slice_test.go @@ -0,0 +1,46 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This test makes sure that t.s = t.s[0:x] doesn't write +// either the slice pointer or the capacity. +// See issue #14855. + +package main + +import "testing" + +const N = 1000000 + +type X struct { + s []int +} + +func TestSlice(t *testing.T) { + done := make(chan struct{}) + a := make([]int, N+10) + + x := &X{a} + + go func() { + for i := 0; i < N; i++ { + x.s = x.s[1:9] + } + done <- struct{}{} + }() + go func() { + for i := 0; i < N; i++ { + x.s = x.s[0:8] // should only write len + } + done <- struct{}{} + }() + <-done + <-done + + if cap(x.s) != cap(a)-N { + t.Errorf("wanted cap=%d, got %d\n", cap(a)-N, cap(x.s)) + } + if &x.s[0] != &a[N] { + t.Errorf("wanted ptr=%p, got %p\n", &a[N], &x.s[0]) + } +} diff --git a/src/cmd/compile/internal/gc/testdata/sqrt_const.go b/src/cmd/compile/internal/gc/testdata/sqrtConst_test.go similarity index 73% rename from src/cmd/compile/internal/gc/testdata/sqrt_const.go rename to src/cmd/compile/internal/gc/testdata/sqrtConst_test.go index 1f25d9aded..5b7a149e42 100644 --- a/src/cmd/compile/internal/gc/testdata/sqrt_const.go +++ b/src/cmd/compile/internal/gc/testdata/sqrtConst_test.go @@ -5,8 +5,8 @@ package main import ( - "fmt" "math" + "testing" ) var tests = [...]struct { @@ -33,27 +33,18 @@ var nanTests = [...]struct { {"sqrtNegInf", math.Inf(-1), math.Sqrt(math.Inf(-1))}, } -var failed = false - -func main() { +func TestSqrtConst(t *testing.T) { for _, test := range tests { if test.got != test.want { - fmt.Printf("%s: math.Sqrt(%f): got %f, want %f\n", test.name, test.in, test.got, test.want) - failed = true + t.Errorf("%s: math.Sqrt(%f): got %f, want %f\n", test.name, test.in, test.got, test.want) } } for _, test := range nanTests { if math.IsNaN(test.got) != true { - fmt.Printf("%s: math.Sqrt(%f): got %f, want NaN\n", test.name, test.in, test.got) - failed = true + t.Errorf("%s: math.Sqrt(%f): got %f, want NaN\n", test.name, test.in, test.got) } } if got := math.Sqrt(math.Inf(1)); !math.IsInf(got, 1) { - fmt.Printf("math.Sqrt(+Inf), got %f, want +Inf\n", got) - failed = true - } - - if failed { - panic("failed") + t.Errorf("math.Sqrt(+Inf), got %f, want +Inf\n", got) } } diff --git a/src/cmd/compile/internal/gc/testdata/string.go b/src/cmd/compile/internal/gc/testdata/string_test.go similarity index 58% rename from src/cmd/compile/internal/gc/testdata/string.go rename to src/cmd/compile/internal/gc/testdata/string_test.go index 03053a6134..5d086f0147 100644 --- a/src/cmd/compile/internal/gc/testdata/string.go +++ b/src/cmd/compile/internal/gc/testdata/string_test.go @@ -5,7 +5,7 @@ // string_ssa.go tests string operations. package main -var failed = false +import "testing" //go:noinline func testStringSlice1_ssa(a string, i, j int) string { @@ -22,7 +22,7 @@ func testStringSlice12_ssa(a string, i, j int) string { return a[i:j] } -func testStringSlice() { +func testStringSlice(t *testing.T) { tests := [...]struct { fn func(string, int, int) string s string @@ -44,10 +44,9 @@ func testStringSlice() { {testStringSlice12_ssa, "", 0, 0, ""}, } - for i, t := range tests { - if got := t.fn(t.s, t.low, t.high); t.want != got { - println("#", i, " ", t.s, "[", t.low, ":", t.high, "] = ", got, " want ", t.want) - failed = true + for i, test := range tests { + if got := test.fn(test.s, test.low, test.high); test.want != got { + t.Errorf("#%d %s[%d,%d] = %s, want %s", i, test.s, test.low, test.high, got, test.want) } } } @@ -61,26 +60,23 @@ func (p *prefix) slice_ssa() { } //go:noinline -func testStructSlice() { +func testStructSlice(t *testing.T) { p := &prefix{"prefix"} p.slice_ssa() if "pre" != p.prefix { - println("wrong field slice: wanted %s got %s", "pre", p.prefix) - failed = true + t.Errorf("wrong field slice: wanted %s got %s", "pre", p.prefix) } } -func testStringSlicePanic() { +func testStringSlicePanic(t *testing.T) { defer func() { if r := recover(); r != nil { - println("panicked as expected") + //println("panicked as expected") } }() str := "foobar" - println("got ", testStringSlice12_ssa(str, 3, 9)) - println("expected to panic, but didn't") - failed = true + t.Errorf("got %s and expected to panic, but didn't", testStringSlice12_ssa(str, 3, 9)) } const _Accuracy_name = "BelowExactAbove" @@ -92,7 +88,7 @@ func testSmallIndexType_ssa(i int) string { return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]] } -func testSmallIndexType() { +func testSmallIndexType(t *testing.T) { tests := []struct { i int want string @@ -102,10 +98,9 @@ func testSmallIndexType() { {2, "Above"}, } - for i, t := range tests { - if got := testSmallIndexType_ssa(t.i); got != t.want { - println("#", i, "got ", got, ", wanted", t.want) - failed = true + for i, test := range tests { + if got := testSmallIndexType_ssa(test.i); got != test.want { + t.Errorf("#%d got %s wanted %s", i, got, test.want) } } } @@ -120,7 +115,7 @@ func testInt64Slice_ssa(s string, i, j int64) string { return s[i:j] } -func testInt64Index() { +func testInt64Index(t *testing.T) { tests := []struct { i int64 j int64 @@ -133,42 +128,36 @@ func testInt64Index() { } str := "BelowExactAbove" - for i, t := range tests { - if got := testInt64Index_ssa(str, t.i); got != t.b { - println("#", i, "got ", got, ", wanted", t.b) - failed = true + for i, test := range tests { + if got := testInt64Index_ssa(str, test.i); got != test.b { + t.Errorf("#%d got %d wanted %d", i, got, test.b) } - if got := testInt64Slice_ssa(str, t.i, t.j); got != t.s { - println("#", i, "got ", got, ", wanted", t.s) - failed = true + if got := testInt64Slice_ssa(str, test.i, test.j); got != test.s { + t.Errorf("#%d got %s wanted %s", i, got, test.s) } } } -func testInt64IndexPanic() { +func testInt64IndexPanic(t *testing.T) { defer func() { if r := recover(); r != nil { - println("panicked as expected") + //println("panicked as expected") } }() str := "foobar" - println("got ", testInt64Index_ssa(str, 1<<32+1)) - println("expected to panic, but didn't") - failed = true + t.Errorf("got %d and expected to panic, but didn't", testInt64Index_ssa(str, 1<<32+1)) } -func testInt64SlicePanic() { +func testInt64SlicePanic(t *testing.T) { defer func() { if r := recover(); r != nil { - println("panicked as expected") + //println("panicked as expected") } }() str := "foobar" - println("got ", testInt64Slice_ssa(str, 1<<32, 1<<32+1)) - println("expected to panic, but didn't") - failed = true + t.Errorf("got %s and expected to panic, but didn't", testInt64Slice_ssa(str, 1<<32, 1<<32+1)) } //go:noinline @@ -176,7 +165,7 @@ func testStringElem_ssa(s string, i int) byte { return s[i] } -func testStringElem() { +func testStringElem(t *testing.T) { tests := []struct { s string i int @@ -186,10 +175,9 @@ func testStringElem() { {"foobar", 0, 102}, {"foobar", 5, 114}, } - for _, t := range tests { - if got := testStringElem_ssa(t.s, t.i); got != t.n { - print("testStringElem \"", t.s, "\"[", t.i, "]=", got, ", wanted ", t.n, "\n") - failed = true + for _, test := range tests { + if got := testStringElem_ssa(test.s, test.i); got != test.n { + t.Errorf("testStringElem \"%s\"[%d] = %d, wanted %d", test.s, test.i, got, test.n) } } } @@ -200,25 +188,20 @@ func testStringElemConst_ssa(i int) byte { return s[i] } -func testStringElemConst() { +func testStringElemConst(t *testing.T) { if got := testStringElemConst_ssa(3); got != 98 { - println("testStringElemConst=", got, ", wanted 98") - failed = true + t.Errorf("testStringElemConst= %d, wanted 98", got) } } -func main() { - testStringSlice() - testStringSlicePanic() - testStructSlice() - testSmallIndexType() - testStringElem() - testStringElemConst() - testInt64Index() - testInt64IndexPanic() - testInt64SlicePanic() - - if failed { - panic("failed") - } +func TestString(t *testing.T) { + testStringSlice(t) + testStringSlicePanic(t) + testStructSlice(t) + testSmallIndexType(t) + testStringElem(t) + testStringElemConst(t) + testInt64Index(t) + testInt64IndexPanic(t) + testInt64SlicePanic(t) } diff --git a/src/cmd/compile/internal/gc/testdata/unsafe.go b/src/cmd/compile/internal/gc/testdata/unsafe_test.go similarity index 88% rename from src/cmd/compile/internal/gc/testdata/unsafe.go rename to src/cmd/compile/internal/gc/testdata/unsafe_test.go index a3d9dbcc39..37599d3fd4 100644 --- a/src/cmd/compile/internal/gc/testdata/unsafe.go +++ b/src/cmd/compile/internal/gc/testdata/unsafe_test.go @@ -5,8 +5,8 @@ package main import ( - "fmt" "runtime" + "testing" "unsafe" ) @@ -14,7 +14,7 @@ import ( var a *[8]uint // unfoldable true -var b = true +var always = true // Test to make sure that a pointer value which is alive // across a call is retained, even when there are matching @@ -25,7 +25,7 @@ var b = true func f_ssa() *[8]uint { // Make x a uintptr pointing to where a points. var x uintptr - if b { + if always { x = uintptr(unsafe.Pointer(a)) } else { x = 0 @@ -48,7 +48,7 @@ func f_ssa() *[8]uint { // to unsafe.Pointer can't be combined with the // uintptr cast above. var z uintptr - if b { + if always { z = y } else { z = 0 @@ -61,7 +61,7 @@ func f_ssa() *[8]uint { func g_ssa() *[7]uint { // Make x a uintptr pointing to where a points. var x uintptr - if b { + if always { x = uintptr(unsafe.Pointer(a)) } else { x = 0 @@ -87,7 +87,7 @@ func g_ssa() *[7]uint { // to unsafe.Pointer can't be combined with the // uintptr cast above. var z uintptr - if b { + if always { z = y } else { z = 0 @@ -95,7 +95,7 @@ func g_ssa() *[7]uint { return (*[7]uint)(unsafe.Pointer(z)) } -func testf() { +func testf(t *testing.T) { a = new([8]uint) for i := 0; i < 8; i++ { a[i] = 0xabcd @@ -103,13 +103,12 @@ func testf() { c := f_ssa() for i := 0; i < 8; i++ { if c[i] != 0xabcd { - fmt.Printf("%d:%x\n", i, c[i]) - panic("bad c") + t.Fatalf("%d:%x\n", i, c[i]) } } } -func testg() { +func testg(t *testing.T) { a = new([8]uint) for i := 0; i < 8; i++ { a[i] = 0xabcd @@ -117,8 +116,7 @@ func testg() { c := g_ssa() for i := 0; i < 7; i++ { if c[i] != 0xabcd { - fmt.Printf("%d:%x\n", i, c[i]) - panic("bad c") + t.Fatalf("%d:%x\n", i, c[i]) } } } @@ -130,19 +128,18 @@ func alias_ssa(ui64 *uint64, ui32 *uint32) uint32 { *ui64 = 0xffffffffffffffff // store return ret } -func testdse() { +func testdse(t *testing.T) { x := int64(-1) // construct two pointers that alias one another ui64 := (*uint64)(unsafe.Pointer(&x)) ui32 := (*uint32)(unsafe.Pointer(&x)) if want, got := uint32(0), alias_ssa(ui64, ui32); got != want { - fmt.Printf("alias_ssa: wanted %d, got %d\n", want, got) - panic("alias_ssa") + t.Fatalf("alias_ssa: wanted %d, got %d\n", want, got) } } -func main() { - testf() - testg() - testdse() +func TestUnsafe(t *testing.T) { + testf(t) + testg(t) + testdse(t) } diff --git a/src/cmd/compile/internal/gc/testdata/zero.go b/src/cmd/compile/internal/gc/testdata/zero_test.go similarity index 81% rename from src/cmd/compile/internal/gc/testdata/zero.go rename to src/cmd/compile/internal/gc/testdata/zero_test.go index 9d261aa401..64fa25eed0 100644 --- a/src/cmd/compile/internal/gc/testdata/zero.go +++ b/src/cmd/compile/internal/gc/testdata/zero_test.go @@ -1,11 +1,10 @@ -// run // Code generated by gen/zeroGen.go. DO NOT EDIT. package main -import "fmt" +import "testing" -type T1 struct { +type Z1 struct { pre [8]byte mid [1]byte post [8]byte @@ -15,17 +14,16 @@ type T1 struct { func zero1_ssa(x *[1]byte) { *x = [1]byte{} } -func testZero1() { - a := T1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero1(t *testing.T) { + a := Z1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero1_ssa(&a.mid) - want := T1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z1{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1]byte{0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero1 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero1 got=%v, want %v\n", a, want) } } -type T2 struct { +type Z2 struct { pre [8]byte mid [2]byte post [8]byte @@ -35,17 +33,16 @@ type T2 struct { func zero2_ssa(x *[2]byte) { *x = [2]byte{} } -func testZero2() { - a := T2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero2(t *testing.T) { + a := Z2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero2_ssa(&a.mid) - want := T2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z2{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [2]byte{0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero2 got=%v, want %v\n", a, want) } } -type T3 struct { +type Z3 struct { pre [8]byte mid [3]byte post [8]byte @@ -55,17 +52,16 @@ type T3 struct { func zero3_ssa(x *[3]byte) { *x = [3]byte{} } -func testZero3() { - a := T3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero3(t *testing.T) { + a := Z3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero3_ssa(&a.mid) - want := T3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z3{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [3]byte{0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero3 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero3 got=%v, want %v\n", a, want) } } -type T4 struct { +type Z4 struct { pre [8]byte mid [4]byte post [8]byte @@ -75,17 +71,16 @@ type T4 struct { func zero4_ssa(x *[4]byte) { *x = [4]byte{} } -func testZero4() { - a := T4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero4(t *testing.T) { + a := Z4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero4_ssa(&a.mid) - want := T4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z4{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [4]byte{0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero4 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero4 got=%v, want %v\n", a, want) } } -type T5 struct { +type Z5 struct { pre [8]byte mid [5]byte post [8]byte @@ -95,17 +90,16 @@ type T5 struct { func zero5_ssa(x *[5]byte) { *x = [5]byte{} } -func testZero5() { - a := T5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero5(t *testing.T) { + a := Z5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero5_ssa(&a.mid) - want := T5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z5{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [5]byte{0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero5 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero5 got=%v, want %v\n", a, want) } } -type T6 struct { +type Z6 struct { pre [8]byte mid [6]byte post [8]byte @@ -115,17 +109,16 @@ type T6 struct { func zero6_ssa(x *[6]byte) { *x = [6]byte{} } -func testZero6() { - a := T6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero6(t *testing.T) { + a := Z6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero6_ssa(&a.mid) - want := T6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z6{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [6]byte{0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero6 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero6 got=%v, want %v\n", a, want) } } -type T7 struct { +type Z7 struct { pre [8]byte mid [7]byte post [8]byte @@ -135,17 +128,16 @@ type T7 struct { func zero7_ssa(x *[7]byte) { *x = [7]byte{} } -func testZero7() { - a := T7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero7(t *testing.T) { + a := Z7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero7_ssa(&a.mid) - want := T7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z7{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [7]byte{0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero7 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero7 got=%v, want %v\n", a, want) } } -type T8 struct { +type Z8 struct { pre [8]byte mid [8]byte post [8]byte @@ -155,17 +147,16 @@ type T8 struct { func zero8_ssa(x *[8]byte) { *x = [8]byte{} } -func testZero8() { - a := T8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero8(t *testing.T) { + a := Z8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero8_ssa(&a.mid) - want := T8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z8{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero8 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero8 got=%v, want %v\n", a, want) } } -type T9 struct { +type Z9 struct { pre [8]byte mid [9]byte post [8]byte @@ -175,17 +166,16 @@ type T9 struct { func zero9_ssa(x *[9]byte) { *x = [9]byte{} } -func testZero9() { - a := T9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero9(t *testing.T) { + a := Z9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero9_ssa(&a.mid) - want := T9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z9{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [9]byte{0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero9 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero9 got=%v, want %v\n", a, want) } } -type T10 struct { +type Z10 struct { pre [8]byte mid [10]byte post [8]byte @@ -195,17 +185,16 @@ type T10 struct { func zero10_ssa(x *[10]byte) { *x = [10]byte{} } -func testZero10() { - a := T10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero10(t *testing.T) { + a := Z10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero10_ssa(&a.mid) - want := T10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z10{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [10]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero10 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero10 got=%v, want %v\n", a, want) } } -type T15 struct { +type Z15 struct { pre [8]byte mid [15]byte post [8]byte @@ -215,17 +204,16 @@ type T15 struct { func zero15_ssa(x *[15]byte) { *x = [15]byte{} } -func testZero15() { - a := T15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero15(t *testing.T) { + a := Z15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero15_ssa(&a.mid) - want := T15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z15{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [15]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero15 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero15 got=%v, want %v\n", a, want) } } -type T16 struct { +type Z16 struct { pre [8]byte mid [16]byte post [8]byte @@ -235,17 +223,16 @@ type T16 struct { func zero16_ssa(x *[16]byte) { *x = [16]byte{} } -func testZero16() { - a := T16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero16(t *testing.T) { + a := Z16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero16_ssa(&a.mid) - want := T16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z16{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero16 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero16 got=%v, want %v\n", a, want) } } -type T17 struct { +type Z17 struct { pre [8]byte mid [17]byte post [8]byte @@ -255,17 +242,16 @@ type T17 struct { func zero17_ssa(x *[17]byte) { *x = [17]byte{} } -func testZero17() { - a := T17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero17(t *testing.T) { + a := Z17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero17_ssa(&a.mid) - want := T17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z17{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [17]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero17 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero17 got=%v, want %v\n", a, want) } } -type T23 struct { +type Z23 struct { pre [8]byte mid [23]byte post [8]byte @@ -275,17 +261,16 @@ type T23 struct { func zero23_ssa(x *[23]byte) { *x = [23]byte{} } -func testZero23() { - a := T23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero23(t *testing.T) { + a := Z23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero23_ssa(&a.mid) - want := T23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z23{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [23]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero23 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero23 got=%v, want %v\n", a, want) } } -type T24 struct { +type Z24 struct { pre [8]byte mid [24]byte post [8]byte @@ -295,17 +280,16 @@ type T24 struct { func zero24_ssa(x *[24]byte) { *x = [24]byte{} } -func testZero24() { - a := T24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero24(t *testing.T) { + a := Z24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero24_ssa(&a.mid) - want := T24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z24{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero24 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero24 got=%v, want %v\n", a, want) } } -type T25 struct { +type Z25 struct { pre [8]byte mid [25]byte post [8]byte @@ -315,17 +299,16 @@ type T25 struct { func zero25_ssa(x *[25]byte) { *x = [25]byte{} } -func testZero25() { - a := T25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero25(t *testing.T) { + a := Z25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero25_ssa(&a.mid) - want := T25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z25{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [25]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero25 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero25 got=%v, want %v\n", a, want) } } -type T31 struct { +type Z31 struct { pre [8]byte mid [31]byte post [8]byte @@ -335,17 +318,16 @@ type T31 struct { func zero31_ssa(x *[31]byte) { *x = [31]byte{} } -func testZero31() { - a := T31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero31(t *testing.T) { + a := Z31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero31_ssa(&a.mid) - want := T31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z31{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [31]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero31 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero31 got=%v, want %v\n", a, want) } } -type T32 struct { +type Z32 struct { pre [8]byte mid [32]byte post [8]byte @@ -355,17 +337,16 @@ type T32 struct { func zero32_ssa(x *[32]byte) { *x = [32]byte{} } -func testZero32() { - a := T32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero32(t *testing.T) { + a := Z32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero32_ssa(&a.mid) - want := T32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z32{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero32 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero32 got=%v, want %v\n", a, want) } } -type T33 struct { +type Z33 struct { pre [8]byte mid [33]byte post [8]byte @@ -375,17 +356,16 @@ type T33 struct { func zero33_ssa(x *[33]byte) { *x = [33]byte{} } -func testZero33() { - a := T33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero33(t *testing.T) { + a := Z33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero33_ssa(&a.mid) - want := T33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z33{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [33]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero33 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero33 got=%v, want %v\n", a, want) } } -type T63 struct { +type Z63 struct { pre [8]byte mid [63]byte post [8]byte @@ -395,17 +375,16 @@ type T63 struct { func zero63_ssa(x *[63]byte) { *x = [63]byte{} } -func testZero63() { - a := T63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero63(t *testing.T) { + a := Z63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero63_ssa(&a.mid) - want := T63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z63{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [63]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero63 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero63 got=%v, want %v\n", a, want) } } -type T64 struct { +type Z64 struct { pre [8]byte mid [64]byte post [8]byte @@ -415,17 +394,16 @@ type T64 struct { func zero64_ssa(x *[64]byte) { *x = [64]byte{} } -func testZero64() { - a := T64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero64(t *testing.T) { + a := Z64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero64_ssa(&a.mid) - want := T64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z64{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero64 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero64 got=%v, want %v\n", a, want) } } -type T65 struct { +type Z65 struct { pre [8]byte mid [65]byte post [8]byte @@ -435,17 +413,16 @@ type T65 struct { func zero65_ssa(x *[65]byte) { *x = [65]byte{} } -func testZero65() { - a := T65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero65(t *testing.T) { + a := Z65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero65_ssa(&a.mid) - want := T65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z65{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [65]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero65 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero65 got=%v, want %v\n", a, want) } } -type T1023 struct { +type Z1023 struct { pre [8]byte mid [1023]byte post [8]byte @@ -455,17 +432,16 @@ type T1023 struct { func zero1023_ssa(x *[1023]byte) { *x = [1023]byte{} } -func testZero1023() { - a := T1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero1023(t *testing.T) { + a := Z1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero1023_ssa(&a.mid) - want := T1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z1023{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1023]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero1023 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero1023 got=%v, want %v\n", a, want) } } -type T1024 struct { +type Z1024 struct { pre [8]byte mid [1024]byte post [8]byte @@ -475,17 +451,16 @@ type T1024 struct { func zero1024_ssa(x *[1024]byte) { *x = [1024]byte{} } -func testZero1024() { - a := T1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero1024(t *testing.T) { + a := Z1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero1024_ssa(&a.mid) - want := T1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z1024{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1024]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero1024 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero1024 got=%v, want %v\n", a, want) } } -type T1025 struct { +type Z1025 struct { pre [8]byte mid [1025]byte post [8]byte @@ -495,261 +470,242 @@ type T1025 struct { func zero1025_ssa(x *[1025]byte) { *x = [1025]byte{} } -func testZero1025() { - a := T1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero1025(t *testing.T) { + a := Z1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero1025_ssa(&a.mid) - want := T1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + want := Z1025{[8]byte{255, 255, 255, 255, 255, 255, 255, 255}, [1025]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} if a != want { - fmt.Printf("zero1025 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero1025 got=%v, want %v\n", a, want) } } -type T8u1 struct { +type Z8u1 struct { b bool val [8]byte } -type T8u2 struct { +type Z8u2 struct { i uint16 val [8]byte } //go:noinline -func zero8u1_ssa(t *T8u1) { +func zero8u1_ssa(t *Z8u1) { t.val = [8]byte{} } //go:noinline -func zero8u2_ssa(t *T8u2) { +func zero8u2_ssa(t *Z8u2) { t.val = [8]byte{} } -func testZero8u() { - a := T8u1{false, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} +func testZero8u(t *testing.T) { + a := Z8u1{false, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero8u1_ssa(&a) - want := T8u1{false, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}} + want := Z8u1{false, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero8u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero8u2 got=%v, want %v\n", a, want) } - b := T8u2{15, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} + b := Z8u2{15, [8]byte{255, 255, 255, 255, 255, 255, 255, 255}} zero8u2_ssa(&b) - wantb := T8u2{15, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z8u2{15, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero8u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero8u2 got=%v, want %v\n", b, wantb) } } -type T16u1 struct { +type Z16u1 struct { b bool val [16]byte } -type T16u2 struct { +type Z16u2 struct { i uint16 val [16]byte } //go:noinline -func zero16u1_ssa(t *T16u1) { +func zero16u1_ssa(t *Z16u1) { t.val = [16]byte{} } //go:noinline -func zero16u2_ssa(t *T16u2) { +func zero16u2_ssa(t *Z16u2) { t.val = [16]byte{} } -func testZero16u() { - a := T16u1{false, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} +func testZero16u(t *testing.T) { + a := Z16u1{false, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero16u1_ssa(&a) - want := T16u1{false, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + want := Z16u1{false, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero16u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero16u2 got=%v, want %v\n", a, want) } - b := T16u2{15, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} + b := Z16u2{15, [16]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero16u2_ssa(&b) - wantb := T16u2{15, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z16u2{15, [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero16u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero16u2 got=%v, want %v\n", b, wantb) } } -type T24u1 struct { +type Z24u1 struct { b bool val [24]byte } -type T24u2 struct { +type Z24u2 struct { i uint16 val [24]byte } //go:noinline -func zero24u1_ssa(t *T24u1) { +func zero24u1_ssa(t *Z24u1) { t.val = [24]byte{} } //go:noinline -func zero24u2_ssa(t *T24u2) { +func zero24u2_ssa(t *Z24u2) { t.val = [24]byte{} } -func testZero24u() { - a := T24u1{false, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} +func testZero24u(t *testing.T) { + a := Z24u1{false, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero24u1_ssa(&a) - want := T24u1{false, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + want := Z24u1{false, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero24u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero24u2 got=%v, want %v\n", a, want) } - b := T24u2{15, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} + b := Z24u2{15, [24]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero24u2_ssa(&b) - wantb := T24u2{15, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z24u2{15, [24]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero24u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero24u2 got=%v, want %v\n", b, wantb) } } -type T32u1 struct { +type Z32u1 struct { b bool val [32]byte } -type T32u2 struct { +type Z32u2 struct { i uint16 val [32]byte } //go:noinline -func zero32u1_ssa(t *T32u1) { +func zero32u1_ssa(t *Z32u1) { t.val = [32]byte{} } //go:noinline -func zero32u2_ssa(t *T32u2) { +func zero32u2_ssa(t *Z32u2) { t.val = [32]byte{} } -func testZero32u() { - a := T32u1{false, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} +func testZero32u(t *testing.T) { + a := Z32u1{false, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero32u1_ssa(&a) - want := T32u1{false, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + want := Z32u1{false, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero32u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero32u2 got=%v, want %v\n", a, want) } - b := T32u2{15, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} + b := Z32u2{15, [32]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero32u2_ssa(&b) - wantb := T32u2{15, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z32u2{15, [32]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero32u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero32u2 got=%v, want %v\n", b, wantb) } } -type T64u1 struct { +type Z64u1 struct { b bool val [64]byte } -type T64u2 struct { +type Z64u2 struct { i uint16 val [64]byte } //go:noinline -func zero64u1_ssa(t *T64u1) { +func zero64u1_ssa(t *Z64u1) { t.val = [64]byte{} } //go:noinline -func zero64u2_ssa(t *T64u2) { +func zero64u2_ssa(t *Z64u2) { t.val = [64]byte{} } -func testZero64u() { - a := T64u1{false, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} +func testZero64u(t *testing.T) { + a := Z64u1{false, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero64u1_ssa(&a) - want := T64u1{false, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + want := Z64u1{false, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero64u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero64u2 got=%v, want %v\n", a, want) } - b := T64u2{15, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} + b := Z64u2{15, [64]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero64u2_ssa(&b) - wantb := T64u2{15, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z64u2{15, [64]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero64u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero64u2 got=%v, want %v\n", b, wantb) } } -type T256u1 struct { +type Z256u1 struct { b bool val [256]byte } -type T256u2 struct { +type Z256u2 struct { i uint16 val [256]byte } //go:noinline -func zero256u1_ssa(t *T256u1) { +func zero256u1_ssa(t *Z256u1) { t.val = [256]byte{} } //go:noinline -func zero256u2_ssa(t *T256u2) { +func zero256u2_ssa(t *Z256u2) { t.val = [256]byte{} } -func testZero256u() { - a := T256u1{false, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} +func testZero256u(t *testing.T) { + a := Z256u1{false, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero256u1_ssa(&a) - want := T256u1{false, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + want := Z256u1{false, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if a != want { - fmt.Printf("zero256u2 got=%v, want %v\n", a, want) - failed = true + t.Errorf("zero256u2 got=%v, want %v\n", a, want) } - b := T256u2{15, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} + b := Z256u2{15, [256]byte{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}} zero256u2_ssa(&b) - wantb := T256u2{15, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} + wantb := Z256u2{15, [256]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}} if b != wantb { - fmt.Printf("zero256u2 got=%v, want %v\n", b, wantb) - failed = true + t.Errorf("zero256u2 got=%v, want %v\n", b, wantb) } } - -var failed bool - -func main() { - testZero1() - testZero2() - testZero3() - testZero4() - testZero5() - testZero6() - testZero7() - testZero8() - testZero9() - testZero10() - testZero15() - testZero16() - testZero17() - testZero23() - testZero24() - testZero25() - testZero31() - testZero32() - testZero33() - testZero63() - testZero64() - testZero65() - testZero1023() - testZero1024() - testZero1025() - testZero8u() - testZero16u() - testZero24u() - testZero32u() - testZero64u() - testZero256u() - if failed { - panic("failed") - } +func TestZero(t *testing.T) { + testZero1(t) + testZero2(t) + testZero3(t) + testZero4(t) + testZero5(t) + testZero6(t) + testZero7(t) + testZero8(t) + testZero9(t) + testZero10(t) + testZero15(t) + testZero16(t) + testZero17(t) + testZero23(t) + testZero24(t) + testZero25(t) + testZero31(t) + testZero32(t) + testZero33(t) + testZero63(t) + testZero64(t) + testZero65(t) + testZero1023(t) + testZero1024(t) + testZero1025(t) + testZero8u(t) + testZero16u(t) + testZero24u(t) + testZero32u(t) + testZero64u(t) + testZero256u(t) } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 1b68e057fc..bb78d8bf73 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1263,7 +1263,7 @@ func typecheck1(n *Node, top int) *Node { n.Op = OCALLFUNC if t.Etype != TFUNC { name := l.String() - if isBuiltinFuncName(name) { + if isBuiltinFuncName(name) && l.Name.Defn != nil { // be more specific when the function // name matches a predeclared function yyerror("cannot call non-function %s (type %v), declared at %s", @@ -3152,7 +3152,7 @@ func typecheckcomplit(n *Node) *Node { // dotpath returns the parent embedded types in reverse order. var ep []string for ei := len(p) - 1; ei >= 0; ei-- { - ep = append(ep, p[ei].field.Type.Sym.Name) + ep = append(ep, p[ei].field.Sym.Name) } ep = append(ep, l.Sym.Name) yyerror("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t) @@ -3333,10 +3333,17 @@ func typecheckas(n *Node) { n.Left = typecheck(n.Left, Erv|Easgn) } - n.Right = typecheck(n.Right, Erv) + // Use Efnstruct so we can emit an "N variables but M values" error + // to be consistent with typecheckas2 (#26616). + n.Right = typecheck(n.Right, Erv|Efnstruct) checkassign(n, n.Left) if n.Right != nil && n.Right.Type != nil { - if n.Left.Type != nil { + if n.Right.Type.IsFuncArgStruct() { + yyerror("assignment mismatch: 1 variable but %d values", n.Right.Type.NumFields()) + // Multi-value RHS isn't actually valid for OAS; nil out + // to indicate failed typechecking. + n.Right.Type = nil + } else if n.Left.Type != nil { n.Right = assignconv(n.Right, n.Left.Type, "assignment") } } @@ -3608,21 +3615,14 @@ func copytype(n *Node, t *types.Type) { } // Double-check use of type as embedded type. - lno := lineno - if embedlineno.IsKnown() { - lineno = embedlineno if t.IsPtr() || t.IsUnsafePtr() { - yyerror("embedded type cannot be a pointer") + yyerrorl(embedlineno, "embedded type cannot be a pointer") } } - - lineno = lno } func typecheckdeftype(n *Node) { - lno := lineno - setlineno(n) n.Type.Sym = n.Sym n.SetTypecheck(1) n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype) @@ -3637,8 +3637,6 @@ func typecheckdeftype(n *Node) { // that don't come along. copytype(n, t) } - - lineno = lno } func typecheckdef(n *Node) { diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index df7428a127..2993e08fc2 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -1022,64 +1022,13 @@ opswitch: n = walkexpr(n, init) case OCONV, OCONVNOP: - if thearch.SoftFloat { - // For the soft-float case, ssa.go handles these conversions. - n.Left = walkexpr(n.Left, init) + n.Left = walkexpr(n.Left, init) + param, result := rtconvfn(n.Left.Type, n.Type) + if param == Txxx { break } - switch thearch.LinkArch.Family { - case sys.ARM, sys.MIPS: - if n.Left.Type.IsFloat() { - switch n.Type.Etype { - case TINT64: - n = mkcall("float64toint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64])) - break opswitch - case TUINT64: - n = mkcall("float64touint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64])) - break opswitch - } - } - - if n.Type.IsFloat() { - switch n.Left.Type.Etype { - case TINT64: - n = conv(mkcall("int64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TINT64])), n.Type) - break opswitch - case TUINT64: - n = conv(mkcall("uint64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT64])), n.Type) - break opswitch - } - } - - case sys.I386: - if n.Left.Type.IsFloat() { - switch n.Type.Etype { - case TINT64: - n = mkcall("float64toint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64])) - break opswitch - case TUINT64: - n = mkcall("float64touint64", n.Type, init, conv(n.Left, types.Types[TFLOAT64])) - break opswitch - case TUINT32, TUINT, TUINTPTR: - n = mkcall("float64touint32", n.Type, init, conv(n.Left, types.Types[TFLOAT64])) - break opswitch - } - } - if n.Type.IsFloat() { - switch n.Left.Type.Etype { - case TINT64: - n = conv(mkcall("int64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TINT64])), n.Type) - break opswitch - case TUINT64: - n = conv(mkcall("uint64tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT64])), n.Type) - break opswitch - case TUINT32, TUINT, TUINTPTR: - n = conv(mkcall("uint32tofloat64", types.Types[TFLOAT64], init, conv(n.Left, types.Types[TUINT32])), n.Type) - break opswitch - } - } - } - n.Left = walkexpr(n.Left, init) + fn := basicnames[param] + "to" + basicnames[result] + n = conv(mkcall(fn, types.Types[result], init, conv(n.Left, types.Types[param])), n.Type) case OANDNOT: n.Left = walkexpr(n.Left, init) @@ -1506,9 +1455,7 @@ opswitch: a = typecheck(a, Etop) a = walkexpr(a, init) init.Append(a) - n = nod(OCONVNOP, h, nil) - n.Type = t - n = typecheck(n, Erv) + n = convnop(h, t) } else { // Call runtime.makehmap to allocate an // hmap on the heap and initialize hmap's hash0 field. @@ -1773,6 +1720,52 @@ opswitch: return n } +// rtconvfn returns the parameter and result types that will be used by a +// runtime function to convert from type src to type dst. The runtime function +// name can be derived from the names of the returned types. +// +// If no such function is necessary, it returns (Txxx, Txxx). +func rtconvfn(src, dst *types.Type) (param, result types.EType) { + if thearch.SoftFloat { + return Txxx, Txxx + } + + switch thearch.LinkArch.Family { + case sys.ARM, sys.MIPS: + if src.IsFloat() { + switch dst.Etype { + case TINT64, TUINT64: + return TFLOAT64, dst.Etype + } + } + if dst.IsFloat() { + switch src.Etype { + case TINT64, TUINT64: + return src.Etype, TFLOAT64 + } + } + + case sys.I386: + if src.IsFloat() { + switch dst.Etype { + case TINT64, TUINT64: + return TFLOAT64, dst.Etype + case TUINT32, TUINT, TUINTPTR: + return TFLOAT64, TUINT32 + } + } + if dst.IsFloat() { + switch src.Etype { + case TINT64, TUINT64: + return src.Etype, TFLOAT64 + case TUINT32, TUINT, TUINTPTR: + return TUINT32, TFLOAT64 + } + } + } + return Txxx, Txxx +} + // TODO(josharian): combine this with its caller and simplify func reduceSlice(n *Node) *Node { low, high, max := n.SliceBounds() @@ -2029,8 +2022,7 @@ func ascompatte(call *Node, isddd bool, lhs *types.Type, rhs []*Node, fp int, in // optimization - can do block copy if eqtypenoname(rhs[0].Type, lhs) { nl := nodarg(lhs, fp) - nr := nod(OCONVNOP, rhs[0], nil) - nr.Type = nl.Type + nr := convnop(rhs[0], nl.Type) n := convas(nod(OAS, nl, nr), init) n.SetTypecheck(1) return []*Node{n} @@ -2220,14 +2212,6 @@ func callnew(t *types.Type) *Node { return v } -func iscallret(n *Node) bool { - if n == nil { - return false - } - n = outervalue(n) - return n.Op == OINDREGSP -} - // isReflectHeaderDataField reports whether l is an expression p.Data // where p has type reflect.SliceHeader or reflect.StringHeader. func isReflectHeaderDataField(l *Node) bool { @@ -2756,6 +2740,15 @@ func conv(n *Node, t *types.Type) *Node { return n } +// convnop converts node n to type t using the OCONVNOP op +// and typechecks the result with Erv. +func convnop(n *Node, t *types.Type) *Node { + n = nod(OCONVNOP, n, nil) + n.Type = t + n = typecheck(n, Erv) + return n +} + // byteindex converts n, which is byte-sized, to a uint8. // We cannot use conv, because we allow converting bool to uint8 here, // which is forbidden in user code. @@ -2952,92 +2945,93 @@ func appendslice(n *Node, init *Nodes) *Node { l1 := n.List.First() l2 := n.List.Second() - var l []*Node + var nodes Nodes // var s []T s := temp(l1.Type) - l = append(l, nod(OAS, s, l1)) // s = l1 + nodes.Append(nod(OAS, s, l1)) // s = l1 + + elemtype := s.Type.Elem() // n := len(s) + len(l2) nn := temp(types.Types[TINT]) - l = append(l, nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil)))) + nodes.Append(nod(OAS, nn, nod(OADD, nod(OLEN, s, nil), nod(OLEN, l2, nil)))) // if uint(n) > uint(cap(s)) nif := nod(OIF, nil, nil) - nif.Left = nod(OGT, nod(OCONV, nn, nil), nod(OCONV, nod(OCAP, s, nil), nil)) - nif.Left.Left.Type = types.Types[TUINT] - nif.Left.Right.Type = types.Types[TUINT] + nuint := conv(nn, types.Types[TUINT]) + scapuint := conv(nod(OCAP, s, nil), types.Types[TUINT]) + nif.Left = nod(OGT, nuint, scapuint) - // instantiate growslice(Type*, []any, int) []any + // instantiate growslice(typ *type, []any, int) []any fn := syslook("growslice") - fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem()) + fn = substArgTypes(fn, elemtype, elemtype) // s = growslice(T, s, n) - nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type.Elem()), s, nn))) - l = append(l, nif) + nif.Nbody.Set1(nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(elemtype), s, nn))) + nodes.Append(nif) // s = s[:n] nt := nod(OSLICE, s, nil) nt.SetSliceBounds(nil, nn, nil) - l = append(l, nod(OAS, s, nt)) + nodes.Append(nod(OAS, s, nt)) - if l1.Type.Elem().HasHeapPointer() { + var ncopy *Node + if elemtype.HasHeapPointer() { // copy(s[len(l1):], l2) nptr1 := nod(OSLICE, s, nil) nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) + nptr2 := l2 + Curfn.Func.setWBPos(n.Pos) + + // instantiate typedslicecopy(typ *type, dst any, src any) int fn := syslook("typedslicecopy") fn = substArgTypes(fn, l1.Type, l2.Type) - var ln Nodes - ln.Set(l) - nt := mkcall1(fn, types.Types[TINT], &ln, typename(l1.Type.Elem()), nptr1, nptr2) - l = append(ln.Slice(), nt) + ncopy = mkcall1(fn, types.Types[TINT], &nodes, typename(elemtype), nptr1, nptr2) + } else if instrumenting && !compiling_runtime { // rely on runtime to instrument copy. // copy(s[len(l1):], l2) nptr1 := nod(OSLICE, s, nil) nptr1.SetSliceBounds(nod(OLEN, l1, nil), nil, nil) + nptr2 := l2 - var ln Nodes - ln.Set(l) - var nt *Node if l2.Type.IsString() { + // instantiate func slicestringcopy(to any, fr any) int fn := syslook("slicestringcopy") fn = substArgTypes(fn, l1.Type, l2.Type) - nt = mkcall1(fn, types.Types[TINT], &ln, nptr1, nptr2) + ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2) } else { + // instantiate func slicecopy(to any, fr any, wid uintptr) int fn := syslook("slicecopy") fn = substArgTypes(fn, l1.Type, l2.Type) - nt = mkcall1(fn, types.Types[TINT], &ln, nptr1, nptr2, nodintconst(s.Type.Elem().Width)) + ncopy = mkcall1(fn, types.Types[TINT], &nodes, nptr1, nptr2, nodintconst(elemtype.Width)) } - l = append(ln.Slice(), nt) } else { // memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T)) nptr1 := nod(OINDEX, s, nod(OLEN, l1, nil)) nptr1.SetBounded(true) - nptr1 = nod(OADDR, nptr1, nil) nptr2 := nod(OSPTR, l2, nil) + nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &nodes) + nwid = nod(OMUL, nwid, nodintconst(elemtype.Width)) + + // instantiate func memmove(to *any, frm *any, length uintptr) fn := syslook("memmove") - fn = substArgTypes(fn, s.Type.Elem(), s.Type.Elem()) - - var ln Nodes - ln.Set(l) - nwid := cheapexpr(conv(nod(OLEN, l2, nil), types.Types[TUINTPTR]), &ln) - - nwid = nod(OMUL, nwid, nodintconst(s.Type.Elem().Width)) - nt := mkcall1(fn, nil, &ln, nptr1, nptr2, nwid) - l = append(ln.Slice(), nt) + fn = substArgTypes(fn, elemtype, elemtype) + ncopy = mkcall1(fn, nil, &nodes, nptr1, nptr2, nwid) } + ln := append(nodes.Slice(), ncopy) - typecheckslice(l, Etop) - walkstmtlist(l) - init.Append(l...) + typecheckslice(ln, Etop) + walkstmtlist(ln) + init.Append(ln...) return s } @@ -3165,8 +3159,7 @@ func extendslice(n *Node, init *Nodes) *Node { hp := nod(OINDEX, s, nod(OLEN, l1, nil)) hp.SetBounded(true) hp = nod(OADDR, hp, nil) - hp = nod(OCONVNOP, hp, nil) - hp.Type = types.Types[TUNSAFEPTR] + hp = convnop(hp, types.Types[TUNSAFEPTR]) // hn := l2 * sizeof(elem(s)) hn := nod(OMUL, l2, nodintconst(elemtype.Width)) @@ -3701,6 +3694,12 @@ func walkinrange(n *Node, init *Nodes) *Node { return n } + // Ensure that Int64() does not overflow on a and c (it'll happen + // for any const above 2**63; see issue #27143). + if !a.CanInt64() || !c.CanInt64() { + return n + } + if opl == OLT { // We have a < b && ... // We need a ≤ b && ... to safely use unsigned comparison tricks. diff --git a/src/cmd/compile/internal/s390x/ssa.go b/src/cmd/compile/internal/s390x/ssa.go index fe206f74e8..be48e1b23e 100644 --- a/src/cmd/compile/internal/s390x/ssa.go +++ b/src/cmd/compile/internal/s390x/ssa.go @@ -160,7 +160,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { switch v.Op { case ssa.OpS390XSLD, ssa.OpS390XSLW, ssa.OpS390XSRD, ssa.OpS390XSRW, - ssa.OpS390XSRAD, ssa.OpS390XSRAW: + ssa.OpS390XSRAD, ssa.OpS390XSRAW, + ssa.OpS390XRLLG, ssa.OpS390XRLL: r := v.Reg() r1 := v.Args[0].Reg() r2 := v.Args[1].Reg() @@ -513,7 +514,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.To.Type = obj.TYPE_MEM p.To.Name = obj.NAME_EXTERN p.To.Sym = v.Aux.(*obj.LSym) - case ssa.OpS390XFLOGR, ssa.OpS390XNEG, ssa.OpS390XNEGW, + case ssa.OpS390XFLOGR, ssa.OpS390XPOPCNT, + ssa.OpS390XNEG, ssa.OpS390XNEGW, ssa.OpS390XMOVWBR, ssa.OpS390XMOVDBR: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG @@ -522,6 +524,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.To.Reg = v.Reg() case ssa.OpS390XNOT, ssa.OpS390XNOTW: v.Fatalf("NOT/NOTW generated %s", v.LongString()) + case ssa.OpS390XSumBytes2, ssa.OpS390XSumBytes4, ssa.OpS390XSumBytes8: + v.Fatalf("SumBytes generated %s", v.LongString()) case ssa.OpS390XMOVDEQ, ssa.OpS390XMOVDNE, ssa.OpS390XMOVDLT, ssa.OpS390XMOVDLE, ssa.OpS390XMOVDGT, ssa.OpS390XMOVDGE, diff --git a/src/cmd/compile/internal/ssa/README.md b/src/cmd/compile/internal/ssa/README.md index 3b30b47504..d283118011 100644 --- a/src/cmd/compile/internal/ssa/README.md +++ b/src/cmd/compile/internal/ssa/README.md @@ -1,59 +1,209 @@ -This package contains the compiler's Static Single Assignment form -component. If you're not familiar with SSA, Wikipedia is a good starting -point: + - https://en.wikipedia.org/wiki/Static_single_assignment_form +## Introduction to the Go compiler's SSA backend -SSA is useful to perform transformations and optimizations, which can be -found in this package in the form of compiler passes and rewrite rules. -The former can be found in the "passes" array in compile.go, while the -latter are generated from gen/*.rules. +This package contains the compiler's Static Single Assignment form component. If +you're not familiar with SSA, its [Wikipedia +article](https://en.wikipedia.org/wiki/Static_single_assignment_form) is a good +starting point. -Like most other SSA forms, funcs consist of blocks and values. Values -perform an operation, which is encoded in the form of an operator and a -number of arguments. The semantics of each Op can be found in -gen/*Ops.go. +It is recommended that you first read [cmd/compile/README.md](../../README.md) +if you are not familiar with the Go compiler already. That document gives an +overview of the compiler, and explains what is SSA's part and purpose in it. -gen/* is used to generate code in the ssa package. This includes -opGen.go from gen/*Ops.go, and the rewrite*.go files from gen/*.rules. -To regenerate these files, see gen/README. +### Key concepts -Blocks can have multiple forms. For example, BlockPlain will always hand -the control flow to another block, and BlockIf will flow to one of two -blocks depending on a value. See block.go for more details. +The names described below may be loosely related to their Go counterparts, but +note that they are not equivalent. For example, a Go block statement has a +variable scope, yet SSA has no notion of variables nor variable scopes. -Values also have types. For example, a constant boolean value will have -a Bool type, and a variable definition value will have a memory type. +It may also be surprising that values and blocks are named after their unique +sequential IDs. They rarely correspond to named entities in the original code, +such as variables or function parameters. The sequential IDs also allow the +compiler to avoid maps, and it is always possible to track back the values to Go +code using debug and position information. -The memory type is special - it represents the global memory state. For -example, an Op that takes a memory argument depends on that memory -state, and an Op which has the memory type impacts the state of memory. -This is important so that memory operations are kept in the right order. +#### Values -For example, take this program: +Values are the basic building blocks of SSA. Per SSA's very definition, a +value is defined exactly once, but it may be used any number of times. A value +mainly consists of a unique identifier, an operator, a type, and some arguments. - func f(a, b *int) { - *a = 3 - *b = *a - } +An operator or `Op` describes the operation that computes the value. The +semantics of each operator can be found in `gen/*Ops.go`. For example, `OpAdd8` +takes two value arguments holding 8-bit integers and results in their addition. +Here is a possible SSA representation of the addition of two `uint8` values: -The two generated stores may show up as follows: + // var c uint8 = a + b + v4 = Add8 v2 v3 - v10 (4) = Store {int} v6 v8 v1 - v14 (5) = Store {int} v7 v8 v10 +A value's type will usually be a Go type. For example, the value in the example +above has a `uint8` type, and a constant boolean value will have a `bool` type. +However, certain types don't come from Go and are special; below we will cover +`memory`, the most common of them. -Since the second store has a memory argument v10, it cannot be reordered -before the first store, which sets that global memory state. And the -logic translates to the code; reordering the two assignments would -result in a different program. +See [value.go](value.go) for more information. + +#### Memory types + +`memory` represents the global memory state. An `Op` that takes a memory +argument depends on that memory state, and an `Op` which has the memory type +impacts the state of memory. This ensures that memory operations are kept in the +right order. For example: + + // *a = 3 + // *b = *a + v10 = Store {int} v6 v8 v1 + v14 = Store {int} v7 v8 v10 + +Here, `Store` stores its second argument (of type `int`) into the first argument +(of type `*int`). The last argument is the memory state; since the second store +depends on the memory value defined by the first store, the two stores cannot be +reordered. + +See [cmd/compile/internal/types/type.go](../types/type.go) for more information. + +#### Blocks + +A block represents a basic block in the control flow graph of a function. It is, +essentially, a list of values that define the operation of this block. Besides +the list of values, blocks mainly consist of a unique identifier, a kind, and a +list of successor blocks. + +The simplest kind is a `plain` block; it simply hands the control flow to +another block, thus its successors list contains one block. + +Another common block kind is the `exit` block. These have a final value, called +control value, which must return a memory state. This is necessary for functions +to return some values, for example - the caller needs some memory state to +depend on, to ensure that it receives those return values correctly. + +The last important block kind we will mention is the `if` block. Its control +value must be a boolean value, and it has exactly two successor blocks. The +control flow is handed to the first successor if the bool is true, and to the +second otherwise. + +Here is a sample if-else control flow represented with basic blocks: + + // func(b bool) int { + // if b { + // return 2 + // } + // return 3 + // } + b1: + v1 = InitMem + v2 = SP + v5 = Addr <*int> {~r1} v2 + v6 = Arg {b} + v8 = Const64 [2] + v12 = Const64 [3] + If v6 -> b2 b3 + b2: <- b1 + v10 = VarDef {~r1} v1 + v11 = Store {int} v5 v8 v10 + Ret v11 + b3: <- b1 + v14 = VarDef {~r1} v1 + v15 = Store {int} v5 v12 v14 + Ret v15 + + + +See [block.go](block.go) for more information. + +#### Functions + +A function represents a function declaration along with its body. It mainly +consists of a name, a type (its signature), a list of blocks that form its body, +and the entry block within said list. + +When a function is called, the control flow is handed to its entry block. If the +function terminates, the control flow will eventually reach an exit block, thus +ending the function call. + +Note that a function may have zero or multiple exit blocks, just like a Go +function can have any number of return points, but it must have exactly one +entry point block. + +Also note that some SSA functions are autogenerated, such as the hash functions +for each type used as a map key. + +For example, this is what an empty function can look like in SSA, with a single +exit block that returns an uninteresting memory state: + + foo func() + b1: + v1 = InitMem + Ret v1 + +See [func.go](func.go) for more information. + +### Compiler passes + +Having a program in SSA form is not very useful on its own. Its advantage lies +in how easy it is to write optimizations that modify the program to make it +better. The way the Go compiler accomplishes this is via a list of passes. + +Each pass transforms a SSA function in some way. For example, a dead code +elimination pass will remove blocks and values that it can prove will never be +executed, and a nil check elimination pass will remove nil checks which it can +prove to be redundant. + +Compiler passes work on one function at a time, and by default run sequentially +and exactly once. + +The `lower` pass is special; it converts the SSA representation from being +machine-independent to being machine-dependent. That is, some abstract operators +are replaced with their non-generic counterparts, potentially reducing or +increasing the final number of values. + + + +See the `passes` list defined in [compile.go](compile.go) for more information. + +### Playing with SSA A good way to see and get used to the compiler's SSA in action is via -GOSSAFUNC. For example, to see func Foo's initial SSA form and final +`GOSSAFUNC`. For example, to see func `Foo`'s initial SSA form and final generated assembly, one can run: GOSSAFUNC=Foo go build -The generated ssa.html file will also contain the SSA func at each of -the compile passes, making it easy to see what each pass does to a -particular program. You can also click on values and blocks to highlight -them, to help follow the control flow and values. +The generated `ssa.html` file will also contain the SSA func at each of the +compile passes, making it easy to see what each pass does to a particular +program. You can also click on values and blocks to highlight them, to help +follow the control flow and values. + + + +### Hacking on SSA + +While most compiler passes are implemented directly in Go code, some others are +code generated. This is currently done via rewrite rules, which have their own +syntax and are maintained in `gen/*.rules`. Simpler optimizations can be written +easily and quickly this way, but rewrite rules are not suitable for more complex +optimizations. + +To read more on rewrite rules, have a look at the top comments in +[gen/generic.rules](gen/generic.rules) and [gen/rulegen.go](gen/rulegen.go). + +Similarly, the code to manage operators is also code generated from +`gen/*Ops.go`, as it is easier to maintain a few tables than a lot of code. +After changing the rules or operators, see [gen/README](gen/README) for +instructions on how to generate the Go code again. + + diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index a0ef5fbced..13e8d7b3de 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -6,6 +6,7 @@ package ssa import ( "math" + "math/bits" ) // checkFunc checks invariants of f. @@ -146,7 +147,7 @@ func checkFunc(f *Func) { // AuxInt must be zero, so leave canHaveAuxInt set to false. case auxFloat32: canHaveAuxInt = true - if !isExactFloat32(v) { + if !isExactFloat32(v.AuxFloat()) { f.Fatalf("value %v has an AuxInt value that is not an exact float32", v) } case auxString, auxSym, auxTyp: @@ -203,11 +204,23 @@ func checkFunc(f *Func) { if len(v.Args) == 0 { f.Fatalf("no args for OpAddr %s", v.LongString()) } - if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB { + if v.Args[0].Op != OpSB { f.Fatalf("bad arg to OpAddr %v", v) } } + if v.Op == OpLocalAddr { + if len(v.Args) != 2 { + f.Fatalf("wrong # of args for OpLocalAddr %s", v.LongString()) + } + if v.Args[0].Op != OpSP { + f.Fatalf("bad arg 0 to OpLocalAddr %v", v) + } + if !v.Args[1].Type.IsMemory() { + f.Fatalf("bad arg 1 to OpLocalAddr %v", v) + } + } + if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() { f.Fatalf("unexpected floating-point type %v", v.LongString()) } @@ -496,8 +509,12 @@ func domCheck(f *Func, sdom SparseTree, x, y *Block) bool { return sdom.isAncestorEq(x, y) } -// isExactFloat32 reports whether v has an AuxInt that can be exactly represented as a float32. -func isExactFloat32(v *Value) bool { - x := v.AuxFloat() - return math.Float64bits(x) == math.Float64bits(float64(float32(x))) +// isExactFloat32 reports whether x can be exactly represented as a float32. +func isExactFloat32(x float64) bool { + // Check the mantissa is in range. + if bits.TrailingZeros64(math.Float64bits(x)) < 52-23 { + return false + } + // Check the exponent is in range. The mantissa check above is sufficient for NaN values. + return math.IsNaN(x) || x == float64(float32(x)) } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index c7797d79e9..8b5d6d94e8 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -42,7 +42,9 @@ func Compile(f *Func) { }() // Run all the passes - printFunc(f) + if f.Log() { + printFunc(f) + } f.HTMLWriter.WriteFunc("start", "start", f) if BuildDump != "" && BuildDump == f.Name { f.dumpFile("build") @@ -84,8 +86,10 @@ func Compile(f *Func) { stats = fmt.Sprintf("[%d ns]", time) } - f.Logf(" pass %s end %s\n", p.name, stats) - printFunc(f) + if f.Log() { + f.Logf(" pass %s end %s\n", p.name, stats) + printFunc(f) + } f.HTMLWriter.WriteFunc(phaseName, fmt.Sprintf("%s %s", phaseName, stats), f) } if p.time || p.mem { @@ -373,7 +377,7 @@ var passes = [...]pass{ {name: "softfloat", fn: softfloat, required: true}, {name: "late opt", fn: opt, required: true}, // TODO: split required rules and optimizing rules {name: "dead auto elim", fn: elimDeadAutosGeneric}, - {name: "generic deadcode", fn: deadcode}, + {name: "generic deadcode", fn: deadcode, required: true}, // remove dead stores, which otherwise mess up store chain {name: "check bce", fn: checkbce}, {name: "branchelim", fn: branchelim}, {name: "fuse", fn: fuse}, diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 28498629b6..40008bcf87 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -9,40 +9,38 @@ import ( "cmd/internal/obj" "cmd/internal/objabi" "cmd/internal/src" - "os" - "strconv" ) // A Config holds readonly compilation information. // It is created once, early during compilation, // and shared across all compilations. type Config struct { - arch string // "amd64", etc. - PtrSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize - RegSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.RegSize - Types Types - lowerBlock blockRewriter // lowering function - lowerValue valueRewriter // lowering function - registers []Register // machine registers - gpRegMask regMask // general purpose integer register mask - fpRegMask regMask // floating point register mask - specialRegMask regMask // special register mask - GCRegMap []*Register // garbage collector register map, by GC register index - FPReg int8 // register number of frame pointer, -1 if not used - LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used - hasGReg bool // has hardware g register - ctxt *obj.Link // Generic arch information - optimize bool // Do optimization - noDuffDevice bool // Don't use Duff's device - useSSE bool // Use SSE for non-float operations - useAvg bool // Use optimizations that need Avg* operations - useHmul bool // Use optimizations that need Hmul* operations - nacl bool // GOOS=nacl - use387 bool // GO386=387 - SoftFloat bool // - NeedsFpScratch bool // No direct move between GP and FP register sets - BigEndian bool // - sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score + arch string // "amd64", etc. + PtrSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.PtrSize + RegSize int64 // 4 or 8; copy of cmd/internal/sys.Arch.RegSize + Types Types + lowerBlock blockRewriter // lowering function + lowerValue valueRewriter // lowering function + registers []Register // machine registers + gpRegMask regMask // general purpose integer register mask + fpRegMask regMask // floating point register mask + specialRegMask regMask // special register mask + GCRegMap []*Register // garbage collector register map, by GC register index + FPReg int8 // register number of frame pointer, -1 if not used + LinkReg int8 // register number of link register if it is a general purpose register, -1 if not used + hasGReg bool // has hardware g register + ctxt *obj.Link // Generic arch information + optimize bool // Do optimization + noDuffDevice bool // Don't use Duff's device + useSSE bool // Use SSE for non-float operations + useAvg bool // Use optimizations that need Avg* operations + useHmul bool // Use optimizations that need Hmul* operations + nacl bool // GOOS=nacl + use387 bool // GO386=387 + SoftFloat bool // + Race bool // race detector enabled + NeedsFpScratch bool // No direct move between GP and FP register sets + BigEndian bool // } type ( @@ -360,22 +358,6 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 3 // BX } - // cutoff is compared with product of numblocks and numvalues, - // if product is smaller than cutoff, use old non-sparse method. - // cutoff == 0 implies all sparse. - // cutoff == -1 implies none sparse. - // Good cutoff values seem to be O(million) depending on constant factor cost of sparse. - // TODO: get this from a flag, not an environment variable - c.sparsePhiCutoff = 2500000 // 0 for testing. // 2500000 determined with crude experiments w/ make.bash - ev := os.Getenv("GO_SSA_PHI_LOC_CUTOFF") - if ev != "" { - v, err := strconv.ParseInt(ev, 10, 64) - if err != nil { - ctxt.Diag("Environment variable GO_SSA_PHI_LOC_CUTOFF (value '%s') did not parse as a number", ev) - } - c.sparsePhiCutoff = uint64(v) // convert -1 to maxint, for never use sparse - } - // Create the GC register map index. // TODO: This is only used for debug printing. Maybe export config.registers? gcRegMapSize := int16(0) @@ -399,5 +381,4 @@ func (c *Config) Set387(b bool) { c.use387 = b } -func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff } -func (c *Config) Ctxt() *obj.Link { return c.ctxt } +func (c *Config) Ctxt() *obj.Link { return c.ctxt } diff --git a/src/cmd/compile/internal/ssa/cse_test.go b/src/cmd/compile/internal/ssa/cse_test.go index adb8664945..b139701990 100644 --- a/src/cmd/compile/internal/ssa/cse_test.go +++ b/src/cmd/compile/internal/ssa/cse_test.go @@ -35,7 +35,7 @@ func TestCSEAuxPartitionBug(t *testing.T) { Valu("r4", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"), Valu("r8", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg2"), Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"), - Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"), + Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"), Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"), Valu("r6", OpAdd64, c.config.Types.Int64, 0, nil, "r4", "r5"), Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"), @@ -105,7 +105,7 @@ func TestZCSE(t *testing.T) { Valu("c2", OpConst64, c.config.Types.Int64, 1, nil), Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "a2ld", "c2"), Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"), - Valu("raddr", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp"), + Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"), Valu("raddrdef", OpVarDef, types.TypeMem, 0, nil, "start"), Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r3", "raddrdef"), Goto("exit")), diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index 4b2f57dcd9..69616b3a88 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -133,7 +133,7 @@ func dse(f *Func) { } } -// elimDeadAutosGeneric deletes autos that are never accessed. To acheive this +// elimDeadAutosGeneric deletes autos that are never accessed. To achieve this // we track the operations that the address of each auto reaches and if it only // reaches stores then we delete all the stores. The other operations will then // be eliminated by the dead code elimination pass. @@ -146,7 +146,7 @@ func elimDeadAutosGeneric(f *Func) { visit := func(v *Value) (changed bool) { args := v.Args switch v.Op { - case OpAddr: + case OpAddr, OpLocalAddr: // Propagate the address if it points to an auto. n, ok := v.Aux.(GCNode) if !ok || n.StorageClass() != ClassAuto { @@ -197,13 +197,15 @@ func elimDeadAutosGeneric(f *Func) { panic("unhandled op with sym effect") } - if v.Uses == 0 || len(args) == 0 { + if v.Uses == 0 && v.Op != OpNilCheck || len(args) == 0 { + // Nil check has no use, but we need to keep it. return } // If the address of the auto reaches a memory or control // operation not covered above then we probably need to keep it. - if v.Type.IsMemory() || v.Type.IsFlags() || (v.Op != OpPhi && v.MemoryArg() != nil) { + // We also need to keep autos if they reach Phis (issue #26153). + if v.Type.IsMemory() || v.Type.IsFlags() || v.Op == OpPhi || v.MemoryArg() != nil { for _, a := range args { if n, ok := addr[a]; ok { if !used[n] { @@ -261,6 +263,14 @@ func elimDeadAutosGeneric(f *Func) { for _, v := range b.Values { changed = visit(v) || changed } + // keep the auto if its address reaches a control value + if b.Control == nil { + continue + } + if n, ok := addr[b.Control]; ok && !used[n] { + used[n] = true + changed = true + } } if !changed { break diff --git a/src/cmd/compile/internal/ssa/debug.go b/src/cmd/compile/internal/ssa/debug.go index c4f90ebff2..c1fbdcc517 100644 --- a/src/cmd/compile/internal/ssa/debug.go +++ b/src/cmd/compile/internal/ssa/debug.go @@ -535,8 +535,6 @@ func (state *debugState) mergePredecessors(b *Block, blockLocs []*BlockDebug) ([ } if len(preds) == 0 { - if state.loggingEnabled { - } state.currentState.reset(nil) return nil, true } @@ -765,7 +763,7 @@ type partsByVarOffset struct { func (a partsByVarOffset) Len() int { return len(a.slotIDs) } func (a partsByVarOffset) Less(i, j int) bool { - return varOffset(a.slots[a.slotIDs[i]]) < varOffset(a.slots[a.slotIDs[i]]) + return varOffset(a.slots[a.slotIDs[i]]) < varOffset(a.slots[a.slotIDs[j]]) } func (a partsByVarOffset) Swap(i, j int) { a.slotIDs[i], a.slotIDs[j] = a.slotIDs[j], a.slotIDs[i] } @@ -854,7 +852,6 @@ func (state *debugState) buildLocationLists(blockLocs []*BlockDebug) { } state.changedVars.clear() } - } if state.loggingEnabled { @@ -914,8 +911,6 @@ func (state *debugState) updateVar(varID VarID, v *Value, curLoc []VarLoc) { for i, slot := range state.varSlots[varID] { pending.pieces[i] = curLoc[slot] } - return - } // writePendingEntry writes out the pending entry for varID, if any, diff --git a/src/cmd/compile/internal/ssa/debug_test.go b/src/cmd/compile/internal/ssa/debug_test.go index d0a7a69db9..0a409bec2c 100644 --- a/src/cmd/compile/internal/ssa/debug_test.go +++ b/src/cmd/compile/internal/ssa/debug_test.go @@ -143,14 +143,21 @@ func TestNexting(t *testing.T) { optFlags += " -l" } - subTest(t, debugger+"-dbg", "hist", dbgFlags) - subTest(t, debugger+"-dbg", "scopes", dbgFlags) - subTest(t, debugger+"-dbg", "i22558", dbgFlags) + moreargs := []string{} + if !*useDelve && (runtime.GOOS == "darwin" || runtime.GOOS == "windows") { + // gdb and lldb on Darwin do not deal with compressed dwarf. + // also, Windows. + moreargs = append(moreargs, "-ldflags=-compressdwarf=false") + } - subTest(t, debugger+"-dbg-race", "i22600", dbgFlags, "-race") + subTest(t, debugger+"-dbg", "hist", dbgFlags, moreargs...) + subTest(t, debugger+"-dbg", "scopes", dbgFlags, moreargs...) + subTest(t, debugger+"-dbg", "i22558", dbgFlags, moreargs...) - optSubTest(t, debugger+"-opt", "hist", optFlags) - optSubTest(t, debugger+"-opt", "scopes", optFlags) + subTest(t, debugger+"-dbg-race", "i22600", dbgFlags, append(moreargs, "-race")...) + + optSubTest(t, debugger+"-opt", "hist", optFlags, moreargs...) + optSubTest(t, debugger+"-opt", "scopes", optFlags, moreargs...) } // subTest creates a subtest that compiles basename.go with the specified gcflags and additional compiler arguments, diff --git a/src/cmd/compile/internal/ssa/flagalloc.go b/src/cmd/compile/internal/ssa/flagalloc.go index 050595ff8d..56c12e320a 100644 --- a/src/cmd/compile/internal/ssa/flagalloc.go +++ b/src/cmd/compile/internal/ssa/flagalloc.go @@ -4,6 +4,30 @@ package ssa +// When breaking up a combined load-compare to separated load and compare operations, +// opLoad specifies the load operation, and opCmp specifies the compare operation. +type typeCmdLoadMap struct { + opLoad Op + opCmp Op +} + +var opCmpLoadMap = map[Op]typeCmdLoadMap{ + OpAMD64CMPQload: {OpAMD64MOVQload, OpAMD64CMPQ}, + OpAMD64CMPLload: {OpAMD64MOVLload, OpAMD64CMPL}, + OpAMD64CMPWload: {OpAMD64MOVWload, OpAMD64CMPW}, + OpAMD64CMPBload: {OpAMD64MOVBload, OpAMD64CMPB}, + Op386CMPLload: {Op386MOVLload, Op386CMPL}, + Op386CMPWload: {Op386MOVWload, Op386CMPW}, + Op386CMPBload: {Op386MOVBload, Op386CMPB}, + OpAMD64CMPQconstload: {OpAMD64MOVQload, OpAMD64CMPQconst}, + OpAMD64CMPLconstload: {OpAMD64MOVLload, OpAMD64CMPLconst}, + OpAMD64CMPWconstload: {OpAMD64MOVWload, OpAMD64CMPWconst}, + OpAMD64CMPBconstload: {OpAMD64MOVBload, OpAMD64CMPBconst}, + Op386CMPLconstload: {Op386MOVLload, Op386CMPLconst}, + Op386CMPWconstload: {Op386MOVWload, Op386CMPWconst}, + Op386CMPBconstload: {Op386MOVBload, Op386CMPBconst}, +} + // flagalloc allocates the flag register among all the flag-generating // instructions. Flag values are recomputed if they need to be // spilled/restored. @@ -122,55 +146,55 @@ func flagalloc(f *Func) { if spill[v.ID] && v.MemoryArg() != nil { switch v.Op { case OpAMD64CMPQload: - load := b.NewValue2IA(v.Pos, OpAMD64MOVQload, f.Config.Types.UInt64, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) - v.Op = OpAMD64CMPQ + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt64, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = 0 v.Aux = nil v.SetArgs2(load, v.Args[1]) - case OpAMD64CMPLload: - load := b.NewValue2IA(v.Pos, OpAMD64MOVLload, f.Config.Types.UInt32, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) - v.Op = OpAMD64CMPL + case OpAMD64CMPLload, Op386CMPLload: + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt32, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = 0 v.Aux = nil v.SetArgs2(load, v.Args[1]) - case OpAMD64CMPWload: - load := b.NewValue2IA(v.Pos, OpAMD64MOVWload, f.Config.Types.UInt16, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) - v.Op = OpAMD64CMPW + case OpAMD64CMPWload, Op386CMPWload: + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt16, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = 0 v.Aux = nil v.SetArgs2(load, v.Args[1]) - case OpAMD64CMPBload: - load := b.NewValue2IA(v.Pos, OpAMD64MOVBload, f.Config.Types.UInt8, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) - v.Op = OpAMD64CMPB + case OpAMD64CMPBload, Op386CMPBload: + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt8, v.AuxInt, v.Aux, v.Args[0], v.Args[2]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = 0 v.Aux = nil v.SetArgs2(load, v.Args[1]) case OpAMD64CMPQconstload: vo := v.AuxValAndOff() - load := b.NewValue2IA(v.Pos, OpAMD64MOVQload, f.Config.Types.UInt64, vo.Off(), v.Aux, v.Args[0], v.Args[1]) - v.Op = OpAMD64CMPQconst + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt64, vo.Off(), v.Aux, v.Args[0], v.Args[1]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = vo.Val() v.Aux = nil v.SetArgs1(load) - case OpAMD64CMPLconstload: + case OpAMD64CMPLconstload, Op386CMPLconstload: vo := v.AuxValAndOff() - load := b.NewValue2IA(v.Pos, OpAMD64MOVLload, f.Config.Types.UInt32, vo.Off(), v.Aux, v.Args[0], v.Args[1]) - v.Op = OpAMD64CMPLconst + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt32, vo.Off(), v.Aux, v.Args[0], v.Args[1]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = vo.Val() v.Aux = nil v.SetArgs1(load) - case OpAMD64CMPWconstload: + case OpAMD64CMPWconstload, Op386CMPWconstload: vo := v.AuxValAndOff() - load := b.NewValue2IA(v.Pos, OpAMD64MOVWload, f.Config.Types.UInt16, vo.Off(), v.Aux, v.Args[0], v.Args[1]) - v.Op = OpAMD64CMPWconst + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt16, vo.Off(), v.Aux, v.Args[0], v.Args[1]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = vo.Val() v.Aux = nil v.SetArgs1(load) - case OpAMD64CMPBconstload: + case OpAMD64CMPBconstload, Op386CMPBconstload: vo := v.AuxValAndOff() - load := b.NewValue2IA(v.Pos, OpAMD64MOVBload, f.Config.Types.UInt8, vo.Off(), v.Aux, v.Args[0], v.Args[1]) - v.Op = OpAMD64CMPBconst + load := b.NewValue2IA(v.Pos, opCmpLoadMap[v.Op].opLoad, f.Config.Types.UInt8, vo.Off(), v.Aux, v.Args[0], v.Args[1]) + v.Op = opCmpLoadMap[v.Op].opCmp v.AuxInt = vo.Val() v.Aux = nil v.SetArgs1(load) diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 85d41d124b..eb5775efcb 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -390,6 +390,19 @@ func (b *Block) NewValue2(pos src.XPos, op Op, t *types.Type, arg0, arg1 *Value) return v } +// NewValue2A returns a new value in the block with two arguments and one aux values. +func (b *Block) NewValue2A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1 *Value) *Value { + v := b.Func.newValue(op, t, b, pos) + v.AuxInt = 0 + v.Aux = aux + v.Args = v.argstorage[:2] + v.argstorage[0] = arg0 + v.argstorage[1] = arg1 + arg0.Uses++ + arg1.Uses++ + return v +} + // NewValue2I returns a new value in the block with two arguments and an auxint value. func (b *Block) NewValue2I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1 *Value) *Value { v := b.Func.newValue(op, t, b, pos) diff --git a/src/cmd/compile/internal/ssa/gen/386.rules b/src/cmd/compile/internal/ssa/gen/386.rules index 570685436a..8131f1117a 100644 --- a/src/cmd/compile/internal/ssa/gen/386.rules +++ b/src/cmd/compile/internal/ssa/gen/386.rules @@ -356,6 +356,7 @@ (GetCallerPC) -> (LoweredGetCallerPC) (GetCallerSP) -> (LoweredGetCallerSP) (Addr {sym} base) -> (LEAL {sym} base) +(LocalAddr {sym} base _) -> (LEAL {sym} base) // block rewrites (If (SETL cmp) yes no) -> (LT cmp yes no) @@ -635,14 +636,16 @@ (MOVSSstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSSstore [off1+off2] {sym} ptr val mem) (MOVSDstore [off1] {sym} (ADDLconst [off2] ptr) val mem) && is32Bit(off1+off2) -> (MOVSDstore [off1+off2] {sym} ptr val mem) -((ADD|SUB|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> - ((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {sym} val base mem) -((ADD|SUB|MUL)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> - ((ADD|SUB|MUL)SSload [off1+off2] {sym} val base mem) -((ADD|SUB|MUL)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> - ((ADD|SUB|MUL)SDload [off1+off2] {sym} val base mem) +((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> + ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {sym} val base mem) +((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> + ((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem) +((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDLconst [off2] base) mem) && is32Bit(off1+off2) -> + ((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDLconst [off2] base) val mem) && is32Bit(off1+off2) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem) +((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) -> + ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) // Fold constants into stores. (MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validOff(off) -> @@ -756,18 +759,21 @@ (MOVSDstore [off1] {sym1} (LEAL8 [off2] {sym2} ptr idx) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> (MOVSDstoreidx8 [off1+off2] {mergeSym(sym1,sym2)} ptr idx val mem) -((ADD|SUB|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) +((ADD|SUB|MUL|AND|OR|XOR)Lload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -((ADD|SUB|MUL)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) + ((ADD|SUB|MUL|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem) +((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|SUB|MUL)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -((ADD|SUB|MUL)SDload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) + ((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) +((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> - ((ADD|SUB|MUL)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + ((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAL [off2] {sym2} base) val mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) +((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) -> + ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) (MOVBload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVBloadidx1 [off] {sym} ptr idx mem) (MOVWload [off] {sym} (ADDL ptr idx) mem) && ptr.Op != OpSB -> (MOVWloadidx1 [off] {sym} ptr idx mem) @@ -845,12 +851,15 @@ (MOVSDstoreidx8 [c] {sym} ptr (ADDLconst [d] idx) val mem) -> (MOVSDstoreidx8 [int64(int32(c+8*d))] {sym} ptr idx val mem) // Merge load/store to op -((ADD|AND|OR|XOR|SUB)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB)Lload x [off] {sym} ptr mem) -((ADD|SUB|MUL)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL)SDload x [off] {sym} ptr mem) -((ADD|SUB|MUL)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL)SSload x [off] {sym} ptr mem) +((ADD|AND|OR|XOR|SUB|MUL)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|AND|OR|XOR|SUB|MUL)Lload x [off] {sym} ptr mem) +((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem) +((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && !config.use387 && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem) (MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) (MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) +(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) + && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) -> + ((ADD|AND|OR|XOR)Lconstmodify [makeValAndOff(c,off)] {sym} ptr mem) (MOVBstoreconstidx1 [x] {sym} (ADDLconst [c] ptr) idx mem) -> (MOVBstoreconstidx1 [ValAndOff(x).add(c)] {sym} ptr idx mem) @@ -1261,3 +1270,16 @@ // a register to use for holding the address of the constant pool entry. (MOVSSconst [c]) && config.ctxt.Flag_shared -> (MOVSSconst2 (MOVSSconst1 [c])) (MOVSDconst [c]) && config.ctxt.Flag_shared -> (MOVSDconst2 (MOVSDconst1 [c])) + +(CMP(L|W|B) l:(MOV(L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l, x) && clobber(l) -> (CMP(L|W|B)load {sym} [off] ptr x mem) +(CMP(L|W|B) x l:(MOV(L|W|B)load {sym} [off] ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> (InvertFlags (CMP(L|W|B)load {sym} [off] ptr x mem)) + +(CMP(L|W|B)const l:(MOV(L|W|B)load {sym} [off] ptr mem) [c]) + && l.Uses == 1 + && validValAndOff(c, off) + && clobber(l) -> + @l.Block (CMP(L|W|B)constload {sym} [makeValAndOff(c,off)] ptr mem) + +(CMPLload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int32(c)),off) -> (CMPLconstload {sym} [makeValAndOff(int64(int32(c)),off)] ptr mem) +(CMPWload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int16(c)),off) -> (CMPWconstload {sym} [makeValAndOff(int64(int16(c)),off)] ptr mem) +(CMPBload {sym} [off] ptr (MOVLconst [c]) mem) && validValAndOff(int64(int8(c)),off) -> (CMPBconstload {sym} [makeValAndOff(int64(int8(c)),off)] ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/386Ops.go b/src/cmd/compile/internal/ssa/gen/386Ops.go index 6c1d506ae4..1786eea7cf 100644 --- a/src/cmd/compile/internal/ssa/gen/386Ops.go +++ b/src/cmd/compile/internal/ssa/gen/386Ops.go @@ -117,9 +117,11 @@ func init() { gp11mod = regInfo{inputs: []regMask{ax, gpsp &^ dx}, outputs: []regMask{dx}, clobbers: ax} gp21mul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}} - gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}} - gp1flags = regInfo{inputs: []regMask{gpsp}} - flagsgp = regInfo{inputs: nil, outputs: gponly} + gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}} + gp1flags = regInfo{inputs: []regMask{gpsp}} + gp0flagsLoad = regInfo{inputs: []regMask{gpspsb, 0}} + gp1flagsLoad = regInfo{inputs: []regMask{gpspsb, gpsp, 0}} + flagsgp = regInfo{inputs: nil, outputs: gponly} readflags = regInfo{inputs: nil, outputs: gponly} flagsgpax = regInfo{inputs: nil, clobbers: ax, outputs: []regMask{gp &^ ax}} @@ -181,6 +183,8 @@ func init() { {name: "SUBSDload", argLength: 3, reg: fp21load, asm: "SUBSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem {name: "MULSSload", argLength: 3, reg: fp21load, asm: "MULSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem {name: "MULSDload", argLength: 3, reg: fp21load, asm: "MULSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "DIVSSload", argLength: 3, reg: fp21load, asm: "DIVSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "DIVSDload", argLength: 3, reg: fp21load, asm: "DIVSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem // binary ops {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true}, // arg0 + arg1 @@ -235,6 +239,16 @@ func init() { {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint {name: "CMPBconst", argLength: 1, reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"}, // arg0 compare to auxint + // compare *(arg0+auxint+aux) to arg1 (in that order). arg2=mem. + {name: "CMPLload", argLength: 3, reg: gp1flagsLoad, asm: "CMPL", aux: "SymOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + {name: "CMPWload", argLength: 3, reg: gp1flagsLoad, asm: "CMPW", aux: "SymOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + {name: "CMPBload", argLength: 3, reg: gp1flagsLoad, asm: "CMPB", aux: "SymOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + + // compare *(arg0+ValAndOff(AuxInt).Off()+aux) to ValAndOff(AuxInt).Val() (in that order). arg1=mem. + {name: "CMPLconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPL", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + {name: "CMPWconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPW", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + {name: "CMPBconstload", argLength: 2, reg: gp0flagsLoad, asm: "CMPB", aux: "SymValAndOff", typ: "Flags", symEffect: "Read", faultOnNilArg0: true}, + {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f32 {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags", usesScratch: true}, // arg0 compare to arg1, f64 @@ -267,11 +281,12 @@ func init() { {name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-15 {name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true}, // arg0 rotate left auxint, rotate amount 0-7 - {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem - {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem - {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & tmp, tmp loaded from arg1+auxint+aux, arg2 = mem - {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | tmp, tmp loaded from arg1+auxint+aux, arg2 = mem - {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 + tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "MULLload", argLength: 3, reg: gp21load, asm: "IMULL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 & tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 | tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem // unary ops {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0 @@ -346,11 +361,17 @@ func init() { {name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem // direct binary-op on memory (read-modify-write) - {name: "ADDLmodify", argLength: 3, reg: gpstore, asm: "ADDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) += arg1, arg2=mem - {name: "SUBLmodify", argLength: 3, reg: gpstore, asm: "SUBL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) -= arg1, arg2=mem - {name: "ANDLmodify", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) &= arg1, arg2=mem - {name: "ORLmodify", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) |= arg1, arg2=mem - {name: "XORLmodify", argLength: 3, reg: gpstore, asm: "XORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) ^= arg1, arg2=mem + {name: "ADDLmodify", argLength: 3, reg: gpstore, asm: "ADDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) += arg1, arg2=mem + {name: "SUBLmodify", argLength: 3, reg: gpstore, asm: "SUBL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) -= arg1, arg2=mem + {name: "ANDLmodify", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) &= arg1, arg2=mem + {name: "ORLmodify", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) |= arg1, arg2=mem + {name: "XORLmodify", argLength: 3, reg: gpstore, asm: "XORL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, clobberFlags: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) ^= arg1, arg2=mem + + // direct binary-op on memory with a constant (read-modify-write) + {name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // add ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem // indexed loads/stores {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", aux: "SymOff", symEffect: "Read"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index dd71ccaf5e..4c11f8d036 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -455,6 +455,8 @@ (GetCallerSP) -> (LoweredGetCallerSP) (Addr {sym} base) && config.PtrSize == 8 -> (LEAQ {sym} base) (Addr {sym} base) && config.PtrSize == 4 -> (LEAL {sym} base) +(LocalAddr {sym} base _) && config.PtrSize == 8 -> (LEAQ {sym} base) +(LocalAddr {sym} base _) && config.PtrSize == 4 -> (LEAL {sym} base) (MOVBstore [off] {sym} ptr y:(SETL x) mem) && y.Uses == 1 -> (SETLstore [off] {sym} ptr x mem) (MOVBstore [off] {sym} ptr y:(SETLE x) mem) && y.Uses == 1 -> (SETLEstore [off] {sym} ptr x mem) @@ -766,6 +768,11 @@ (ROLWconst [c] (ROLWconst [d] x)) -> (ROLWconst [(c+d)&15] x) (ROLBconst [c] (ROLBconst [d] x)) -> (ROLBconst [(c+d)& 7] x) +(RotateLeft8 a b) -> (ROLB a b) +(RotateLeft16 a b) -> (ROLW a b) +(RotateLeft32 a b) -> (ROLL a b) +(RotateLeft64 a b) -> (ROLQ a b) + // Non-constant rotates. // We want to issue a rotate when the Go source contains code like // y &= 63 @@ -986,6 +993,8 @@ (MOVLQZX x:(MOVQload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLload [off] {sym} ptr mem) (MOVLQZX x) && zeroUpper32Bits(x,3) -> x +(MOVWQZX x) && zeroUpper48Bits(x,3) -> x +(MOVBQZX x) && zeroUpper56Bits(x,3) -> x (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVBloadidx1 [off] {sym} ptr idx mem) (MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 [off] {sym} ptr idx mem) @@ -1033,12 +1042,18 @@ ((ADD|SUB|AND|OR|XOR)Qload [off1+off2] {sym} val base mem) ((ADD|SUB|AND|OR|XOR)Lload [off1] {sym} val (ADDQconst [off2] base) mem) && is32Bit(off1+off2) -> ((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {sym} val base mem) -((ADD|SUB|MUL)SSload [off1] {sym} val (ADDQconst [off2] base) mem) && is32Bit(off1+off2) -> - ((ADD|SUB|MUL)SSload [off1+off2] {sym} val base mem) -((ADD|SUB|MUL)SDload [off1] {sym} val (ADDQconst [off2] base) mem) && is32Bit(off1+off2) -> - ((ADD|SUB|MUL)SDload [off1+off2] {sym} val base mem) -(ADD(L|Q)constmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) -> - (ADD(L|Q)constmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) +((ADD|SUB|MUL|DIV)SSload [off1] {sym} val (ADDQconst [off2] base) mem) && is32Bit(off1+off2) -> + ((ADD|SUB|MUL|DIV)SSload [off1+off2] {sym} val base mem) +((ADD|SUB|MUL|DIV)SDload [off1] {sym} val (ADDQconst [off2] base) mem) && is32Bit(off1+off2) -> + ((ADD|SUB|MUL|DIV)SDload [off1+off2] {sym} val base mem) +((ADD|AND|OR|XOR)Qconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) -> + ((ADD|AND|OR|XOR)Qconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) +((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd(off2) -> + ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) +((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(off1+off2) -> + ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {sym} base val mem) +((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(off1+off2) -> + ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {sym} base val mem) // Fold constants into stores. (MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) && validValAndOff(c,off) -> @@ -1073,15 +1088,24 @@ ((ADD|SUB|AND|OR|XOR)Lload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> ((ADD|SUB|AND|OR|XOR)Lload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -((ADD|SUB|MUL)SSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) +((ADD|SUB|MUL|DIV)SSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - ((ADD|SUB|MUL)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -((ADD|SUB|MUL)SDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) + ((ADD|SUB|MUL|DIV)SSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) +((ADD|SUB|MUL|DIV)SDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> - ((ADD|SUB|MUL)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) -(ADD(L|Q)constmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + ((ADD|SUB|MUL|DIV)SDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) +((ADD|AND|OR|XOR)Qconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) -> - (ADD(L|Q)constmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + ((ADD|AND|OR|XOR)Qconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) -> + ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> + ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) +((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> + ((ADD|SUB|AND|OR|XOR)Lmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) // generating indexed loads and stores (MOV(B|W|L|Q|SS|SD)load [off1] {sym1} (LEAQ1 [off2] {sym2} ptr idx) mem) && is32Bit(off1+off2) && canMergeSym(sym1, sym2) -> @@ -2265,8 +2289,14 @@ // TODO: add indexed variants? ((ADD|SUB|AND|OR|XOR)Q x l:(MOVQload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Qload x [off] {sym} ptr mem) ((ADD|SUB|AND|OR|XOR)L x l:(MOVLload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|AND|OR|XOR)Lload x [off] {sym} ptr mem) -((ADD|SUB|MUL)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL)SDload x [off] {sym} ptr mem) -((ADD|SUB|MUL)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL)SSload x [off] {sym} ptr mem) +((ADD|SUB|MUL|DIV)SD x l:(MOVSDload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SDload x [off] {sym} ptr mem) +((ADD|SUB|MUL|DIV)SS x l:(MOVSSload [off] {sym} ptr mem)) && canMergeLoad(v, l, x) && clobber(l) -> ((ADD|SUB|MUL|DIV)SSload x [off] {sym} ptr mem) +(MOVLstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Lload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) +(MOVLstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)L l:(MOVLload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) -> + ((ADD|SUB|AND|OR|XOR)Lmodify [off] {sym} ptr x mem) +(MOVQstore {sym} [off] ptr y:((ADD|AND|OR|XOR)Qload x [off] {sym} ptr mem) mem) && y.Uses==1 && clobber(y) -> ((ADD|AND|OR|XOR)Qmodify [off] {sym} ptr x mem) +(MOVQstore {sym} [off] ptr y:((ADD|SUB|AND|OR|XOR)Q l:(MOVQload [off] {sym} ptr mem) x) mem) && y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) -> + ((ADD|SUB|AND|OR|XOR)Qmodify [off] {sym} ptr x mem) // Merge ADDQconst and LEAQ into atomic loads. (MOVQatomicload [off1] {sym} (ADDQconst [off2] ptr) mem) && is32Bit(off1+off2) -> @@ -2350,12 +2380,12 @@ (MOVWQZX (MOVBQZX x)) -> (MOVBQZX x) (MOVBQZX (MOVBQZX x)) -> (MOVBQZX x) -(MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) +(MOVQstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Qconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) -> - (ADDQconstmodify {sym} [makeValAndOff(c,off)] ptr mem) -(MOVLstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) + ((ADD|AND|OR|XOR)Qconstmodify {sym} [makeValAndOff(c,off)] ptr mem) +(MOVLstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) -> - (ADDLconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + ((ADD|AND|OR|XOR)Lconstmodify {sym} [makeValAndOff(c,off)] ptr mem) // float <-> int register moves, with no conversion. // These come up when compiling math.{Float{32,64}bits,Float{32,64}frombits}. @@ -2376,11 +2406,6 @@ (XORQload x [off] {sym} ptr (MOVSDstore [off] {sym} ptr y _)) -> (XORQ x (MOVQf2i y)) (XORLload x [off] {sym} ptr (MOVSSstore [off] {sym} ptr y _)) -> (XORL x (MOVLf2i y)) -(ADDQconstmodify [valOff] {sym} ptr (MOVSDstore [ValAndOff(valOff).Off()] {sym} ptr x _)) -> - (ADDQconst [ValAndOff(valOff).Val()] (MOVQf2i x)) -(ADDLconstmodify [valOff] {sym} ptr (MOVSSstore [ValAndOff(valOff).Off()] {sym} ptr x _)) -> - (ADDLconst [ValAndOff(valOff).Val()] (MOVLf2i x)) - (ADDSDload x [off] {sym} ptr (MOVQstore [off] {sym} ptr y _)) -> (ADDSD x (MOVQi2f y)) (ADDSSload x [off] {sym} ptr (MOVLstore [off] {sym} ptr y _)) -> (ADDSS x (MOVLi2f y)) (SUBSDload x [off] {sym} ptr (MOVQstore [off] {sym} ptr y _)) -> (SUBSD x (MOVQi2f y)) @@ -2405,6 +2430,13 @@ // See issue 22947 for details (ADD(Q|L)const [off] x:(SP)) -> (LEA(Q|L) [off] x) +// HMULx is commutative, but its first argument must go in AX. +// If possible, put a rematerializeable value in the first argument slot, +// to reduce the odds that another value will be have to spilled +// specifically to free up AX. +(HMUL(Q|L) x y) && !x.rematerializeable() && y.rematerializeable() -> (HMUL(Q|L) y x) +(HMUL(Q|L)U x y) && !x.rematerializeable() && y.rematerializeable() -> (HMUL(Q|L)U y x) + // Fold loads into compares // Note: these may be undone by the flagalloc pass. (CMP(Q|L|W|B) l:(MOV(Q|L|W|B)load {sym} [off] ptr mem) x) && canMergeLoad(v, l, x) && clobber(l) -> (CMP(Q|L|W|B)load {sym} [off] ptr x mem) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 5a8634abd1..512df99694 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -189,6 +189,8 @@ func init() { {name: "SUBSDload", argLength: 3, reg: fp21load, asm: "SUBSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 - tmp, tmp loaded from arg1+auxint+aux, arg2 = mem {name: "MULSSload", argLength: 3, reg: fp21load, asm: "MULSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem {name: "MULSDload", argLength: 3, reg: fp21load, asm: "MULSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 * tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "DIVSSload", argLength: 3, reg: fp21load, asm: "DIVSS", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp32 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + {name: "DIVSDload", argLength: 3, reg: fp21load, asm: "DIVSD", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, symEffect: "Read"}, // fp64 arg0 / tmp, tmp loaded from arg1+auxint+aux, arg2 = mem // binary ops {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true, clobberFlags: true}, // arg0 + arg1 @@ -225,20 +227,26 @@ func init() { {name: "MULQU2", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx, ax}}, commutative: true, asm: "MULQ", clobberFlags: true}, // arg0 * arg1, returns (hi, lo) {name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r) - {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1 - {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1 - {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint - {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint + {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1 + {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 & arg1 + {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint + {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 & auxint + {name: "ANDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem - {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1 - {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1 - {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint - {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint + {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1 + {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 | arg1 + {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint + {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 | auxint + {name: "ORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem - {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1 - {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1 - {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint - {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint + {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1 + {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true}, // arg0 ^ arg1 + {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint + {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true}, // arg0 ^ auxint + {name: "XORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1 {name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1 @@ -338,6 +346,18 @@ func init() { {name: "XORQload", argLength: 3, reg: gp21load, asm: "XORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read"}, // arg0 ^ tmp, tmp loaded from arg1+auxint+aux, arg2 = mem + // direct binary-op on memory (read-modify-write) + {name: "ADDQmodify", argLength: 3, reg: gpstore, asm: "ADDQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) += arg1, arg2=mem + {name: "SUBQmodify", argLength: 3, reg: gpstore, asm: "SUBQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) -= arg1, arg2=mem + {name: "ANDQmodify", argLength: 3, reg: gpstore, asm: "ANDQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) &= arg1, arg2=mem + {name: "ORQmodify", argLength: 3, reg: gpstore, asm: "ORQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) |= arg1, arg2=mem + {name: "XORQmodify", argLength: 3, reg: gpstore, asm: "XORQ", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) ^= arg1, arg2=mem + {name: "ADDLmodify", argLength: 3, reg: gpstore, asm: "ADDL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) += arg1, arg2=mem + {name: "SUBLmodify", argLength: 3, reg: gpstore, asm: "SUBL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) -= arg1, arg2=mem + {name: "ANDLmodify", argLength: 3, reg: gpstore, asm: "ANDL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) &= arg1, arg2=mem + {name: "ORLmodify", argLength: 3, reg: gpstore, asm: "ORL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) |= arg1, arg2=mem + {name: "XORLmodify", argLength: 3, reg: gpstore, asm: "XORL", aux: "SymOff", typ: "Mem", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write"}, // *(arg0+auxint+aux) ^= arg1, arg2=mem + // unary ops {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true}, // -arg0 {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true}, // -arg0 diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules index 65b11c9980..fdf4d1e900 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM.rules @@ -253,6 +253,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVWaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVWaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) @@ -811,6 +812,10 @@ (SUBconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(uint32(-c)) -> (ADDconst [int64(int32(-c))] x) (ANDconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c)) -> (BICconst [int64(int32(^uint32(c)))] x) (BICconst [c] x) && !isARMImmRot(uint32(c)) && isARMImmRot(^uint32(c)) -> (ANDconst [int64(int32(^uint32(c)))] x) +(ADDconst [c] x) && objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && uint32(-c)<=0xffff -> (SUBconst [int64(int32(-c))] x) +(SUBconst [c] x) && objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && uint32(-c)<=0xffff -> (ANDconst [int64(int32(-c))] x) +(ANDconst [c] x) && objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && ^uint32(c)<=0xffff -> (BICconst [int64(int32(^uint32(c)))] x) +(BICconst [c] x) && objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && ^uint32(c)<=0xffff -> (ANDconst [int64(int32(^uint32(c)))] x) (ADDconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(c+d))]) (ADDconst [c] (ADDconst [d] x)) -> (ADDconst [int64(int32(c+d))] x) (ADDconst [c] (SUBconst [d] x)) -> (ADDconst [int64(int32(c-d))] x) @@ -1335,67 +1340,207 @@ // comparison simplification (CMP x (RSBconst [0] y)) -> (CMN x y) (CMN x (RSBconst [0] y)) -> (CMP x y) -(EQ (CMPconst [0] (SUB x y)) yes no) -> (EQ (CMP x y) yes no) -(EQ (CMPconst [0] (SUBconst [c] x)) yes no) -> (EQ (CMPconst [c] x) yes no) -(EQ (CMPconst [0] (SUBshiftLL x y [c])) yes no) -> (EQ (CMPshiftLL x y [c]) yes no) -(EQ (CMPconst [0] (SUBshiftRL x y [c])) yes no) -> (EQ (CMPshiftRL x y [c]) yes no) -(EQ (CMPconst [0] (SUBshiftRA x y [c])) yes no) -> (EQ (CMPshiftRA x y [c]) yes no) -(EQ (CMPconst [0] (SUBshiftLLreg x y z)) yes no) -> (EQ (CMPshiftLLreg x y z) yes no) -(EQ (CMPconst [0] (SUBshiftRLreg x y z)) yes no) -> (EQ (CMPshiftRLreg x y z) yes no) -(EQ (CMPconst [0] (SUBshiftRAreg x y z)) yes no) -> (EQ (CMPshiftRAreg x y z) yes no) -(NE (CMPconst [0] (SUB x y)) yes no) -> (NE (CMP x y) yes no) -(NE (CMPconst [0] (SUBconst [c] x)) yes no) -> (NE (CMPconst [c] x) yes no) -(NE (CMPconst [0] (SUBshiftLL x y [c])) yes no) -> (NE (CMPshiftLL x y [c]) yes no) -(NE (CMPconst [0] (SUBshiftRL x y [c])) yes no) -> (NE (CMPshiftRL x y [c]) yes no) -(NE (CMPconst [0] (SUBshiftRA x y [c])) yes no) -> (NE (CMPshiftRA x y [c]) yes no) -(NE (CMPconst [0] (SUBshiftLLreg x y z)) yes no) -> (NE (CMPshiftLLreg x y z) yes no) -(NE (CMPconst [0] (SUBshiftRLreg x y z)) yes no) -> (NE (CMPshiftRLreg x y z) yes no) -(NE (CMPconst [0] (SUBshiftRAreg x y z)) yes no) -> (NE (CMPshiftRAreg x y z) yes no) -(EQ (CMPconst [0] (ADD x y)) yes no) -> (EQ (CMN x y) yes no) -(EQ (CMPconst [0] (ADDconst [c] x)) yes no) -> (EQ (CMNconst [c] x) yes no) -(EQ (CMPconst [0] (ADDshiftLL x y [c])) yes no) -> (EQ (CMNshiftLL x y [c]) yes no) -(EQ (CMPconst [0] (ADDshiftRL x y [c])) yes no) -> (EQ (CMNshiftRL x y [c]) yes no) -(EQ (CMPconst [0] (ADDshiftRA x y [c])) yes no) -> (EQ (CMNshiftRA x y [c]) yes no) -(EQ (CMPconst [0] (ADDshiftLLreg x y z)) yes no) -> (EQ (CMNshiftLLreg x y z) yes no) -(EQ (CMPconst [0] (ADDshiftRLreg x y z)) yes no) -> (EQ (CMNshiftRLreg x y z) yes no) -(EQ (CMPconst [0] (ADDshiftRAreg x y z)) yes no) -> (EQ (CMNshiftRAreg x y z) yes no) -(NE (CMPconst [0] (ADD x y)) yes no) -> (NE (CMN x y) yes no) -(NE (CMPconst [0] (ADDconst [c] x)) yes no) -> (NE (CMNconst [c] x) yes no) -(NE (CMPconst [0] (ADDshiftLL x y [c])) yes no) -> (NE (CMNshiftLL x y [c]) yes no) -(NE (CMPconst [0] (ADDshiftRL x y [c])) yes no) -> (NE (CMNshiftRL x y [c]) yes no) -(NE (CMPconst [0] (ADDshiftRA x y [c])) yes no) -> (NE (CMNshiftRA x y [c]) yes no) -(NE (CMPconst [0] (ADDshiftLLreg x y z)) yes no) -> (NE (CMNshiftLLreg x y z) yes no) -(NE (CMPconst [0] (ADDshiftRLreg x y z)) yes no) -> (NE (CMNshiftRLreg x y z) yes no) -(NE (CMPconst [0] (ADDshiftRAreg x y z)) yes no) -> (NE (CMNshiftRAreg x y z) yes no) -(EQ (CMPconst [0] (AND x y)) yes no) -> (EQ (TST x y) yes no) -(EQ (CMPconst [0] (ANDconst [c] x)) yes no) -> (EQ (TSTconst [c] x) yes no) -(EQ (CMPconst [0] (ANDshiftLL x y [c])) yes no) -> (EQ (TSTshiftLL x y [c]) yes no) -(EQ (CMPconst [0] (ANDshiftRL x y [c])) yes no) -> (EQ (TSTshiftRL x y [c]) yes no) -(EQ (CMPconst [0] (ANDshiftRA x y [c])) yes no) -> (EQ (TSTshiftRA x y [c]) yes no) -(EQ (CMPconst [0] (ANDshiftLLreg x y z)) yes no) -> (EQ (TSTshiftLLreg x y z) yes no) -(EQ (CMPconst [0] (ANDshiftRLreg x y z)) yes no) -> (EQ (TSTshiftRLreg x y z) yes no) -(EQ (CMPconst [0] (ANDshiftRAreg x y z)) yes no) -> (EQ (TSTshiftRAreg x y z) yes no) -(NE (CMPconst [0] (AND x y)) yes no) -> (NE (TST x y) yes no) -(NE (CMPconst [0] (ANDconst [c] x)) yes no) -> (NE (TSTconst [c] x) yes no) -(NE (CMPconst [0] (ANDshiftLL x y [c])) yes no) -> (NE (TSTshiftLL x y [c]) yes no) -(NE (CMPconst [0] (ANDshiftRL x y [c])) yes no) -> (NE (TSTshiftRL x y [c]) yes no) -(NE (CMPconst [0] (ANDshiftRA x y [c])) yes no) -> (NE (TSTshiftRA x y [c]) yes no) -(NE (CMPconst [0] (ANDshiftLLreg x y z)) yes no) -> (NE (TSTshiftLLreg x y z) yes no) -(NE (CMPconst [0] (ANDshiftRLreg x y z)) yes no) -> (NE (TSTshiftRLreg x y z) yes no) -(NE (CMPconst [0] (ANDshiftRAreg x y z)) yes no) -> (NE (TSTshiftRAreg x y z) yes no) -(EQ (CMPconst [0] (XOR x y)) yes no) -> (EQ (TEQ x y) yes no) -(EQ (CMPconst [0] (XORconst [c] x)) yes no) -> (EQ (TEQconst [c] x) yes no) -(EQ (CMPconst [0] (XORshiftLL x y [c])) yes no) -> (EQ (TEQshiftLL x y [c]) yes no) -(EQ (CMPconst [0] (XORshiftRL x y [c])) yes no) -> (EQ (TEQshiftRL x y [c]) yes no) -(EQ (CMPconst [0] (XORshiftRA x y [c])) yes no) -> (EQ (TEQshiftRA x y [c]) yes no) -(EQ (CMPconst [0] (XORshiftLLreg x y z)) yes no) -> (EQ (TEQshiftLLreg x y z) yes no) -(EQ (CMPconst [0] (XORshiftRLreg x y z)) yes no) -> (EQ (TEQshiftRLreg x y z) yes no) -(EQ (CMPconst [0] (XORshiftRAreg x y z)) yes no) -> (EQ (TEQshiftRAreg x y z) yes no) -(NE (CMPconst [0] (XOR x y)) yes no) -> (NE (TEQ x y) yes no) -(NE (CMPconst [0] (XORconst [c] x)) yes no) -> (NE (TEQconst [c] x) yes no) -(NE (CMPconst [0] (XORshiftLL x y [c])) yes no) -> (NE (TEQshiftLL x y [c]) yes no) -(NE (CMPconst [0] (XORshiftRL x y [c])) yes no) -> (NE (TEQshiftRL x y [c]) yes no) -(NE (CMPconst [0] (XORshiftRA x y [c])) yes no) -> (NE (TEQshiftRA x y [c]) yes no) -(NE (CMPconst [0] (XORshiftLLreg x y z)) yes no) -> (NE (TEQshiftLLreg x y z) yes no) -(NE (CMPconst [0] (XORshiftRLreg x y z)) yes no) -> (NE (TEQshiftRLreg x y z) yes no) -(NE (CMPconst [0] (XORshiftRAreg x y z)) yes no) -> (NE (TEQshiftRAreg x y z) yes no) +(EQ (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (EQ (CMP x y) yes no) +(EQ (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (EQ (CMP a (MUL x y)) yes no) +(EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (EQ (CMPconst [c] x) yes no) +(EQ (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (EQ (CMPshiftLL x y [c]) yes no) +(EQ (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (EQ (CMPshiftRL x y [c]) yes no) +(EQ (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (EQ (CMPshiftRA x y [c]) yes no) +(EQ (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (EQ (CMPshiftLLreg x y z) yes no) +(EQ (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (EQ (CMPshiftRLreg x y z) yes no) +(EQ (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (EQ (CMPshiftRAreg x y z) yes no) +(NE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (NE (CMP x y) yes no) +(NE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (NE (CMP a (MUL x y)) yes no) +(NE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (NE (CMPconst [c] x) yes no) +(NE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (NE (CMPshiftLL x y [c]) yes no) +(NE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (NE (CMPshiftRL x y [c]) yes no) +(NE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (NE (CMPshiftRA x y [c]) yes no) +(NE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (CMPshiftLLreg x y z) yes no) +(NE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (CMPshiftRLreg x y z) yes no) +(NE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (CMPshiftRAreg x y z) yes no) +(EQ (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (EQ (CMN x y) yes no) +(EQ (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (EQ (CMN a (MUL x y)) yes no) +(EQ (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (EQ (CMNconst [c] x) yes no) +(EQ (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (EQ (CMNshiftLL x y [c]) yes no) +(EQ (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (EQ (CMNshiftRL x y [c]) yes no) +(EQ (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (EQ (CMNshiftRA x y [c]) yes no) +(EQ (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (EQ (CMNshiftLLreg x y z) yes no) +(EQ (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (EQ (CMNshiftRLreg x y z) yes no) +(EQ (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (EQ (CMNshiftRAreg x y z) yes no) +(NE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (NE (CMN x y) yes no) +(NE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (NE (CMN a (MUL x y)) yes no) +(NE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (NE (CMNconst [c] x) yes no) +(NE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (NE (CMNshiftLL x y [c]) yes no) +(NE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (NE (CMNshiftRL x y [c]) yes no) +(NE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (NE (CMNshiftRA x y [c]) yes no) +(NE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (CMNshiftLLreg x y z) yes no) +(NE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (CMNshiftRLreg x y z) yes no) +(NE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (CMNshiftRAreg x y z) yes no) +(EQ (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (EQ (TST x y) yes no) +(EQ (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (EQ (TSTconst [c] x) yes no) +(EQ (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (EQ (TSTshiftLL x y [c]) yes no) +(EQ (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (EQ (TSTshiftRL x y [c]) yes no) +(EQ (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (EQ (TSTshiftRA x y [c]) yes no) +(EQ (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (EQ (TSTshiftLLreg x y z) yes no) +(EQ (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (EQ (TSTshiftRLreg x y z) yes no) +(EQ (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (EQ (TSTshiftRAreg x y z) yes no) +(NE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (NE (TST x y) yes no) +(NE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (NE (TSTconst [c] x) yes no) +(NE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (NE (TSTshiftLL x y [c]) yes no) +(NE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (NE (TSTshiftRL x y [c]) yes no) +(NE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (NE (TSTshiftRA x y [c]) yes no) +(NE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TSTshiftLLreg x y z) yes no) +(NE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TSTshiftRLreg x y z) yes no) +(NE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TSTshiftRAreg x y z) yes no) +(EQ (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (EQ (TEQ x y) yes no) +(EQ (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (EQ (TEQconst [c] x) yes no) +(EQ (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (EQ (TEQshiftLL x y [c]) yes no) +(EQ (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (EQ (TEQshiftRL x y [c]) yes no) +(EQ (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (EQ (TEQshiftRA x y [c]) yes no) +(EQ (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (EQ (TEQshiftLLreg x y z) yes no) +(EQ (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (EQ (TEQshiftRLreg x y z) yes no) +(EQ (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (EQ (TEQshiftRAreg x y z) yes no) +(NE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (NE (TEQ x y) yes no) +(NE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (NE (TEQconst [c] x) yes no) +(NE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (NE (TEQshiftLL x y [c]) yes no) +(NE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (NE (TEQshiftRL x y [c]) yes no) +(NE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (NE (TEQshiftRA x y [c]) yes no) +(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no) +(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no) +(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no) +(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL x y)) yes no) +(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no) +(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no) +(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL x y)) yes no) +(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no) +(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no) +(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL x y)) yes no) +(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no) +(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no) +(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL x y)) yes no) +(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no) +(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no) +(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no) +(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (TSTshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LE (TST x y) yes no) +(LE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LE (TSTconst [c] x) yes no) +(LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (TSTshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TSTshiftRAreg x y z) yes no) +(LT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LT (TEQ x y) yes no) +(LT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LT (TEQconst [c] x) yes no) +(LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftLL x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftRL x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (TEQshiftRA x y [c]) yes no) +(LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftLLreg x y z) yes no) +(LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftRLreg x y z) yes no) +(LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (TEQshiftRAreg x y z) yes no) +(LE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (LE (TEQ x y) yes no) +(LE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (LE (TEQconst [c] x) yes no) +(LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftLL x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftRL x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (TEQshiftRA x y [c]) yes no) +(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no) +(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no) +(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no) +(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL x y)) yes no) +(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no) +(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no) +(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL x y)) yes no) +(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no) +(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no) +(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no) +(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no) +(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL x y)) yes no) +(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no) +(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no) +(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL x y)) yes no) +(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no) +(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (TSTshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GE (TST x y) yes no) +(GE (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GE (TSTconst [c] x) yes no) +(GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (TSTshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (TSTshiftRAreg x y z) yes no) +(GT (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GT (TEQ x y) yes no) +(GT (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GT (TEQconst [c] x) yes no) +(GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftLL x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftRL x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (TEQshiftRA x y [c]) yes no) +(GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftLLreg x y z) yes no) +(GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftRLreg x y z) yes no) +(GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (TEQshiftRAreg x y z) yes no) +(GE (CMPconst [0] l:(XOR x y)) yes no) && l.Uses==1 -> (GE (TEQ x y) yes no) +(GE (CMPconst [0] l:(XORconst [c] x)) yes no) && l.Uses==1 -> (GE (TEQconst [c] x) yes no) +(GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftLL x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftRL x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (TEQshiftRA x y [c]) yes no) +(GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftLLreg x y z) yes no) +(GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRLreg x y z) yes no) +(GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (TEQshiftRAreg x y z) yes no) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index a7e747e6e7..ede7ed3d7a 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -317,6 +317,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVDaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVDaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) @@ -573,8 +574,17 @@ (EQ (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (EQ (TST x y) yes no) (NE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (NE (TST x y) yes no) -(EQ (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (EQ (TST x y) yes no) -(NE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (NE (TST x y) yes no) +(LT (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LT (TST x y) yes no) +(LE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LE (TST x y) yes no) +(GT (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GT (TST x y) yes no) +(GE (CMPconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GE (TST x y) yes no) + +(EQ (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (EQ (TSTW x y) yes no) +(NE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (NE (TSTW x y) yes no) +(LT (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LT (TSTW x y) yes no) +(LE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (LE (TSTW x y) yes no) +(GT (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GT (TSTW x y) yes no) +(GE (CMPWconst [0] z:(AND x y)) yes no) && z.Uses == 1 -> (GE (TSTW x y) yes no) (EQ (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (TSTconst [c] y) yes no) (NE (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (NE (TSTconst [c] y) yes no) @@ -583,16 +593,81 @@ (GT (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (GT (TSTconst [c] y) yes no) (GE (CMPconst [0] x:(ANDconst [c] y)) yes no) && x.Uses == 1 -> (GE (TSTconst [c] y) yes no) +(EQ (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (CMNconst [c] y) yes no) +(NE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (NE (CMNconst [c] y) yes no) +(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LT (CMNconst [c] y) yes no) +(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LE (CMNconst [c] y) yes no) +(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GT (CMNconst [c] y) yes no) +(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GE (CMNconst [c] y) yes no) + +(EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (EQ (CMNWconst [c] y) yes no) +(NE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (NE (CMNWconst [c] y) yes no) +(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LT (CMNWconst [c] y) yes no) +(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (LE (CMNWconst [c] y) yes no) +(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GT (CMNWconst [c] y) yes no) +(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 -> (GE (CMNWconst [c] y) yes no) + (EQ (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (EQ (CMN x y) yes no) (NE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (NE (CMN x y) yes no) +(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LT (CMN x y) yes no) +(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LE (CMN x y) yes no) +(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GT (CMN x y) yes no) +(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GE (CMN x y) yes no) + +(EQ (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (EQ (CMNW x y) yes no) +(NE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (NE (CMNW x y) yes no) +(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LT (CMNW x y) yes no) +(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (LE (CMNW x y) yes no) +(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GT (CMNW x y) yes no) +(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 -> (GE (CMNW x y) yes no) + (EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (EQ (CMN x y) yes no) (NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (NE (CMN x y) yes no) +(LT (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (LT (CMN x y) yes no) +(LE (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (LE (CMN x y) yes no) +(GT (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (GT (CMN x y) yes no) +(GE (CMP x z:(NEG y)) yes no) && z.Uses == 1 -> (GE (CMN x y) yes no) + +(EQ (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (EQ (CMNW x y) yes no) +(NE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (NE (CMNW x y) yes no) +(LT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (LT (CMNW x y) yes no) +(LE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (LE (CMNW x y) yes no) +(GT (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (GT (CMNW x y) yes no) +(GE (CMPW x z:(NEG y)) yes no) && z.Uses == 1 -> (GE (CMNW x y) yes no) (EQ (CMPconst [0] x) yes no) -> (Z x yes no) (NE (CMPconst [0] x) yes no) -> (NZ x yes no) (EQ (CMPWconst [0] x) yes no) -> (ZW x yes no) (NE (CMPWconst [0] x) yes no) -> (NZW x yes no) +(EQ (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (EQ (CMN a (MUL x y)) yes no) +(NE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (NE (CMN a (MUL x y)) yes no) +(LT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (LT (CMN a (MUL x y)) yes no) +(LE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (LE (CMN a (MUL x y)) yes no) +(GT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (GT (CMN a (MUL x y)) yes no) +(GE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 -> (GE (CMN a (MUL x y)) yes no) + +(EQ (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (EQ (CMP a (MUL x y)) yes no) +(NE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (NE (CMP a (MUL x y)) yes no) +(LE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (LE (CMP a (MUL x y)) yes no) +(LT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (LT (CMP a (MUL x y)) yes no) +(GE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (GE (CMP a (MUL x y)) yes no) +(GT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 -> (GT (CMP a (MUL x y)) yes no) + +(EQ (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (EQ (CMNW a (MULW x y)) yes no) +(NE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (NE (CMNW a (MULW x y)) yes no) +(LE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (LE (CMNW a (MULW x y)) yes no) +(LT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (LT (CMNW a (MULW x y)) yes no) +(GE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (GE (CMNW a (MULW x y)) yes no) +(GT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 -> (GT (CMNW a (MULW x y)) yes no) + +(EQ (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (EQ (CMPW a (MULW x y)) yes no) +(NE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (NE (CMPW a (MULW x y)) yes no) +(LE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (LE (CMPW a (MULW x y)) yes no) +(LT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (LT (CMPW a (MULW x y)) yes no) +(GE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (GE (CMPW a (MULW x y)) yes no) +(GT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 -> (GT (CMPW a (MULW x y)) yes no) + // Absorb bit-tests into block (Z (ANDconst [c] x) yes no) && oneBit(c) -> (TBZ {ntz(c)} x yes no) (NZ (ANDconst [c] x) yes no) && oneBit(c) -> (TBNZ {ntz(c)} x yes no) @@ -649,6 +724,8 @@ (MOVHload [off] {sym} (ADD ptr idx) mem) && off == 0 && sym == nil -> (MOVHloadidx ptr idx mem) (MOVBUload [off] {sym} (ADD ptr idx) mem) && off == 0 && sym == nil -> (MOVBUloadidx ptr idx mem) (MOVBload [off] {sym} (ADD ptr idx) mem) && off == 0 && sym == nil -> (MOVBloadidx ptr idx mem) +(FMOVSload [off] {sym} (ADD ptr idx) mem) && off == 0 && sym == nil -> (FMOVSloadidx ptr idx mem) +(FMOVDload [off] {sym} (ADD ptr idx) mem) && off == 0 && sym == nil -> (FMOVDloadidx ptr idx mem) (MOVDloadidx ptr (MOVDconst [c]) mem) -> (MOVDload [c] ptr mem) (MOVDloadidx (MOVDconst [c]) ptr mem) -> (MOVDload [c] ptr mem) (MOVWUloadidx ptr (MOVDconst [c]) mem) -> (MOVWUload [c] ptr mem) @@ -663,6 +740,10 @@ (MOVBUloadidx (MOVDconst [c]) ptr mem) -> (MOVBUload [c] ptr mem) (MOVBloadidx ptr (MOVDconst [c]) mem) -> (MOVBload [c] ptr mem) (MOVBloadidx (MOVDconst [c]) ptr mem) -> (MOVBload [c] ptr mem) +(FMOVSloadidx ptr (MOVDconst [c]) mem) -> (FMOVSload [c] ptr mem) +(FMOVSloadidx (MOVDconst [c]) ptr mem) -> (FMOVSload [c] ptr mem) +(FMOVDloadidx ptr (MOVDconst [c]) mem) -> (FMOVDload [c] ptr mem) +(FMOVDloadidx (MOVDconst [c]) ptr mem) -> (FMOVDload [c] ptr mem) // shifted register indexed load (MOVDload [off] {sym} (ADDshiftLL [3] ptr idx) mem) && off == 0 && sym == nil -> (MOVDloadidx8 ptr idx mem) @@ -730,6 +811,8 @@ (MOVWstore [off] {sym} (ADD ptr idx) val mem) && off == 0 && sym == nil -> (MOVWstoreidx ptr idx val mem) (MOVHstore [off] {sym} (ADD ptr idx) val mem) && off == 0 && sym == nil -> (MOVHstoreidx ptr idx val mem) (MOVBstore [off] {sym} (ADD ptr idx) val mem) && off == 0 && sym == nil -> (MOVBstoreidx ptr idx val mem) +(FMOVDstore [off] {sym} (ADD ptr idx) val mem) && off == 0 && sym == nil -> (FMOVDstoreidx ptr idx val mem) +(FMOVSstore [off] {sym} (ADD ptr idx) val mem) && off == 0 && sym == nil -> (FMOVSstoreidx ptr idx val mem) (MOVDstoreidx ptr (MOVDconst [c]) val mem) -> (MOVDstore [c] ptr val mem) (MOVDstoreidx (MOVDconst [c]) idx val mem) -> (MOVDstore [c] idx val mem) (MOVWstoreidx ptr (MOVDconst [c]) val mem) -> (MOVWstore [c] ptr val mem) @@ -738,6 +821,10 @@ (MOVHstoreidx (MOVDconst [c]) idx val mem) -> (MOVHstore [c] idx val mem) (MOVBstoreidx ptr (MOVDconst [c]) val mem) -> (MOVBstore [c] ptr val mem) (MOVBstoreidx (MOVDconst [c]) idx val mem) -> (MOVBstore [c] idx val mem) +(FMOVDstoreidx ptr (MOVDconst [c]) val mem) -> (FMOVDstore [c] ptr val mem) +(FMOVDstoreidx (MOVDconst [c]) idx val mem) -> (FMOVDstore [c] idx val mem) +(FMOVSstoreidx ptr (MOVDconst [c]) val mem) -> (FMOVSstore [c] ptr val mem) +(FMOVSstoreidx (MOVDconst [c]) idx val mem) -> (FMOVSstore [c] idx val mem) // shifted register indexed store (MOVDstore [off] {sym} (ADDshiftLL [3] ptr idx) val mem) && off == 0 && sym == nil -> (MOVDstoreidx8 ptr idx val mem) @@ -1025,7 +1112,9 @@ (OR x (MOVDconst [c])) -> (ORconst [c] x) (XOR x (MOVDconst [c])) -> (XORconst [c] x) (TST x (MOVDconst [c])) -> (TSTconst [c] x) +(TSTW x (MOVDconst [c])) -> (TSTWconst [c] x) (CMN x (MOVDconst [c])) -> (CMNconst [c] x) +(CMNW x (MOVDconst [c])) -> (CMNWconst [c] x) (BIC x (MOVDconst [c])) -> (ANDconst [^c] x) (EON x (MOVDconst [c])) -> (XORconst [^c] x) (ORN x (MOVDconst [c])) -> (ORconst [^c] x) @@ -1045,6 +1134,17 @@ (MUL (NEG x) y) -> (MNEG x y) (MULW (NEG x) y) -> (MNEGW x y) +// madd/msub +(ADD a l:(MUL x y)) && l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MADD a x y) +(SUB a l:(MUL x y)) && l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MSUB a x y) +(ADD a l:(MNEG x y)) && l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MSUB a x y) +(SUB a l:(MNEG x y)) && l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MADD a x y) + +(ADD a l:(MULW x y)) && l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MADDW a x y) +(SUB a l:(MULW x y)) && l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MSUBW a x y) +(ADD a l:(MNEGW x y)) && l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MSUBW a x y) +(SUB a l:(MNEGW x y)) && l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) -> (MADDW a x y) + // mul by constant (MUL x (MOVDconst [-1])) -> (NEG x) (MUL _ (MOVDconst [0])) -> (MOVDconst [0]) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go index c87c18f3fb..eb0ad530a1 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go @@ -139,6 +139,7 @@ func init() { gp1flags = regInfo{inputs: []regMask{gpg}} gp1flags1 = regInfo{inputs: []regMask{gpg}, outputs: []regMask{gp}} gp21 = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{gp}} + gp31 = regInfo{inputs: []regMask{gpg, gpg, gpg}, outputs: []regMask{gp}} gp21nog = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}} gp2flags = regInfo{inputs: []regMask{gpg, gpg}} gp2flags1 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}} @@ -158,7 +159,9 @@ func init() { fp31 = regInfo{inputs: []regMask{fp, fp, fp}, outputs: []regMask{fp}} fp2flags = regInfo{inputs: []regMask{fp, fp}} fpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{fp}} + fp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{fp}} fpstore = regInfo{inputs: []regMask{gpspsbg, fp}} + fpstore2 = regInfo{inputs: []regMask{gpspsbg, gpg, fp}} readflags = regInfo{inputs: nil, outputs: []regMask{gp}} ) ops := []opData{ @@ -233,6 +236,10 @@ func init() { {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD"}, // +arg0 - (arg1 * arg2) {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS"}, // -arg0 + (arg1 * arg2) {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD"}, // -arg0 + (arg1 * arg2) + {name: "MADD", argLength: 3, reg: gp31, asm: "MADD"}, // +arg0 + (arg1 * arg2) + {name: "MADDW", argLength: 3, reg: gp31, asm: "MADDW"}, // +arg0 + (arg1 * arg2), 32-bit + {name: "MSUB", argLength: 3, reg: gp31, asm: "MSUB"}, // +arg0 - (arg1 * arg2) + {name: "MSUBW", argLength: 3, reg: gp31, asm: "MSUBW"}, // +arg0 - (arg1 * arg2), 32-bit // shifts {name: "SLL", argLength: 2, reg: gp21, asm: "LSL"}, // arg0 << arg1, shift amount is mod 64 @@ -251,13 +258,13 @@ func init() { {name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int64", typ: "Flags"}, // arg0 compare to auxInt {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1, 32 bit {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt, 32 bit - {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1 + {name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags", commutative: true}, // arg0 compare to -arg1 {name: "CMNconst", argLength: 1, reg: gp1flags, asm: "CMN", aux: "Int64", typ: "Flags"}, // arg0 compare to -auxInt - {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags"}, // arg0 compare to -arg1, 32 bit + {name: "CMNW", argLength: 2, reg: gp2flags, asm: "CMNW", typ: "Flags", commutative: true}, // arg0 compare to -arg1, 32 bit {name: "CMNWconst", argLength: 1, reg: gp1flags, asm: "CMNW", aux: "Int32", typ: "Flags"}, // arg0 compare to -auxInt, 32 bit - {name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags"}, // arg0 & arg1 compare to 0 + {name: "TST", argLength: 2, reg: gp2flags, asm: "TST", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0 {name: "TSTconst", argLength: 1, reg: gp1flags, asm: "TST", aux: "Int64", typ: "Flags"}, // arg0 & auxInt compare to 0 - {name: "TSTW", argLength: 2, reg: gp2flags, asm: "TSTW", typ: "Flags"}, // arg0 & arg1 compare to 0, 32 bit + {name: "TSTW", argLength: 2, reg: gp2flags, asm: "TSTW", typ: "Flags", commutative: true}, // arg0 & arg1 compare to 0, 32 bit {name: "TSTWconst", argLength: 1, reg: gp1flags, asm: "TSTW", aux: "Int32", typ: "Flags"}, // arg0 & auxInt compare to 0, 32 bit {name: "FCMPS", argLength: 2, reg: fp2flags, asm: "FCMPS", typ: "Flags"}, // arg0 compare to arg1, float32 {name: "FCMPD", argLength: 2, reg: fp2flags, asm: "FCMPD", typ: "Flags"}, // arg0 compare to arg1, float64 @@ -324,20 +331,22 @@ func init() { {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0 + auxInt + aux. arg1=mem. // register indexed load - {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD"}, // load 64-bit dword from arg0 + arg1, arg2 = mem. - {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW"}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU"}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH"}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU"}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB"}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU"}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit dword from arg0 + arg1, arg2 = mem. + {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8"}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8"}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "FMOVSloadidx", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32"}, // load 32-bit float from arg0 + arg1, arg2=mem. + {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64"}, // load 64-bit float from arg0 + arg1, arg2=mem. // shifted register indexed load - {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. - {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. - {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD"}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. + {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. + {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32"}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32"}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. + {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64"}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. @@ -348,10 +357,12 @@ func init() { {name: "FMOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "FMOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. // register indexed store - {name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVHstoreidx", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVWstoreidx", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1, arg3 = mem. - {name: "MOVDstoreidx", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVBstoreidx", argLength: 4, reg: gpstore2, asm: "MOVB", typ: "Mem"}, // store 1 byte of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVHstoreidx", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVWstoreidx", argLength: 4, reg: gpstore2, asm: "MOVW", typ: "Mem"}, // store 4 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "MOVDstoreidx", argLength: 4, reg: gpstore2, asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg2 to arg0 + arg1, arg3 = mem. + {name: "FMOVSstoreidx", argLength: 4, reg: fpstore2, asm: "FMOVS", typ: "Mem"}, // store 32-bit float of arg2 to arg0 + arg1, arg3=mem. + {name: "FMOVDstoreidx", argLength: 4, reg: fpstore2, asm: "FMOVD", typ: "Mem"}, // store 64-bit float of arg2 to arg0 + arg1, arg3=mem. // shifted register indexed store {name: "MOVHstoreidx2", argLength: 4, reg: gpstore2, asm: "MOVH", typ: "Mem"}, // store 2 bytes of arg2 to arg0 + arg1*2, arg3 = mem. diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go index 2df9003247..4e2b0c5a5d 100644 --- a/src/cmd/compile/internal/ssa/gen/ARMOps.go +++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go @@ -373,21 +373,21 @@ func init() { {name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem", faultOnNilArg0: true, symEffect: "Write"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. - {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW"}, // load from arg0 + arg1. arg2=mem - {name: "MOVWloadshiftLL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1<>auxInt, unsigned shift. arg2=mem - {name: "MOVWloadshiftRA", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1>>auxInt, signed shift. arg2=mem - {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU"}, // load from arg0 + arg1. arg2=mem - {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB"}, // load from arg0 + arg1. arg2=mem - {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU"}, // load from arg0 + arg1. arg2=mem - {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH"}, // load from arg0 + arg1. arg2=mem + {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "UInt32"}, // load from arg0 + arg1. arg2=mem + {name: "MOVWloadshiftLL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32", typ: "UInt32"}, // load from arg0 + arg1<>auxInt, unsigned shift. arg2=mem + {name: "MOVWloadshiftRA", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32", typ: "UInt32"}, // load from arg0 + arg1>>auxInt, signed shift. arg2=mem + {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8"}, // load from arg0 + arg1. arg2=mem + {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8"}, // load from arg0 + arg1. arg2=mem + {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16"}, // load from arg0 + arg1. arg2=mem + {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16"}, // load from arg0 + arg1. arg2=mem - {name: "MOVWstoreidx", argLength: 4, reg: gp2store, asm: "MOVW"}, // store arg2 to arg0 + arg1. arg3=mem - {name: "MOVWstoreshiftLL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1<>auxInt, unsigned shift. arg3=mem - {name: "MOVWstoreshiftRA", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1>>auxInt, signed shift. arg3=mem - {name: "MOVBstoreidx", argLength: 4, reg: gp2store, asm: "MOVB"}, // store arg2 to arg0 + arg1. arg3=mem - {name: "MOVHstoreidx", argLength: 4, reg: gp2store, asm: "MOVH"}, // store arg2 to arg0 + arg1. arg3=mem + {name: "MOVWstoreidx", argLength: 4, reg: gp2store, asm: "MOVW", typ: "Mem"}, // store arg2 to arg0 + arg1. arg3=mem + {name: "MOVWstoreshiftLL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32", typ: "Mem"}, // store arg2 to arg0 + arg1<>auxInt, unsigned shift. arg3=mem + {name: "MOVWstoreshiftRA", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32", typ: "Mem"}, // store arg2 to arg0 + arg1>>auxInt, signed shift. arg3=mem + {name: "MOVBstoreidx", argLength: 4, reg: gp2store, asm: "MOVB", typ: "Mem"}, // store arg2 to arg0 + arg1. arg3=mem + {name: "MOVHstoreidx", argLength: 4, reg: gp2store, asm: "MOVH", typ: "Mem"}, // store arg2 to arg0 + arg1. arg3=mem {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVBS"}, // move from arg0, sign-extended from byte {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte diff --git a/src/cmd/compile/internal/ssa/gen/MIPS.rules b/src/cmd/compile/internal/ssa/gen/MIPS.rules index 50fdf29b04..098e19c8a8 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS.rules @@ -219,6 +219,7 @@ (OffPtr [off] ptr) -> (ADDconst [off] ptr) (Addr {sym} base) -> (MOVWaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVWaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/MIPS64.rules b/src/cmd/compile/internal/ssa/gen/MIPS64.rules index f5e78ec294..70f4f0d616 100644 --- a/src/cmd/compile/internal/ssa/gen/MIPS64.rules +++ b/src/cmd/compile/internal/ssa/gen/MIPS64.rules @@ -229,6 +229,7 @@ (OffPtr [off] ptr) -> (ADDVconst [off] ptr) (Addr {sym} base) -> (MOVVaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVVaddr {sym} base) // loads (Load ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index a668b61093..6ef8c7b5b9 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -273,6 +273,7 @@ // (MaskIfNotCarry CarrySet) -> -1 (Addr {sym} base) -> (MOVDaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVDaddr {sym} base) (OffPtr [off] ptr) -> (ADD (MOVDconst [off]) ptr) // TODO: optimize these cases? diff --git a/src/cmd/compile/internal/ssa/gen/S390X.rules b/src/cmd/compile/internal/ssa/gen/S390X.rules index 61ac734224..47766fa77d 100644 --- a/src/cmd/compile/internal/ssa/gen/S390X.rules +++ b/src/cmd/compile/internal/ssa/gen/S390X.rules @@ -88,6 +88,34 @@ (BitLen64 x) -> (SUB (MOVDconst [64]) (FLOGR x)) +// POPCNT treats the input register as a vector of 8 bytes, producing +// a population count for each individual byte. For inputs larger than +// a single byte we therefore need to sum the individual bytes produced +// by the POPCNT instruction. For example, the following instruction +// sequence could be used to calculate the population count of a 4-byte +// value: +// +// MOVD $0x12345678, R1 // R1=0x12345678 <-- input +// POPCNT R1, R2 // R2=0x02030404 +// SRW $16, R2, R3 // R3=0x00000203 +// ADDW R2, R3, R4 // R4=0x02030607 +// SRW $8, R4, R5 // R5=0x00020306 +// ADDW R4, R5, R6 // R6=0x0205090d +// MOVBZ R6, R7 // R7=0x0000000d <-- result is 13 +// +(PopCount8 x) -> (POPCNT (MOVBZreg x)) +(PopCount16 x) -> (MOVBZreg (SumBytes2 (POPCNT x))) +(PopCount32 x) -> (MOVBZreg (SumBytes4 (POPCNT x))) +(PopCount64 x) -> (MOVBZreg (SumBytes8 (POPCNT x))) + +// SumBytes{2,4,8} pseudo operations sum the values of the rightmost +// 2, 4 or 8 bytes respectively. The result is a single byte however +// other bytes might contain junk so a zero extension is required if +// the desired output type is larger than 1 byte. +(SumBytes2 x) -> (ADDW (SRWconst x [8]) x) +(SumBytes4 x) -> (SumBytes2 (ADDW (SRWconst x [16]) x)) +(SumBytes8 x) -> (SumBytes4 (ADDW (SRDconst x [32]) x)) + (Bswap64 x) -> (MOVDBR x) (Bswap32 x) -> (MOVWBR x) @@ -205,6 +233,10 @@ (Rsh(16|8)x16 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE y (MOVDconst [63]) (CMPWUconst (MOVHZreg y) [64]))) (Rsh(16|8)x8 x y) -> (SRAW (MOV(H|B)reg x) (MOVDGE y (MOVDconst [63]) (CMPWUconst (MOVBZreg y) [64]))) +// Lowering rotates +(RotateLeft32 x y) -> (RLL x y) +(RotateLeft64 x y) -> (RLLG x y) + // Lowering comparisons (Less64 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMP x y)) (Less32 x y) -> (MOVDLT (MOVDconst [0]) (MOVDconst [1]) (CMPW x y)) @@ -367,6 +399,7 @@ (GetCallerSP) -> (LoweredGetCallerSP) (GetCallerPC) -> (LoweredGetCallerPC) (Addr {sym} base) -> (MOVDaddr {sym} base) +(LocalAddr {sym} base _) -> (MOVDaddr {sym} base) (ITab (Load ptr mem)) -> (MOVDload ptr mem) // block rewrites @@ -503,7 +536,10 @@ (SRW x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRW x y) (SRAW x (MOV(D|W|H|B|WZ|HZ|BZ)reg y)) -> (SRAW x y) -// Rotate generation +// Constant rotate generation +(RLL x (MOVDconst [c])) -> (RLLconst x [c&31]) +(RLLG x (MOVDconst [c])) -> (RLLGconst x [c&63]) + (ADD (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) ( OR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) (XOR (SLDconst x [c]) (SRDconst x [d])) && d == 64-c -> (RLLGconst [c] x) diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go index ae01375473..19cb4be41c 100644 --- a/src/cmd/compile/internal/ssa/gen/S390XOps.go +++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go @@ -321,6 +321,8 @@ func init() { {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int8", clobberFlags: true}, // signed arg0 >> auxint, shift amount 0-63 {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int8", clobberFlags: true}, // signed int32(arg0) >> auxint, shift amount 0-31 + {name: "RLLG", argLength: 2, reg: sh21, asm: "RLLG"}, // arg0 rotate left arg1, rotate amount 0-63 + {name: "RLL", argLength: 2, reg: sh21, asm: "RLL"}, // arg0 rotate left arg1, rotate amount 0-31 {name: "RLLGconst", argLength: 1, reg: gp11, asm: "RLLG", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-63 {name: "RLLconst", argLength: 1, reg: gp11, asm: "RLL", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-31 @@ -530,6 +532,25 @@ func init() { clobberFlags: true, }, + // population count + // + // Counts the number of ones in each byte of arg0 + // and places the result into the corresponding byte + // of the result. + { + name: "POPCNT", + argLength: 1, + reg: gp11, + asm: "POPCNT", + typ: "UInt64", + clobberFlags: true, + }, + + // pseudo operations to sum the output of the POPCNT instruction + {name: "SumBytes2", argLength: 1, typ: "UInt8"}, // sum the rightmost 2 bytes in arg0 ignoring overflow + {name: "SumBytes4", argLength: 1, typ: "UInt8"}, // sum the rightmost 4 bytes in arg0 ignoring overflow + {name: "SumBytes8", argLength: 1, typ: "UInt8"}, // sum all the bytes in arg0 ignoring overflow + // store multiple { name: "STMG2", diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules index 272b260cb7..dc1581362c 100644 --- a/src/cmd/compile/internal/ssa/gen/Wasm.rules +++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules @@ -352,6 +352,7 @@ (GetCallerPC) -> (LoweredGetCallerPC) (GetCallerSP) -> (LoweredGetCallerSP) (Addr {sym} base) -> (LoweredAddr {sym} base) +(LocalAddr {sym} base _) -> (LoweredAddr {sym} base) // Write barrier. (WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 7931aa7f06..aa944b5379 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -371,6 +371,12 @@ (Rsh16Ux64 (Rsh16Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh16Ux64 x (Const64 [c+d])) (Rsh8Ux64 (Rsh8Ux64 x (Const64 [c])) (Const64 [d])) && !uaddOvf(c,d) -> (Rsh8Ux64 x (Const64 [c+d])) +// Remove signed right shift before an unsigned right shift that extracts the sign bit. +(Rsh8Ux64 (Rsh8x64 x _) (Const64 [7] )) -> (Rsh8Ux64 x (Const64 [7] )) +(Rsh16Ux64 (Rsh16x64 x _) (Const64 [15])) -> (Rsh16Ux64 x (Const64 [15])) +(Rsh32Ux64 (Rsh32x64 x _) (Const64 [31])) -> (Rsh32Ux64 x (Const64 [31])) +(Rsh64Ux64 (Rsh64x64 x _) (Const64 [63])) -> (Rsh64Ux64 x (Const64 [63])) + // ((x >> c1) << c2) >> c3 (Rsh(64|32|16|8)Ux64 (Lsh(64|32|16|8)x64 (Rsh(64|32|16|8)Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) && uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) @@ -566,9 +572,9 @@ // Pass constants through math.Float{32,64}bits and math.Float{32,64}frombits (Load p1 (Store {t2} p2 (Const64 [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 8 && is64BitFloat(t1) -> (Const64F [x]) -(Load p1 (Store {t2} p2 (Const32 [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitFloat(t1) -> (Const32F [f2i(float64(math.Float32frombits(uint32(x))))]) +(Load p1 (Store {t2} p2 (Const32 [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitFloat(t1) -> (Const32F [f2i(extend32Fto64F(math.Float32frombits(uint32(x))))]) (Load p1 (Store {t2} p2 (Const64F [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 8 && is64BitInt(t1) -> (Const64 [x]) -(Load p1 (Store {t2} p2 (Const32F [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitInt(t1) -> (Const32 [int64(int32(math.Float32bits(float32(i2f(x)))))]) +(Load p1 (Store {t2} p2 (Const32F [x]) _)) && isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitInt(t1) -> (Const32 [int64(int32(math.Float32bits(truncate64Fto32F(i2f(x)))))]) // Float Loads up to Zeros so they can be constant folded. (Load op:(OffPtr [o1] p1) @@ -1370,6 +1376,8 @@ (NeqPtr x x) -> (ConstBool [0]) (EqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a == b)]) (NeqPtr (Addr {a} _) (Addr {b} _)) -> (ConstBool [b2i(a != b)]) +(EqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) -> (ConstBool [b2i(a == b)]) +(NeqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) -> (ConstBool [b2i(a != b)]) (EqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == 0)]) (NeqPtr (OffPtr [o1] p1) p2) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 != 0)]) (EqPtr (OffPtr [o1] p1) (OffPtr [o2] p2)) && isSamePtr(p1, p2) -> (ConstBool [b2i(o1 == o2)]) @@ -1377,6 +1385,11 @@ (EqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c == d)]) (NeqPtr (Const(32|64) [c]) (Const(32|64) [d])) -> (ConstBool [b2i(c != d)]) +(EqPtr (LocalAddr _ _) (Addr _)) -> (ConstBool [0]) +(NeqPtr (LocalAddr _ _) (Addr _)) -> (ConstBool [1]) +(EqPtr (Addr _) (LocalAddr _ _)) -> (ConstBool [0]) +(NeqPtr (Addr _) (LocalAddr _ _)) -> (ConstBool [1]) + // Simplify address comparisons. (EqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (Not (IsNonNil o1)) (NeqPtr (AddPtr p1 o1) p2) && isSamePtr(p1, p2) -> (IsNonNil o1) @@ -1389,6 +1402,7 @@ (IsNonNil (ConstNil)) -> (ConstBool [0]) (IsNonNil (Const(32|64) [c])) -> (ConstBool [b2i(c != 0)]) (IsNonNil (Addr _)) -> (ConstBool [1]) +(IsNonNil (LocalAddr _ _)) -> (ConstBool [1]) // Inline small or disjoint runtime.memmove calls with constant length. (StaticCall {sym} s1:(Store _ (Const(64|32) [sz]) s2:(Store _ src s3:(Store {t} _ dst mem)))) @@ -1783,3 +1797,5 @@ (Store {t4} (OffPtr [o4] dst) d3 (Store {t5} (OffPtr [o5] dst) d4 (Zero {t1} [n] dst mem))))) + +(StaticCall {sym} x) && needRaceCleanup(sym,v) -> x diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 07d93ac073..7292012d26 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -264,10 +264,14 @@ var genericOps = []opData{ {name: "BitRev32", argLength: 1}, // Reverse the bits in arg[0] {name: "BitRev64", argLength: 1}, // Reverse the bits in arg[0] - {name: "PopCount8", argLength: 1}, // Count bits in arg[0] - {name: "PopCount16", argLength: 1}, // Count bits in arg[0] - {name: "PopCount32", argLength: 1}, // Count bits in arg[0] - {name: "PopCount64", argLength: 1}, // Count bits in arg[0] + {name: "PopCount8", argLength: 1}, // Count bits in arg[0] + {name: "PopCount16", argLength: 1}, // Count bits in arg[0] + {name: "PopCount32", argLength: 1}, // Count bits in arg[0] + {name: "PopCount64", argLength: 1}, // Count bits in arg[0] + {name: "RotateLeft8", argLength: 2}, // Rotate bits in arg[0] left by arg[1] + {name: "RotateLeft16", argLength: 2}, // Rotate bits in arg[0] left by arg[1] + {name: "RotateLeft32", argLength: 2}, // Rotate bits in arg[0] left by arg[1] + {name: "RotateLeft64", argLength: 2}, // Rotate bits in arg[0] left by arg[1] // Square root, float64 only. // Special cases: @@ -331,7 +335,8 @@ var genericOps = []opData{ // the Aux field will be a *obj.LSym. // If the variable is a local, the base pointer will be SP and // the Aux field will be a *gc.Node. - {name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable. + {name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SB. Aux identifies the variable. + {name: "LocalAddr", argLength: 2, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP. Arg1=mem. Aux identifies the variable. {name: "SP", zeroWidth: true}, // stack pointer {name: "SB", typ: "Uintptr", zeroWidth: true}, // static base pointer (a.k.a. globals pointer) diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 15d64d63e9..c51ea02262 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -11,12 +11,15 @@ import ( "html" "io" "os" + "path/filepath" + "strconv" "strings" ) type HTMLWriter struct { Logger - w io.WriteCloser + w io.WriteCloser + path string } func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter { @@ -24,7 +27,11 @@ func NewHTMLWriter(path string, logger Logger, funcname string) *HTMLWriter { if err != nil { logger.Fatalf(src.NoXPos, "%v", err) } - html := HTMLWriter{w: out, Logger: logger} + pwd, err := os.Getwd() + if err != nil { + logger.Fatalf(src.NoXPos, "%v", err) + } + html := HTMLWriter{w: out, Logger: logger, path: filepath.Join(pwd, path)} html.start(funcname) return &html } @@ -54,7 +61,7 @@ body { } .stats { - font-size: 60%; + font-size: 60%; } table { @@ -97,6 +104,34 @@ td.collapsed div { text-align: right; } +code, pre, .lines, .ast { + font-family: Menlo, monospace; + font-size: 12px; +} + +.allow-x-scroll { + overflow-x: scroll; +} + +.lines { + float: left; + overflow: hidden; + text-align: right; +} + +.lines div { + padding-right: 10px; + color: gray; +} + +div.line-number { + font-size: 12px; +} + +.ast { + white-space: nowrap; +} + td.ssa-prog { width: 600px; word-wrap: break-word; @@ -158,10 +193,14 @@ dd.ssa-prog { } .line-number { - font-style: italic; font-size: 11px; } +.no-line-number { + font-size: 11px; + color: gray; +} + .highlight-aquamarine { background-color: aquamarine; } .highlight-coral { background-color: coral; } .highlight-lightpink { background-color: lightpink; } @@ -235,7 +274,7 @@ for (var i = 0; i < outlines.length; i++) { window.onload = function() { var ssaElemClicked = function(elem, event, selections, selected) { - event.stopPropagation() + event.stopPropagation(); // TODO: pushState with updated state and read it on page load, // so that state can survive across reloads @@ -288,11 +327,11 @@ window.onload = function() { var ssaValueClicked = function(event) { ssaElemClicked(this, event, highlights, highlighted); - } + }; var ssaBlockClicked = function(event) { ssaElemClicked(this, event, outlines, outlined); - } + }; var ssavalues = document.getElementsByClassName("ssa-value"); for (var i = 0; i < ssavalues.length; i++) { @@ -311,7 +350,14 @@ window.onload = function() { for (var i = 0; i < ssablocks.length; i++) { ssablocks[i].addEventListener('click', ssaBlockClicked); } - var expandedDefault = [ + + var lines = document.getElementsByClassName("line-number"); + for (var i = 0; i < lines.length; i++) { + lines[i].addEventListener('click', ssaValueClicked); + } + + // Contains phase names which are expanded by default. Other columns are collapsed. + var expandedDefault = [ "start", "deadcode", "opt", @@ -319,56 +365,53 @@ window.onload = function() { "late deadcode", "regalloc", "genssa", - ] - function isExpDefault(id) { - for (var i = 0; i < expandedDefault.length; i++) { - if (id.startsWith(expandedDefault[i])) { - return true; - } - } - return false; - } + ]; + function toggler(phase) { return function() { toggle_cell(phase+'-col'); toggle_cell(phase+'-exp'); }; } + function toggle_cell(id) { - var e = document.getElementById(id); - if(e.style.display == 'table-cell') - e.style.display = 'none'; - else - e.style.display = 'table-cell'; + var e = document.getElementById(id); + if (e.style.display == 'table-cell') { + e.style.display = 'none'; + } else { + e.style.display = 'table-cell'; + } } + // Go through all columns and collapse needed phases. var td = document.getElementsByTagName("td"); for (var i = 0; i < td.length; i++) { var id = td[i].id; - var def = isExpDefault(id); var phase = id.substr(0, id.length-4); + var show = expandedDefault.indexOf(phase) !== -1 if (id.endsWith("-exp")) { var h2 = td[i].getElementsByTagName("h2"); if (h2 && h2[0]) { h2[0].addEventListener('click', toggler(phase)); } } else { - td[i].addEventListener('click', toggler(phase)); + td[i].addEventListener('click', toggler(phase)); } - if (id.endsWith("-col") && def || id.endsWith("-exp") && !def) { - td[i].style.display = 'none'; - continue + if (id.endsWith("-col") && show || id.endsWith("-exp") && !show) { + td[i].style.display = 'none'; + continue; } td[i].style.display = 'table-cell'; } }; function toggle_visibility(id) { - var e = document.getElementById(id); - if(e.style.display == 'block') - e.style.display = 'none'; - else - e.style.display = 'block'; + var e = document.getElementById(id); + if (e.style.display == 'block') { + e.style.display = 'none'; + } else { + e.style.display = 'block'; + } } @@ -411,9 +454,11 @@ func (w *HTMLWriter) Close() { io.WriteString(w.w, "") io.WriteString(w.w, "") w.w.Close() + fmt.Printf("dumped SSA to %v\n", w.path) } // WriteFunc writes f in a column headed by title. +// phase is used for collapsing columns and should be unique across the table. func (w *HTMLWriter) WriteFunc(phase, title string, f *Func) { if w == nil { return // avoid generating HTML just to discard it @@ -422,6 +467,114 @@ func (w *HTMLWriter) WriteFunc(phase, title string, f *Func) { // TODO: Add visual representation of f's CFG. } +// FuncLines contains source code for a function to be displayed +// in sources column. +type FuncLines struct { + Filename string + StartLineno uint + Lines []string +} + +// ByTopo sorts topologically: target function is on top, +// followed by inlined functions sorted by filename and line numbers. +type ByTopo []*FuncLines + +func (x ByTopo) Len() int { return len(x) } +func (x ByTopo) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x ByTopo) Less(i, j int) bool { + a := x[i] + b := x[j] + if a.Filename == a.Filename { + return a.StartLineno < b.StartLineno + } + return a.Filename < b.Filename +} + +// WriteSources writes lines as source code in a column headed by title. +// phase is used for collapsing columns and should be unique across the table. +func (w *HTMLWriter) WriteSources(phase string, all []*FuncLines) { + if w == nil { + return // avoid generating HTML just to discard it + } + var buf bytes.Buffer + fmt.Fprint(&buf, "
    ") + filename := "" + for _, fl := range all { + fmt.Fprint(&buf, "
     
    ") + if filename != fl.Filename { + fmt.Fprint(&buf, "
     
    ") + filename = fl.Filename + } + for i := range fl.Lines { + ln := int(fl.StartLineno) + i + fmt.Fprintf(&buf, "
    %v
    ", ln, ln) + } + } + fmt.Fprint(&buf, "
    ")
    +	filename = ""
    +	for _, fl := range all {
    +		fmt.Fprint(&buf, "
     
    ") + if filename != fl.Filename { + fmt.Fprintf(&buf, "
    %v
    ", fl.Filename) + filename = fl.Filename + } + for i, line := range fl.Lines { + ln := int(fl.StartLineno) + i + var escaped string + if strings.TrimSpace(line) == "" { + escaped = " " + } else { + escaped = html.EscapeString(line) + } + fmt.Fprintf(&buf, "
    %v
    ", ln, escaped) + } + } + fmt.Fprint(&buf, "
    ") + w.WriteColumn(phase, phase, "allow-x-scroll", buf.String()) +} + +func (w *HTMLWriter) WriteAST(phase string, buf *bytes.Buffer) { + if w == nil { + return // avoid generating HTML just to discard it + } + lines := strings.Split(buf.String(), "\n") + var out bytes.Buffer + + fmt.Fprint(&out, "
    ") + for _, l := range lines { + l = strings.TrimSpace(l) + var escaped string + var lineNo string + if l == "" { + escaped = " " + } else { + if strings.HasPrefix(l, "buildssa") { + escaped = fmt.Sprintf("%v", l) + } else { + // Parse the line number from the format l(123). + idx := strings.Index(l, " l(") + if idx != -1 { + subl := l[idx+3:] + idxEnd := strings.Index(subl, ")") + if idxEnd != -1 { + if _, err := strconv.Atoi(subl[:idxEnd]); err == nil { + lineNo = subl[:idxEnd] + } + } + } + escaped = html.EscapeString(l) + } + } + if lineNo != "" { + fmt.Fprintf(&out, "
    %v
    ", lineNo, escaped) + } else { + fmt.Fprintf(&out, "
    %v
    ", escaped) + } + } + fmt.Fprint(&out, "
    ") + w.WriteColumn(phase, phase, "allow-x-scroll", out.String()) +} + // WriteColumn writes raw HTML in a column headed by title. // It is intended for pre- and post-compilation log output. func (w *HTMLWriter) WriteColumn(phase, title, class, html string) { @@ -470,9 +623,9 @@ func (v *Value) LongHTML() string { // maybe we could replace some of that with formatting. s := fmt.Sprintf("", v.String()) - linenumber := "(?)" + linenumber := "(?)" if v.Pos.IsKnown() { - linenumber = fmt.Sprintf("(%s)", v.Pos.LineNumberHTML()) + linenumber = fmt.Sprintf("(%s)", v.Pos.LineNumber(), v.Pos.LineNumberHTML()) } s += fmt.Sprintf("%s %s = %s", v.HTML(), linenumber, v.Op.String()) @@ -536,7 +689,7 @@ func (b *Block) LongHTML() string { if b.Pos.IsKnown() { // TODO does not begin to deal with the full complexity of line numbers. // Maybe we want a string/slice instead, of outer-inner when inlining. - s += fmt.Sprintf(" (line %s)", b.Pos.LineNumberHTML()) + s += fmt.Sprintf(" (%s)", b.Pos.LineNumber(), b.Pos.LineNumberHTML()) } return s } diff --git a/src/cmd/compile/internal/ssa/loop_test.go b/src/cmd/compile/internal/ssa/loop_test.go index 6810f5f797..8f72930bce 100644 --- a/src/cmd/compile/internal/ssa/loop_test.go +++ b/src/cmd/compile/internal/ssa/loop_test.go @@ -50,7 +50,7 @@ func TestLoopConditionS390X(t *testing.T) { Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), Valu("SP", OpSP, c.config.Types.Uintptr, 0, nil), - Valu("ret", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP"), + Valu("ret", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "SP", "mem"), Valu("N", OpArg, c.config.Types.Int64, 0, c.Frontend().Auto(src.NoXPos, c.config.Types.Int64)), Valu("starti", OpConst64, c.config.Types.Int64, 0, nil), Valu("startsum", OpConst64, c.config.Types.Int64, 0, nil), diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go index 2ab05711ad..8ab1a0c695 100644 --- a/src/cmd/compile/internal/ssa/loopbce.go +++ b/src/cmd/compile/internal/ssa/loopbce.go @@ -15,15 +15,15 @@ const ( type indVar struct { ind *Value // induction variable - inc *Value // increment, a constant - nxt *Value // ind+inc variable min *Value // minimum value, inclusive/exclusive depends on flags max *Value // maximum value, inclusive/exclusive depends on flags entry *Block // entry block in the loop. flags indVarFlags - // Invariants: for all blocks dominated by entry: - // min <= ind < max - // min <= nxt <= max + // Invariant: for all blocks strictly dominated by entry: + // min <= ind < max [if flags == 0] + // min < ind < max [if flags == indVarMinExc] + // min <= ind <= max [if flags == indVarMaxInc] + // min < ind <= max [if flags == indVarMinExc|indVarMaxInc] } // findIndVar finds induction variables in a function. @@ -49,7 +49,6 @@ func findIndVar(f *Func) []indVar { var iv []indVar sdom := f.sdom() -nextb: for _, b := range f.Blocks { if b.Kind != BlockIf || len(b.Preds) != 2 { continue @@ -57,7 +56,6 @@ nextb: var flags indVarFlags var ind, max *Value // induction, and maximum - entry := -1 // which successor of b enters the loop // Check thet the control if it either ind />= ind. // TODO: Handle 32-bit comparisons. @@ -66,21 +64,21 @@ nextb: flags |= indVarMaxInc fallthrough case OpLess64: - entry = 0 ind, max = b.Control.Args[0], b.Control.Args[1] case OpGeq64: flags |= indVarMaxInc fallthrough case OpGreater64: - entry = 0 ind, max = b.Control.Args[1], b.Control.Args[0] default: - continue nextb + continue } // See if the arguments are reversed (i < len() <=> len() > i) + less := true if max.Op == OpPhi { ind, max = max, ind + less = false } // Check that the induction variable is a phi that depends on itself. @@ -108,22 +106,35 @@ nextb: panic("unreachable") // one of the cases must be true from the above. } - // Expect the increment to be a constant. + // Expect the increment to be a nonzero constant. if inc.Op != OpConst64 { continue } + step := inc.AuxInt + if step == 0 { + continue + } + + // Increment sign must match comparison direction. + // When incrementing, the termination comparison must be ind />= max. + // See issue 26116. + if step > 0 && !less { + continue + } + if step < 0 && less { + continue + } // If the increment is negative, swap min/max and their flags - if inc.AuxInt <= 0 { + if step < 0 { min, max = max, min oldf := flags - flags = 0 + flags = indVarMaxInc if oldf&indVarMaxInc == 0 { flags |= indVarMinExc } - if oldf&indVarMinExc == 0 { - flags |= indVarMaxInc - } + step = -step } // Up to now we extracted the induction variable (ind), @@ -140,26 +151,26 @@ nextb: // as an induction variable. // First condition: loop entry has a single predecessor, which - // is the header block. This implies that b.Succs[entry] is + // is the header block. This implies that b.Succs[0] is // reached iff ind < max. - if len(b.Succs[entry].b.Preds) != 1 { - // b.Succs[1-entry] must exit the loop. + if len(b.Succs[0].b.Preds) != 1 { + // b.Succs[1] must exit the loop. continue } - // Second condition: b.Succs[entry] dominates nxt so that + // Second condition: b.Succs[0] dominates nxt so that // nxt is computed when inc < max, meaning nxt <= max. - if !sdom.isAncestorEq(b.Succs[entry].b, nxt.Block) { + if !sdom.isAncestorEq(b.Succs[0].b, nxt.Block) { // inc+ind can only be reached through the branch that enters the loop. continue } // We can only guarantee that the loops runs within limits of induction variable // if the increment is ±1 or when the limits are constants. - if inc.AuxInt != 1 && inc.AuxInt != -1 { + if step != 1 { ok := false - if min.Op == OpConst64 && max.Op == OpConst64 && inc.AuxInt != 0 { - if max.AuxInt > min.AuxInt && max.AuxInt%inc.AuxInt == min.AuxInt%inc.AuxInt { // handle overflow + if min.Op == OpConst64 && max.Op == OpConst64 { + if max.AuxInt > min.AuxInt && max.AuxInt%step == min.AuxInt%step { // handle overflow ok = true } } @@ -169,16 +180,14 @@ nextb: } if f.pass.debug >= 1 { - printIndVar(b, ind, min, max, inc.AuxInt, flags) + printIndVar(b, ind, min, max, step, flags) } iv = append(iv, indVar{ ind: ind, - inc: inc, - nxt: nxt, min: min, max: max, - entry: b.Succs[entry].b, + entry: b.Succs[0].b, flags: flags, }) b.Logf("found induction variable %v (inc = %v, min = %v, max = %v)\n", ind, inc, min, max) diff --git a/src/cmd/compile/internal/ssa/nilcheck.go b/src/cmd/compile/internal/ssa/nilcheck.go index 2e4ad064a9..f2e17c606b 100644 --- a/src/cmd/compile/internal/ssa/nilcheck.go +++ b/src/cmd/compile/internal/ssa/nilcheck.go @@ -47,7 +47,7 @@ func nilcheckelim(f *Func) { // a value resulting from taking the address of a // value, or a value constructed from an offset of a // non-nil ptr (OpAddPtr) implies it is non-nil - if v.Op == OpAddr || v.Op == OpAddPtr { + if v.Op == OpAddr || v.Op == OpLocalAddr || v.Op == OpAddPtr || v.Op == OpOffPtr { nonNilValues[v.ID] = true } } diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index 3ca033797d..815c4a5047 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -212,7 +212,7 @@ func TestNilcheckPhi(t *testing.T) { Valu("mem", OpInitMem, types.TypeMem, 0, nil), Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil), Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil), - Valu("baddr", OpAddr, c.config.Types.Bool, 0, "b", "sp"), + Valu("baddr", OpLocalAddr, c.config.Types.Bool, 0, "b", "sp", "mem"), Valu("bool1", OpLoad, c.config.Types.Bool, 0, nil, "baddr", "mem"), If("bool1", "b1", "b2")), Bloc("b1", diff --git a/src/cmd/compile/internal/ssa/numberlines.go b/src/cmd/compile/internal/ssa/numberlines.go index 997b05c3a2..662f58e4b5 100644 --- a/src/cmd/compile/internal/ssa/numberlines.go +++ b/src/cmd/compile/internal/ssa/numberlines.go @@ -14,7 +14,7 @@ func isPoorStatementOp(op Op) bool { switch op { // Note that Nilcheck often vanishes, but when it doesn't, you'd love to start the statement there // so that a debugger-user sees the stop before the panic, and can examine the value. - case OpAddr, OpOffPtr, OpStructSelect, OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F: + case OpAddr, OpLocalAddr, OpOffPtr, OpStructSelect, OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F: return true } return false diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 4924947d8b..5bf7021432 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -262,6 +262,8 @@ const ( Op386SUBSDload Op386MULSSload Op386MULSDload + Op386DIVSSload + Op386DIVSDload Op386ADDL Op386ADDLconst Op386ADDLcarry @@ -300,6 +302,12 @@ const ( Op386CMPLconst Op386CMPWconst Op386CMPBconst + Op386CMPLload + Op386CMPWload + Op386CMPBload + Op386CMPLconstload + Op386CMPWconstload + Op386CMPBconstload Op386UCOMISS Op386UCOMISD Op386TESTL @@ -327,6 +335,7 @@ const ( Op386ROLBconst Op386ADDLload Op386SUBLload + Op386MULLload Op386ANDLload Op386ORLload Op386XORLload @@ -385,6 +394,10 @@ const ( Op386ANDLmodify Op386ORLmodify Op386XORLmodify + Op386ADDLconstmodify + Op386ANDLconstmodify + Op386ORLconstmodify + Op386XORLconstmodify Op386MOVBloadidx1 Op386MOVWloadidx1 Op386MOVWloadidx2 @@ -456,6 +469,8 @@ const ( OpAMD64SUBSDload OpAMD64MULSSload OpAMD64MULSDload + OpAMD64DIVSSload + OpAMD64DIVSDload OpAMD64ADDQ OpAMD64ADDL OpAMD64ADDQconst @@ -487,14 +502,20 @@ const ( OpAMD64ANDL OpAMD64ANDQconst OpAMD64ANDLconst + OpAMD64ANDQconstmodify + OpAMD64ANDLconstmodify OpAMD64ORQ OpAMD64ORL OpAMD64ORQconst OpAMD64ORLconst + OpAMD64ORQconstmodify + OpAMD64ORLconstmodify OpAMD64XORQ OpAMD64XORL OpAMD64XORQconst OpAMD64XORLconst + OpAMD64XORQconstmodify + OpAMD64XORLconstmodify OpAMD64CMPQ OpAMD64CMPL OpAMD64CMPW @@ -579,6 +600,16 @@ const ( OpAMD64ORLload OpAMD64XORQload OpAMD64XORLload + OpAMD64ADDQmodify + OpAMD64SUBQmodify + OpAMD64ANDQmodify + OpAMD64ORQmodify + OpAMD64XORQmodify + OpAMD64ADDLmodify + OpAMD64SUBLmodify + OpAMD64ANDLmodify + OpAMD64ORLmodify + OpAMD64XORLmodify OpAMD64NEGQ OpAMD64NEGL OpAMD64NOTQ @@ -1098,6 +1129,10 @@ const ( OpARM64FMSUBD OpARM64FNMSUBS OpARM64FNMSUBD + OpARM64MADD + OpARM64MADDW + OpARM64MSUB + OpARM64MSUBW OpARM64SLL OpARM64SLLconst OpARM64SRL @@ -1175,6 +1210,8 @@ const ( OpARM64MOVHUloadidx OpARM64MOVBloadidx OpARM64MOVBUloadidx + OpARM64FMOVSloadidx + OpARM64FMOVDloadidx OpARM64MOVHloadidx2 OpARM64MOVHUloadidx2 OpARM64MOVWloadidx4 @@ -1191,6 +1228,8 @@ const ( OpARM64MOVHstoreidx OpARM64MOVWstoreidx OpARM64MOVDstoreidx + OpARM64FMOVSstoreidx + OpARM64FMOVDstoreidx OpARM64MOVHstoreidx2 OpARM64MOVWstoreidx4 OpARM64MOVDstoreidx8 @@ -1755,6 +1794,8 @@ const ( OpS390XSRAW OpS390XSRADconst OpS390XSRAWconst + OpS390XRLLG + OpS390XRLL OpS390XRLLGconst OpS390XRLLconst OpS390XNEG @@ -1863,6 +1904,10 @@ const ( OpS390XLoweredAtomicExchange32 OpS390XLoweredAtomicExchange64 OpS390XFLOGR + OpS390XPOPCNT + OpS390XSumBytes2 + OpS390XSumBytes4 + OpS390XSumBytes8 OpS390XSTMG2 OpS390XSTMG3 OpS390XSTMG4 @@ -2147,6 +2192,10 @@ const ( OpPopCount16 OpPopCount32 OpPopCount64 + OpRotateLeft8 + OpRotateLeft16 + OpRotateLeft32 + OpRotateLeft64 OpSqrt OpFloor OpCeil @@ -2172,6 +2221,7 @@ const ( OpInitMem OpArg OpAddr + OpLocalAddr OpSP OpSB OpLoad @@ -2737,6 +2787,42 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "DIVSSload", + auxType: auxSymOff, + argLen: 3, + resultInArg0: true, + faultOnNilArg1: true, + symEffect: SymRead, + asm: x86.ADIVSS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + {1, 65791}, // AX CX DX BX SP BP SI DI SB + }, + outputs: []outputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + }, + }, + }, + { + name: "DIVSDload", + auxType: auxSymOff, + argLen: 3, + resultInArg0: true, + faultOnNilArg1: true, + symEffect: SymRead, + asm: x86.ADIVSD, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + {1, 65791}, // AX CX DX BX SP BP SI DI SB + }, + outputs: []outputInfo{ + {0, 65280}, // X0 X1 X2 X3 X4 X5 X6 X7 + }, + }, + }, { name: "ADDL", argLen: 2, @@ -3322,6 +3408,87 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "CMPLload", + auxType: auxSymOff, + argLen: 3, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 255}, // AX CX DX BX SP BP SI DI + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "CMPWload", + auxType: auxSymOff, + argLen: 3, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPW, + reg: regInfo{ + inputs: []inputInfo{ + {1, 255}, // AX CX DX BX SP BP SI DI + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "CMPBload", + auxType: auxSymOff, + argLen: 3, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPB, + reg: regInfo{ + inputs: []inputInfo{ + {1, 255}, // AX CX DX BX SP BP SI DI + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "CMPLconstload", + auxType: auxSymValAndOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "CMPWconstload", + auxType: auxSymValAndOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPW, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "CMPBconstload", + auxType: auxSymValAndOff, + argLen: 2, + faultOnNilArg0: true, + symEffect: SymRead, + asm: x86.ACMPB, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, { name: "UCOMISS", argLen: 2, @@ -3725,6 +3892,25 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "MULLload", + auxType: auxSymOff, + argLen: 3, + resultInArg0: true, + clobberFlags: true, + faultOnNilArg1: true, + symEffect: SymRead, + asm: x86.AIMULL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 239}, // AX CX DX BX BP SI DI + {1, 65791}, // AX CX DX BX SP BP SI DI SB + }, + outputs: []outputInfo{ + {0, 239}, // AX CX DX BX BP SI DI + }, + }, + }, { name: "ANDLload", auxType: auxSymOff, @@ -4435,6 +4621,7 @@ var opcodeTable = [...]opInfo{ name: "ADDLmodify", auxType: auxSymOff, argLen: 3, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymRead | SymWrite, asm: x86.AADDL, @@ -4449,6 +4636,7 @@ var opcodeTable = [...]opInfo{ name: "SUBLmodify", auxType: auxSymOff, argLen: 3, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymRead | SymWrite, asm: x86.ASUBL, @@ -4463,6 +4651,7 @@ var opcodeTable = [...]opInfo{ name: "ANDLmodify", auxType: auxSymOff, argLen: 3, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymRead | SymWrite, asm: x86.AANDL, @@ -4477,6 +4666,7 @@ var opcodeTable = [...]opInfo{ name: "ORLmodify", auxType: auxSymOff, argLen: 3, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymRead | SymWrite, asm: x86.AORL, @@ -4491,6 +4681,7 @@ var opcodeTable = [...]opInfo{ name: "XORLmodify", auxType: auxSymOff, argLen: 3, + clobberFlags: true, faultOnNilArg0: true, symEffect: SymRead | SymWrite, asm: x86.AXORL, @@ -4501,6 +4692,62 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "ANDLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "ORLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, + { + name: "XORLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 65791}, // AX CX DX BX SP BP SI DI SB + }, + }, + }, { name: "MOVBloadidx1", auxType: auxSymOff, @@ -5444,6 +5691,42 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "DIVSSload", + auxType: auxSymOff, + argLen: 3, + resultInArg0: true, + faultOnNilArg1: true, + symEffect: SymRead, + asm: x86.ADIVSS, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 + {1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + outputs: []outputInfo{ + {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 + }, + }, + }, + { + name: "DIVSDload", + auxType: auxSymOff, + argLen: 3, + resultInArg0: true, + faultOnNilArg1: true, + symEffect: SymRead, + asm: x86.ADIVSD, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 + {1, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + outputs: []outputInfo{ + {0, 4294901760}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 + }, + }, + }, { name: "ADDQ", argLen: 2, @@ -5942,6 +6225,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDQconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDQ, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ANDLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, { name: "ORQ", argLen: 2, @@ -6008,6 +6319,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORQconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORQ, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ORLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, { name: "XORQ", argLen: 2, @@ -6074,6 +6413,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORQconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORQ, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "XORLconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORL, + reg: regInfo{ + inputs: []inputInfo{ + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, { name: "CMPQ", argLen: 2, @@ -7322,6 +7689,156 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDQmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDQ, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "SUBQmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.ASUBQ, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ANDQmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDQ, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ORQmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORQ, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "XORQmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORQ, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ADDLmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "SUBLmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.ASUBL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ANDLmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "ORLmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, + { + name: "XORLmodify", + auxType: auxSymOff, + argLen: 3, + clobberFlags: true, + faultOnNilArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 65535}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 + {0, 4295032831}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R14 R15 SB + }, + }, + }, { name: "NEGQ", argLen: 1, @@ -14443,6 +14960,66 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "MADD", + argLen: 3, + asm: arm64.AMADD, + reg: regInfo{ + inputs: []inputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {2, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, + { + name: "MADDW", + argLen: 3, + asm: arm64.AMADDW, + reg: regInfo{ + inputs: []inputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {2, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, + { + name: "MSUB", + argLen: 3, + asm: arm64.AMSUB, + reg: regInfo{ + inputs: []inputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {2, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, + { + name: "MSUBW", + argLen: 3, + asm: arm64.AMSUBW, + reg: regInfo{ + inputs: []inputInfo{ + {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {2, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + }, + outputs: []outputInfo{ + {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 + }, + }, + }, { name: "SLL", argLen: 2, @@ -14630,9 +15207,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMN", - argLen: 2, - asm: arm64.ACMN, + name: "CMN", + argLen: 2, + commutative: true, + asm: arm64.ACMN, reg: regInfo{ inputs: []inputInfo{ {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -14652,9 +15230,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMNW", - argLen: 2, - asm: arm64.ACMNW, + name: "CMNW", + argLen: 2, + commutative: true, + asm: arm64.ACMNW, reg: regInfo{ inputs: []inputInfo{ {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -14674,9 +15253,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TST", - argLen: 2, - asm: arm64.ATST, + name: "TST", + argLen: 2, + commutative: true, + asm: arm64.ATST, reg: regInfo{ inputs: []inputInfo{ {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -14696,9 +15276,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TSTW", - argLen: 2, - asm: arm64.ATSTW, + name: "TSTW", + argLen: 2, + commutative: true, + asm: arm64.ATSTW, reg: regInfo{ inputs: []inputInfo{ {0, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -15517,6 +16098,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSloadidx", + argLen: 3, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDloadidx", + argLen: 3, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + }, + outputs: []outputInfo{ + {0, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "MOVHloadidx2", argLen: 3, @@ -15734,6 +16343,30 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "FMOVSstoreidx", + argLen: 4, + asm: arm64.AFMOVS, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, + { + name: "FMOVDstoreidx", + argLen: 4, + asm: arm64.AFMOVD, + reg: regInfo{ + inputs: []inputInfo{ + {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 + {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB + {2, 9223372034707292160}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 + }, + }, + }, { name: "MOVHstoreidx2", argLen: 4, @@ -23358,6 +23991,34 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "RLLG", + argLen: 2, + asm: s390x.ARLLG, + reg: regInfo{ + inputs: []inputInfo{ + {1, 23550}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + outputs: []outputInfo{ + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + }, + }, + { + name: "RLL", + argLen: 2, + asm: s390x.ARLL, + reg: regInfo{ + inputs: []inputInfo{ + {1, 23550}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + outputs: []outputInfo{ + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + }, + }, { name: "RLLGconst", auxType: auxInt8, @@ -24914,6 +25575,35 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "POPCNT", + argLen: 1, + clobberFlags: true, + asm: s390x.APOPCNT, + reg: regInfo{ + inputs: []inputInfo{ + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + outputs: []outputInfo{ + {0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14 + }, + }, + }, + { + name: "SumBytes2", + argLen: 1, + reg: regInfo{}, + }, + { + name: "SumBytes4", + argLen: 1, + reg: regInfo{}, + }, + { + name: "SumBytes8", + argLen: 1, + reg: regInfo{}, + }, { name: "STMG2", auxType: auxSymOff, @@ -27089,6 +27779,26 @@ var opcodeTable = [...]opInfo{ argLen: 1, generic: true, }, + { + name: "RotateLeft8", + argLen: 2, + generic: true, + }, + { + name: "RotateLeft16", + argLen: 2, + generic: true, + }, + { + name: "RotateLeft32", + argLen: 2, + generic: true, + }, + { + name: "RotateLeft64", + argLen: 2, + generic: true, + }, { name: "Sqrt", argLen: 1, @@ -27231,6 +27941,13 @@ var opcodeTable = [...]opInfo{ symEffect: SymAddr, generic: true, }, + { + name: "LocalAddr", + auxType: auxSym, + argLen: 2, + symEffect: SymAddr, + generic: true, + }, { name: "SP", argLen: 0, diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index c20f8b7ebc..af2b9ef0ed 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -425,13 +425,13 @@ func (ft *factsTable) update(parent *Block, v, w *Value, d domain, r relation) { // // Useful for i > 0; s[i-1]. lim, ok := ft.limits[x.ID] - if ok && lim.min > opMin[v.Op] { + if ok && ((d == signed && lim.min > opMin[v.Op]) || (d == unsigned && lim.umin > 0)) { ft.update(parent, x, w, d, gt) } } else if x, delta := isConstDelta(w); x != nil && delta == 1 { // v >= x+1 && x < max ⇒ v > x lim, ok := ft.limits[x.ID] - if ok && lim.max < opMax[w.Op] { + if ok && ((d == signed && lim.max < opMax[w.Op]) || (d == unsigned && lim.umax < opUMax[w.Op])) { ft.update(parent, v, x, d, gt) } } @@ -527,6 +527,11 @@ var opMax = map[Op]int64{ OpAdd32: math.MaxInt32, OpSub32: math.MaxInt32, } +var opUMax = map[Op]uint64{ + OpAdd64: math.MaxUint64, OpSub64: math.MaxUint64, + OpAdd32: math.MaxUint32, OpSub32: math.MaxUint32, +} + // isNonNegative reports whether v is known to be non-negative. func (ft *factsTable) isNonNegative(v *Value) bool { if isNonNegative(v) { diff --git a/src/cmd/compile/internal/ssa/redblack32_test.go b/src/cmd/compile/internal/ssa/redblack32_test.go index 6d72a3eee5..1ec2976072 100644 --- a/src/cmd/compile/internal/ssa/redblack32_test.go +++ b/src/cmd/compile/internal/ssa/redblack32_test.go @@ -175,8 +175,6 @@ func allRBT32Ops(te *testing.T, x []int32) { if s != "" { te.Errorf("Tree consistency problem at %v", s) return - } else { - // fmt.Printf("%s", t.DebugString()) } } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index bbf1932981..278da6fe99 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -119,6 +119,7 @@ import ( "cmd/internal/src" "cmd/internal/sys" "fmt" + "math/bits" "unsafe" ) @@ -183,26 +184,16 @@ func (s *regAllocState) RegMaskString(m regMask) string { // countRegs returns the number of set bits in the register mask. func countRegs(r regMask) int { - n := 0 - for r != 0 { - n += int(r & 1) - r >>= 1 - } - return n + return bits.OnesCount64(uint64(r)) } // pickReg picks an arbitrary register from the register mask. func pickReg(r regMask) register { - // pick the lowest one if r == 0 { panic("can't pick a register from an empty set") } - for i := register(0); ; i++ { - if r&1 != 0 { - return i - } - r >>= 1 - } + // pick the lowest one + return register(bits.TrailingZeros64(uint64(r))) } type use struct { diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index d581160b5f..ca6280deb1 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -418,6 +418,38 @@ func shiftIsBounded(v *Value) bool { return v.AuxInt != 0 } +// truncate64Fto32F converts a float64 value to a float32 preserving the bit pattern +// of the mantissa. It will panic if the truncation results in lost information. +func truncate64Fto32F(f float64) float32 { + if !isExactFloat32(f) { + panic("truncate64Fto32F: truncation is not exact") + } + if !math.IsNaN(f) { + return float32(f) + } + // NaN bit patterns aren't necessarily preserved across conversion + // instructions so we need to do the conversion manually. + b := math.Float64bits(f) + m := b & ((1 << 52) - 1) // mantissa (a.k.a. significand) + // | sign | exponent | mantissa | + r := uint32(((b >> 32) & (1 << 31)) | 0x7f800000 | (m >> (52 - 23))) + return math.Float32frombits(r) +} + +// extend32Fto64F converts a float32 value to a float64 value preserving the bit +// pattern of the mantissa. +func extend32Fto64F(f float32) float64 { + if !math.IsNaN(float64(f)) { + return float64(f) + } + // NaN bit patterns aren't necessarily preserved across conversion + // instructions so we need to do the conversion manually. + b := uint64(math.Float32bits(f)) + // | sign | exponent | mantissa | + r := ((b << 32) & (1 << 63)) | (0x7ff << 52) | ((b & 0x7fffff) << (52 - 23)) + return math.Float64frombits(r) +} + // i2f is used in rules for converting from an AuxInt to a float. func i2f(i int64) float64 { return math.Float64frombits(uint64(i)) @@ -468,7 +500,7 @@ func isSamePtr(p1, p2 *Value) bool { switch p1.Op { case OpOffPtr: return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0]) - case OpAddr: + case OpAddr, OpLocalAddr: // OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op. // Checking for value equality only works after [z]cse has run. return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op @@ -506,18 +538,17 @@ func disjoint(p1 *Value, n1 int64, p2 *Value, n2 int64) bool { // If one pointer is on the stack and the other is an argument // then they can't overlap. switch p1.Op { - case OpAddr: - if p2.Op == OpAddr || p2.Op == OpSP { + case OpAddr, OpLocalAddr: + if p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpSP { return true } return p2.Op == OpArg && p1.Args[0].Op == OpSP case OpArg: - if p2.Op == OpSP { + if p2.Op == OpSP || p2.Op == OpLocalAddr { return true } - return p2.Op == OpAddr && p2.Args[0].Op == OpSP case OpSP: - return p2.Op == OpAddr || p2.Op == OpArg || p2.Op == OpSP + return p2.Op == OpAddr || p2.Op == OpLocalAddr || p2.Op == OpArg || p2.Op == OpSP } return false } @@ -895,6 +926,54 @@ func zeroUpper32Bits(x *Value, depth int) bool { return false } +// zeroUpper48Bits is similar to zeroUpper32Bits, but for upper 48 bits +func zeroUpper48Bits(x *Value, depth int) bool { + switch x.Op { + case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2: + return true + case OpArg: + return x.Type.Width == 2 + case OpPhi, OpSelect0, OpSelect1: + // Phis can use each-other as an arguments, instead of tracking visited values, + // just limit recursion depth. + if depth <= 0 { + return false + } + for i := range x.Args { + if !zeroUpper48Bits(x.Args[i], depth-1) { + return false + } + } + return true + + } + return false +} + +// zeroUpper56Bits is similar to zeroUpper32Bits, but for upper 56 bits +func zeroUpper56Bits(x *Value, depth int) bool { + switch x.Op { + case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1: + return true + case OpArg: + return x.Type.Width == 1 + case OpPhi, OpSelect0, OpSelect1: + // Phis can use each-other as an arguments, instead of tracking visited values, + // just limit recursion depth. + if depth <= 0 { + return false + } + for i := range x.Args { + if !zeroUpper56Bits(x.Args[i], depth-1) { + return false + } + } + return true + + } + return false +} + // isInlinableMemmove reports whether the given arch performs a Move of the given size // faster than memmove. It will only return true if replacing the memmove with a Move is // safe, either because Move is small or because the arguments are disjoint. @@ -906,7 +985,7 @@ func isInlinableMemmove(dst, src *Value, sz int64, c *Config) bool { // have fast Move ops. switch c.arch { case "amd64", "amd64p32": - return sz <= 16 + return sz <= 16 || (sz < 1024 && disjoint(dst, sz, src, sz)) case "386", "ppc64", "ppc64le", "arm64": return sz <= 8 case "s390x": @@ -979,3 +1058,31 @@ func registerizable(b *Block, t interface{}) bool { } return false } + +// needRaceCleanup reports whether this call to racefuncenter/exit isn't needed. +func needRaceCleanup(sym interface{}, v *Value) bool { + f := v.Block.Func + if !f.Config.Race { + return false + } + if !isSameSym(sym, "runtime.racefuncenter") && !isSameSym(sym, "runtime.racefuncexit") { + return false + } + for _, b := range f.Blocks { + for _, v := range b.Values { + if v.Op == OpStaticCall { + switch v.Aux.(fmt.Stringer).String() { + case "runtime.racefuncenter", "runtime.racefuncexit", "runtime.panicindex", + "runtime.panicslice", "runtime.panicdivide", "runtime.panicwrap": + // Check for racefuncenter will encounter racefuncexit and vice versa. + // Allow calls to panic* + default: + // If we encountered any call, we need to keep racefunc*, + // for accurate stacktraces. + return false + } + } + } + } + return true +} diff --git a/src/cmd/compile/internal/ssa/rewrite386.go b/src/cmd/compile/internal/ssa/rewrite386.go index 7d9810b4a6..abc1d18309 100644 --- a/src/cmd/compile/internal/ssa/rewrite386.go +++ b/src/cmd/compile/internal/ssa/rewrite386.go @@ -23,6 +23,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ADDLcarry_0(v) case Op386ADDLconst: return rewriteValue386_Op386ADDLconst_0(v) + case Op386ADDLconstmodify: + return rewriteValue386_Op386ADDLconstmodify_0(v) case Op386ADDLload: return rewriteValue386_Op386ADDLload_0(v) case Op386ADDLmodify: @@ -39,6 +41,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ANDL_0(v) case Op386ANDLconst: return rewriteValue386_Op386ANDLconst_0(v) + case Op386ANDLconstmodify: + return rewriteValue386_Op386ANDLconstmodify_0(v) case Op386ANDLload: return rewriteValue386_Op386ANDLload_0(v) case Op386ANDLmodify: @@ -47,14 +51,28 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386CMPB_0(v) case Op386CMPBconst: return rewriteValue386_Op386CMPBconst_0(v) + case Op386CMPBload: + return rewriteValue386_Op386CMPBload_0(v) case Op386CMPL: return rewriteValue386_Op386CMPL_0(v) case Op386CMPLconst: - return rewriteValue386_Op386CMPLconst_0(v) + return rewriteValue386_Op386CMPLconst_0(v) || rewriteValue386_Op386CMPLconst_10(v) + case Op386CMPLload: + return rewriteValue386_Op386CMPLload_0(v) case Op386CMPW: return rewriteValue386_Op386CMPW_0(v) case Op386CMPWconst: return rewriteValue386_Op386CMPWconst_0(v) + case Op386CMPWload: + return rewriteValue386_Op386CMPWload_0(v) + case Op386DIVSD: + return rewriteValue386_Op386DIVSD_0(v) + case Op386DIVSDload: + return rewriteValue386_Op386DIVSDload_0(v) + case Op386DIVSS: + return rewriteValue386_Op386DIVSS_0(v) + case Op386DIVSSload: + return rewriteValue386_Op386DIVSSload_0(v) case Op386LEAL: return rewriteValue386_Op386LEAL_0(v) case Op386LEAL1: @@ -90,7 +108,7 @@ func rewriteValue386(v *Value) bool { case Op386MOVLloadidx4: return rewriteValue386_Op386MOVLloadidx4_0(v) case Op386MOVLstore: - return rewriteValue386_Op386MOVLstore_0(v) || rewriteValue386_Op386MOVLstore_10(v) + return rewriteValue386_Op386MOVLstore_0(v) || rewriteValue386_Op386MOVLstore_10(v) || rewriteValue386_Op386MOVLstore_20(v) case Op386MOVLstoreconst: return rewriteValue386_Op386MOVLstoreconst_0(v) case Op386MOVLstoreconstidx1: @@ -157,6 +175,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386MULL_0(v) case Op386MULLconst: return rewriteValue386_Op386MULLconst_0(v) || rewriteValue386_Op386MULLconst_10(v) || rewriteValue386_Op386MULLconst_20(v) || rewriteValue386_Op386MULLconst_30(v) + case Op386MULLload: + return rewriteValue386_Op386MULLload_0(v) case Op386MULSD: return rewriteValue386_Op386MULSD_0(v) case Op386MULSDload: @@ -173,6 +193,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386ORL_0(v) || rewriteValue386_Op386ORL_10(v) || rewriteValue386_Op386ORL_20(v) || rewriteValue386_Op386ORL_30(v) || rewriteValue386_Op386ORL_40(v) || rewriteValue386_Op386ORL_50(v) case Op386ORLconst: return rewriteValue386_Op386ORLconst_0(v) + case Op386ORLconstmodify: + return rewriteValue386_Op386ORLconstmodify_0(v) case Op386ORLload: return rewriteValue386_Op386ORLload_0(v) case Op386ORLmodify: @@ -257,6 +279,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_Op386XORL_0(v) || rewriteValue386_Op386XORL_10(v) case Op386XORLconst: return rewriteValue386_Op386XORLconst_0(v) + case Op386XORLconstmodify: + return rewriteValue386_Op386XORLconstmodify_0(v) case Op386XORLload: return rewriteValue386_Op386XORLload_0(v) case Op386XORLmodify: @@ -441,6 +465,8 @@ func rewriteValue386(v *Value) bool { return rewriteValue386_OpLess8U_0(v) case OpLoad: return rewriteValue386_OpLoad_0(v) + case OpLocalAddr: + return rewriteValue386_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValue386_OpLsh16x16_0(v) case OpLsh16x32: @@ -1539,6 +1565,62 @@ func rewriteValue386_Op386ADDLconst_0(v *Value) bool { } return false } +func rewriteValue386_Op386ADDLconstmodify_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (ADDLconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ADDLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386ADDLconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(Op386ADDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ADDLconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (ADDLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386LEAL { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386ADDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386ADDLload_0(v *Value) bool { b := v.Block _ = b @@ -2057,6 +2139,62 @@ func rewriteValue386_Op386ANDLconst_0(v *Value) bool { } return false } +func rewriteValue386_Op386ANDLconstmodify_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (ANDLconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ANDLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386ADDLconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(Op386ANDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ANDLconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (ANDLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386LEAL { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386ANDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386ANDLload_0(v *Value) bool { b := v.Block _ = b @@ -2214,9 +2352,65 @@ func rewriteValue386_Op386CMPB_0(v *Value) bool { v.AddArg(v0) return true } + // match: (CMPB l:(MOVBload {sym} [off] ptr mem) x) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (CMPBload {sym} [off] ptr x mem) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != Op386MOVBload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + x := v.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386CMPBload) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (CMPB x l:(MOVBload {sym} [off] ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (InvertFlags (CMPBload {sym} [off] ptr x mem)) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVBload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386InvertFlags) + v0 := b.NewValue0(v.Pos, Op386CMPBload, types.TypeFlags) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(x) + v0.AddArg(mem) + v.AddArg(v0) + return true + } return false } func rewriteValue386_Op386CMPBconst_0(v *Value) bool { + b := v.Block + _ = b // match: (CMPBconst (MOVLconst [x]) [y]) // cond: int8(x)==int8(y) // result: (FlagEQ) @@ -2363,6 +2557,60 @@ func rewriteValue386_Op386CMPBconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (CMPBconst l:(MOVBload {sym} [off] ptr mem) [c]) + // cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l) + // result: @l.Block (CMPBconstload {sym} [makeValAndOff(c,off)] ptr mem) + for { + c := v.AuxInt + l := v.Args[0] + if l.Op != Op386MOVBload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) { + break + } + b = l.Block + v0 := b.NewValue0(v.Pos, Op386CMPBconstload, types.TypeFlags) + v.reset(OpCopy) + v.AddArg(v0) + v0.AuxInt = makeValAndOff(c, off) + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386CMPBload_0(v *Value) bool { + // match: (CMPBload {sym} [off] ptr (MOVLconst [c]) mem) + // cond: validValAndOff(int64(int8(c)),off) + // result: (CMPBconstload {sym} [makeValAndOff(int64(int8(c)),off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386MOVLconst { + break + } + c := v_1.AuxInt + mem := v.Args[2] + if !(validValAndOff(int64(int8(c)), off)) { + break + } + v.reset(Op386CMPBconstload) + v.AuxInt = makeValAndOff(int64(int8(c)), off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } return false } func rewriteValue386_Op386CMPL_0(v *Value) bool { @@ -2402,6 +2650,60 @@ func rewriteValue386_Op386CMPL_0(v *Value) bool { v.AddArg(v0) return true } + // match: (CMPL l:(MOVLload {sym} [off] ptr mem) x) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (CMPLload {sym} [off] ptr x mem) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != Op386MOVLload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + x := v.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386CMPLload) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (CMPL x l:(MOVLload {sym} [off] ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (InvertFlags (CMPLload {sym} [off] ptr x mem)) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVLload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386InvertFlags) + v0 := b.NewValue0(v.Pos, Op386CMPLload, types.TypeFlags) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(x) + v0.AddArg(mem) + v.AddArg(v0) + return true + } return false } func rewriteValue386_Op386CMPLconst_0(v *Value) bool { @@ -2569,6 +2871,65 @@ func rewriteValue386_Op386CMPLconst_0(v *Value) bool { } return false } +func rewriteValue386_Op386CMPLconst_10(v *Value) bool { + b := v.Block + _ = b + // match: (CMPLconst l:(MOVLload {sym} [off] ptr mem) [c]) + // cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l) + // result: @l.Block (CMPLconstload {sym} [makeValAndOff(c,off)] ptr mem) + for { + c := v.AuxInt + l := v.Args[0] + if l.Op != Op386MOVLload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) { + break + } + b = l.Block + v0 := b.NewValue0(v.Pos, Op386CMPLconstload, types.TypeFlags) + v.reset(OpCopy) + v.AddArg(v0) + v0.AuxInt = makeValAndOff(c, off) + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386CMPLload_0(v *Value) bool { + // match: (CMPLload {sym} [off] ptr (MOVLconst [c]) mem) + // cond: validValAndOff(int64(int32(c)),off) + // result: (CMPLconstload {sym} [makeValAndOff(int64(int32(c)),off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386MOVLconst { + break + } + c := v_1.AuxInt + mem := v.Args[2] + if !(validValAndOff(int64(int32(c)), off)) { + break + } + v.reset(Op386CMPLconstload) + v.AuxInt = makeValAndOff(int64(int32(c)), off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386CMPW_0(v *Value) bool { b := v.Block _ = b @@ -2606,9 +2967,65 @@ func rewriteValue386_Op386CMPW_0(v *Value) bool { v.AddArg(v0) return true } + // match: (CMPW l:(MOVWload {sym} [off] ptr mem) x) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (CMPWload {sym} [off] ptr x mem) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != Op386MOVWload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + x := v.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386CMPWload) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (CMPW x l:(MOVWload {sym} [off] ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (InvertFlags (CMPWload {sym} [off] ptr x mem)) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVWload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386InvertFlags) + v0 := b.NewValue0(v.Pos, Op386CMPWload, types.TypeFlags) + v0.AuxInt = off + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(x) + v0.AddArg(mem) + v.AddArg(v0) + return true + } return false } func rewriteValue386_Op386CMPWconst_0(v *Value) bool { + b := v.Block + _ = b // match: (CMPWconst (MOVLconst [x]) [y]) // cond: int16(x)==int16(y) // result: (FlagEQ) @@ -2755,6 +3172,246 @@ func rewriteValue386_Op386CMPWconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (CMPWconst l:(MOVWload {sym} [off] ptr mem) [c]) + // cond: l.Uses == 1 && validValAndOff(c, off) && clobber(l) + // result: @l.Block (CMPWconstload {sym} [makeValAndOff(c,off)] ptr mem) + for { + c := v.AuxInt + l := v.Args[0] + if l.Op != Op386MOVWload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(l.Uses == 1 && validValAndOff(c, off) && clobber(l)) { + break + } + b = l.Block + v0 := b.NewValue0(v.Pos, Op386CMPWconstload, types.TypeFlags) + v.reset(OpCopy) + v.AddArg(v0) + v0.AuxInt = makeValAndOff(c, off) + v0.Aux = sym + v0.AddArg(ptr) + v0.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386CMPWload_0(v *Value) bool { + // match: (CMPWload {sym} [off] ptr (MOVLconst [c]) mem) + // cond: validValAndOff(int64(int16(c)),off) + // result: (CMPWconstload {sym} [makeValAndOff(int64(int16(c)),off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386MOVLconst { + break + } + c := v_1.AuxInt + mem := v.Args[2] + if !(validValAndOff(int64(int16(c)), off)) { + break + } + v.reset(Op386CMPWconstload) + v.AuxInt = makeValAndOff(int64(int16(c)), off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386DIVSD_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (DIVSD x l:(MOVSDload [off] {sym} ptr mem)) + // cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) + // result: (DIVSDload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVSDload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { + break + } + v.reset(Op386DIVSDload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386DIVSDload_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (DIVSDload [off1] {sym} val (ADDLconst [off2] base) mem) + // cond: is32Bit(off1+off2) + // result: (DIVSDload [off1+off2] {sym} val base mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386ADDLconst { + break + } + off2 := v_1.AuxInt + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(Op386DIVSDload) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (DIVSDload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (DIVSDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386LEAL { + break + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386DIVSDload) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386DIVSS_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (DIVSS x l:(MOVSSload [off] {sym} ptr mem)) + // cond: canMergeLoad(v, l, x) && !config.use387 && clobber(l) + // result: (DIVSSload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVSSload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && !config.use387 && clobber(l)) { + break + } + v.reset(Op386DIVSSload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386DIVSSload_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (DIVSSload [off1] {sym} val (ADDLconst [off2] base) mem) + // cond: is32Bit(off1+off2) + // result: (DIVSSload [off1+off2] {sym} val base mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386ADDLconst { + break + } + off2 := v_1.AuxInt + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(Op386DIVSSload) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (DIVSSload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (DIVSSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386LEAL { + break + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386DIVSSload) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } return false } func rewriteValue386_Op386LEAL_0(v *Value) bool { @@ -5969,6 +6626,173 @@ func rewriteValue386_Op386MOVLstore_10(v *Value) bool { v.AddArg(mem) return true } + // match: (MOVLstore {sym} [off] ptr y:(ADDLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) + // result: (ADDLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != Op386ADDLconst { + break + } + c := y.AuxInt + l := y.Args[0] + if l.Op != Op386MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) { + break + } + v.reset(Op386ADDLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValue386_Op386MOVLstore_20(v *Value) bool { + // match: (MOVLstore {sym} [off] ptr y:(ANDLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) + // result: (ANDLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != Op386ANDLconst { + break + } + c := y.AuxInt + l := y.Args[0] + if l.Op != Op386MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) { + break + } + v.reset(Op386ANDLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ORLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) + // result: (ORLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != Op386ORLconst { + break + } + c := y.AuxInt + l := y.Args[0] + if l.Op != Op386MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) { + break + } + v.reset(Op386ORLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(XORLconst [c] l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) && validValAndOff(c,off) + // result: (XORLconstmodify [makeValAndOff(c,off)] {sym} ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != Op386XORLconst { + break + } + c := y.AuxInt + l := y.Args[0] + if l.Op != Op386MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l) && validValAndOff(c, off)) { + break + } + v.reset(Op386XORLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } return false } func rewriteValue386_Op386MOVLstoreconst_0(v *Value) bool { @@ -9484,6 +10308,58 @@ func rewriteValue386_Op386MULL_0(v *Value) bool { v.AddArg(x) return true } + // match: (MULL x l:(MOVLload [off] {sym} ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (MULLload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != Op386MOVLload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386MULLload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MULL l:(MOVLload [off] {sym} ptr mem) x) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (MULLload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != Op386MOVLload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + x := v.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(Op386MULLload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } return false } func rewriteValue386_Op386MULLconst_0(v *Value) bool { @@ -9991,6 +10867,66 @@ func rewriteValue386_Op386MULLconst_30(v *Value) bool { } return false } +func rewriteValue386_Op386MULLload_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (MULLload [off1] {sym} val (ADDLconst [off2] base) mem) + // cond: is32Bit(off1+off2) + // result: (MULLload [off1+off2] {sym} val base mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386ADDLconst { + break + } + off2 := v_1.AuxInt + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(Op386MULLload) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (MULLload [off1] {sym1} val (LEAL [off2] {sym2} base) mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (MULLload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != Op386LEAL { + break + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386MULLload) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386MULSD_0(v *Value) bool { b := v.Block _ = b @@ -14120,6 +15056,62 @@ func rewriteValue386_Op386ORLconst_0(v *Value) bool { } return false } +func rewriteValue386_Op386ORLconstmodify_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (ORLconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ORLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386ADDLconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(Op386ORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ORLconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (ORLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386LEAL { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386ORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386ORLload_0(v *Value) bool { b := v.Block _ = b @@ -16310,6 +17302,62 @@ func rewriteValue386_Op386XORLconst_0(v *Value) bool { } return false } +func rewriteValue386_Op386XORLconstmodify_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (XORLconstmodify [valoff1] {sym} (ADDLconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (XORLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386ADDLconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(Op386XORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (XORLconstmodify [valoff1] {sym1} (LEAL [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared) + // result: (XORLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != Op386LEAL { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) && (base.Op != OpSB || !config.ctxt.Flag_shared)) { + break + } + v.reset(Op386XORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValue386_Op386XORLload_0(v *Value) bool { b := v.Block _ = b @@ -17878,6 +18926,20 @@ func rewriteValue386_OpLoad_0(v *Value) bool { } return false } +func rewriteValue386_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (LEAL {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(Op386LEAL) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValue386_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 5c681b94b7..1b531954db 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -23,6 +23,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADDLconstmodify_0(v) case OpAMD64ADDLload: return rewriteValueAMD64_OpAMD64ADDLload_0(v) + case OpAMD64ADDLmodify: + return rewriteValueAMD64_OpAMD64ADDLmodify_0(v) case OpAMD64ADDQ: return rewriteValueAMD64_OpAMD64ADDQ_0(v) || rewriteValueAMD64_OpAMD64ADDQ_10(v) || rewriteValueAMD64_OpAMD64ADDQ_20(v) case OpAMD64ADDQconst: @@ -31,6 +33,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADDQconstmodify_0(v) case OpAMD64ADDQload: return rewriteValueAMD64_OpAMD64ADDQload_0(v) + case OpAMD64ADDQmodify: + return rewriteValueAMD64_OpAMD64ADDQmodify_0(v) case OpAMD64ADDSD: return rewriteValueAMD64_OpAMD64ADDSD_0(v) case OpAMD64ADDSDload: @@ -43,14 +47,22 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ANDL_0(v) case OpAMD64ANDLconst: return rewriteValueAMD64_OpAMD64ANDLconst_0(v) + case OpAMD64ANDLconstmodify: + return rewriteValueAMD64_OpAMD64ANDLconstmodify_0(v) case OpAMD64ANDLload: return rewriteValueAMD64_OpAMD64ANDLload_0(v) + case OpAMD64ANDLmodify: + return rewriteValueAMD64_OpAMD64ANDLmodify_0(v) case OpAMD64ANDQ: return rewriteValueAMD64_OpAMD64ANDQ_0(v) case OpAMD64ANDQconst: return rewriteValueAMD64_OpAMD64ANDQconst_0(v) + case OpAMD64ANDQconstmodify: + return rewriteValueAMD64_OpAMD64ANDQconstmodify_0(v) case OpAMD64ANDQload: return rewriteValueAMD64_OpAMD64ANDQload_0(v) + case OpAMD64ANDQmodify: + return rewriteValueAMD64_OpAMD64ANDQmodify_0(v) case OpAMD64BSFQ: return rewriteValueAMD64_OpAMD64BSFQ_0(v) case OpAMD64BTLconst: @@ -153,6 +165,22 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64CMPXCHGLlock_0(v) case OpAMD64CMPXCHGQlock: return rewriteValueAMD64_OpAMD64CMPXCHGQlock_0(v) + case OpAMD64DIVSD: + return rewriteValueAMD64_OpAMD64DIVSD_0(v) + case OpAMD64DIVSDload: + return rewriteValueAMD64_OpAMD64DIVSDload_0(v) + case OpAMD64DIVSS: + return rewriteValueAMD64_OpAMD64DIVSS_0(v) + case OpAMD64DIVSSload: + return rewriteValueAMD64_OpAMD64DIVSSload_0(v) + case OpAMD64HMULL: + return rewriteValueAMD64_OpAMD64HMULL_0(v) + case OpAMD64HMULLU: + return rewriteValueAMD64_OpAMD64HMULLU_0(v) + case OpAMD64HMULQ: + return rewriteValueAMD64_OpAMD64HMULQ_0(v) + case OpAMD64HMULQU: + return rewriteValueAMD64_OpAMD64HMULQU_0(v) case OpAMD64LEAL: return rewriteValueAMD64_OpAMD64LEAL_0(v) case OpAMD64LEAL1: @@ -212,7 +240,7 @@ func rewriteValueAMD64(v *Value) bool { case OpAMD64MOVLloadidx8: return rewriteValueAMD64_OpAMD64MOVLloadidx8_0(v) case OpAMD64MOVLstore: - return rewriteValueAMD64_OpAMD64MOVLstore_0(v) || rewriteValueAMD64_OpAMD64MOVLstore_10(v) + return rewriteValueAMD64_OpAMD64MOVLstore_0(v) || rewriteValueAMD64_OpAMD64MOVLstore_10(v) || rewriteValueAMD64_OpAMD64MOVLstore_20(v) || rewriteValueAMD64_OpAMD64MOVLstore_30(v) case OpAMD64MOVLstoreconst: return rewriteValueAMD64_OpAMD64MOVLstoreconst_0(v) case OpAMD64MOVLstoreconstidx1: @@ -242,7 +270,7 @@ func rewriteValueAMD64(v *Value) bool { case OpAMD64MOVQloadidx8: return rewriteValueAMD64_OpAMD64MOVQloadidx8_0(v) case OpAMD64MOVQstore: - return rewriteValueAMD64_OpAMD64MOVQstore_0(v) + return rewriteValueAMD64_OpAMD64MOVQstore_0(v) || rewriteValueAMD64_OpAMD64MOVQstore_10(v) || rewriteValueAMD64_OpAMD64MOVQstore_20(v) case OpAMD64MOVQstoreconst: return rewriteValueAMD64_OpAMD64MOVQstoreconst_0(v) case OpAMD64MOVQstoreconstidx1: @@ -329,14 +357,22 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ORL_0(v) || rewriteValueAMD64_OpAMD64ORL_10(v) || rewriteValueAMD64_OpAMD64ORL_20(v) || rewriteValueAMD64_OpAMD64ORL_30(v) || rewriteValueAMD64_OpAMD64ORL_40(v) || rewriteValueAMD64_OpAMD64ORL_50(v) || rewriteValueAMD64_OpAMD64ORL_60(v) || rewriteValueAMD64_OpAMD64ORL_70(v) || rewriteValueAMD64_OpAMD64ORL_80(v) || rewriteValueAMD64_OpAMD64ORL_90(v) || rewriteValueAMD64_OpAMD64ORL_100(v) || rewriteValueAMD64_OpAMD64ORL_110(v) || rewriteValueAMD64_OpAMD64ORL_120(v) || rewriteValueAMD64_OpAMD64ORL_130(v) case OpAMD64ORLconst: return rewriteValueAMD64_OpAMD64ORLconst_0(v) + case OpAMD64ORLconstmodify: + return rewriteValueAMD64_OpAMD64ORLconstmodify_0(v) case OpAMD64ORLload: return rewriteValueAMD64_OpAMD64ORLload_0(v) + case OpAMD64ORLmodify: + return rewriteValueAMD64_OpAMD64ORLmodify_0(v) case OpAMD64ORQ: return rewriteValueAMD64_OpAMD64ORQ_0(v) || rewriteValueAMD64_OpAMD64ORQ_10(v) || rewriteValueAMD64_OpAMD64ORQ_20(v) || rewriteValueAMD64_OpAMD64ORQ_30(v) || rewriteValueAMD64_OpAMD64ORQ_40(v) || rewriteValueAMD64_OpAMD64ORQ_50(v) || rewriteValueAMD64_OpAMD64ORQ_60(v) || rewriteValueAMD64_OpAMD64ORQ_70(v) || rewriteValueAMD64_OpAMD64ORQ_80(v) || rewriteValueAMD64_OpAMD64ORQ_90(v) || rewriteValueAMD64_OpAMD64ORQ_100(v) || rewriteValueAMD64_OpAMD64ORQ_110(v) || rewriteValueAMD64_OpAMD64ORQ_120(v) || rewriteValueAMD64_OpAMD64ORQ_130(v) || rewriteValueAMD64_OpAMD64ORQ_140(v) || rewriteValueAMD64_OpAMD64ORQ_150(v) || rewriteValueAMD64_OpAMD64ORQ_160(v) case OpAMD64ORQconst: return rewriteValueAMD64_OpAMD64ORQconst_0(v) + case OpAMD64ORQconstmodify: + return rewriteValueAMD64_OpAMD64ORQconstmodify_0(v) case OpAMD64ORQload: return rewriteValueAMD64_OpAMD64ORQload_0(v) + case OpAMD64ORQmodify: + return rewriteValueAMD64_OpAMD64ORQmodify_0(v) case OpAMD64ROLB: return rewriteValueAMD64_OpAMD64ROLB_0(v) case OpAMD64ROLBconst: @@ -451,12 +487,16 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64SUBLconst_0(v) case OpAMD64SUBLload: return rewriteValueAMD64_OpAMD64SUBLload_0(v) + case OpAMD64SUBLmodify: + return rewriteValueAMD64_OpAMD64SUBLmodify_0(v) case OpAMD64SUBQ: return rewriteValueAMD64_OpAMD64SUBQ_0(v) case OpAMD64SUBQconst: return rewriteValueAMD64_OpAMD64SUBQconst_0(v) case OpAMD64SUBQload: return rewriteValueAMD64_OpAMD64SUBQload_0(v) + case OpAMD64SUBQmodify: + return rewriteValueAMD64_OpAMD64SUBQmodify_0(v) case OpAMD64SUBSD: return rewriteValueAMD64_OpAMD64SUBSD_0(v) case OpAMD64SUBSDload: @@ -493,14 +533,22 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64XORL_0(v) || rewriteValueAMD64_OpAMD64XORL_10(v) case OpAMD64XORLconst: return rewriteValueAMD64_OpAMD64XORLconst_0(v) || rewriteValueAMD64_OpAMD64XORLconst_10(v) + case OpAMD64XORLconstmodify: + return rewriteValueAMD64_OpAMD64XORLconstmodify_0(v) case OpAMD64XORLload: return rewriteValueAMD64_OpAMD64XORLload_0(v) + case OpAMD64XORLmodify: + return rewriteValueAMD64_OpAMD64XORLmodify_0(v) case OpAMD64XORQ: return rewriteValueAMD64_OpAMD64XORQ_0(v) || rewriteValueAMD64_OpAMD64XORQ_10(v) case OpAMD64XORQconst: return rewriteValueAMD64_OpAMD64XORQconst_0(v) + case OpAMD64XORQconstmodify: + return rewriteValueAMD64_OpAMD64XORQconstmodify_0(v) case OpAMD64XORQload: return rewriteValueAMD64_OpAMD64XORQload_0(v) + case OpAMD64XORQmodify: + return rewriteValueAMD64_OpAMD64XORQmodify_0(v) case OpAdd16: return rewriteValueAMD64_OpAdd16_0(v) case OpAdd32: @@ -783,6 +831,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpLess8U_0(v) case OpLoad: return rewriteValueAMD64_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueAMD64_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueAMD64_OpLsh16x16_0(v) case OpLsh16x32: @@ -899,6 +949,14 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpPopCount64_0(v) case OpPopCount8: return rewriteValueAMD64_OpPopCount8_0(v) + case OpRotateLeft16: + return rewriteValueAMD64_OpRotateLeft16_0(v) + case OpRotateLeft32: + return rewriteValueAMD64_OpRotateLeft32_0(v) + case OpRotateLeft64: + return rewriteValueAMD64_OpRotateLeft64_0(v) + case OpRotateLeft8: + return rewriteValueAMD64_OpRotateLeft8_0(v) case OpRound32F: return rewriteValueAMD64_OpRound32F_0(v) case OpRound64F: @@ -1874,10 +1932,6 @@ func rewriteValueAMD64_OpAMD64ADDLconst_10(v *Value) bool { return false } func rewriteValueAMD64_OpAMD64ADDLconstmodify_0(v *Value) bool { - b := v.Block - _ = b - typ := &b.Func.Config.Types - _ = typ // match: (ADDLconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) // cond: ValAndOff(valoff1).canAdd(off2) // result: (ADDLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) @@ -1927,36 +1981,6 @@ func rewriteValueAMD64_OpAMD64ADDLconstmodify_0(v *Value) bool { v.AddArg(mem) return true } - // match: (ADDLconstmodify [valOff] {sym} ptr (MOVSSstore [ValAndOff(valOff).Off()] {sym} ptr x _)) - // cond: - // result: (ADDLconst [ValAndOff(valOff).Val()] (MOVLf2i x)) - for { - valOff := v.AuxInt - sym := v.Aux - _ = v.Args[1] - ptr := v.Args[0] - v_1 := v.Args[1] - if v_1.Op != OpAMD64MOVSSstore { - break - } - if v_1.AuxInt != ValAndOff(valOff).Off() { - break - } - if v_1.Aux != sym { - break - } - _ = v_1.Args[2] - if ptr != v_1.Args[0] { - break - } - x := v_1.Args[1] - v.reset(OpAMD64ADDLconst) - v.AuxInt = ValAndOff(valOff).Val() - v0 := b.NewValue0(v.Pos, OpAMD64MOVLf2i, typ.UInt32) - v0.AddArg(x) - v.AddArg(v0) - return true - } return false } func rewriteValueAMD64_OpAMD64ADDLload_0(v *Value) bool { @@ -2050,6 +2074,62 @@ func rewriteValueAMD64_OpAMD64ADDLload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDLmodify_0(v *Value) bool { + // match: (ADDLmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ADDLmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ADDLmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ADDLmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ADDLmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDLmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ADDQ_0(v *Value) bool { // match: (ADDQ x (MOVQconst [c])) // cond: is32Bit(c) @@ -2772,10 +2852,6 @@ func rewriteValueAMD64_OpAMD64ADDQconst_10(v *Value) bool { return false } func rewriteValueAMD64_OpAMD64ADDQconstmodify_0(v *Value) bool { - b := v.Block - _ = b - typ := &b.Func.Config.Types - _ = typ // match: (ADDQconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) // cond: ValAndOff(valoff1).canAdd(off2) // result: (ADDQconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) @@ -2825,36 +2901,6 @@ func rewriteValueAMD64_OpAMD64ADDQconstmodify_0(v *Value) bool { v.AddArg(mem) return true } - // match: (ADDQconstmodify [valOff] {sym} ptr (MOVSDstore [ValAndOff(valOff).Off()] {sym} ptr x _)) - // cond: - // result: (ADDQconst [ValAndOff(valOff).Val()] (MOVQf2i x)) - for { - valOff := v.AuxInt - sym := v.Aux - _ = v.Args[1] - ptr := v.Args[0] - v_1 := v.Args[1] - if v_1.Op != OpAMD64MOVSDstore { - break - } - if v_1.AuxInt != ValAndOff(valOff).Off() { - break - } - if v_1.Aux != sym { - break - } - _ = v_1.Args[2] - if ptr != v_1.Args[0] { - break - } - x := v_1.Args[1] - v.reset(OpAMD64ADDQconst) - v.AuxInt = ValAndOff(valOff).Val() - v0 := b.NewValue0(v.Pos, OpAMD64MOVQf2i, typ.UInt64) - v0.AddArg(x) - v.AddArg(v0) - return true - } return false } func rewriteValueAMD64_OpAMD64ADDQload_0(v *Value) bool { @@ -2948,6 +2994,62 @@ func rewriteValueAMD64_OpAMD64ADDQload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDQmodify_0(v *Value) bool { + // match: (ADDQmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ADDQmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ADDQmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ADDQmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ADDQmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDQmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ADDSD_0(v *Value) bool { // match: (ADDSD x l:(MOVSDload [off] {sym} ptr mem)) // cond: canMergeLoad(v, l, x) && clobber(l) @@ -3546,6 +3648,58 @@ func rewriteValueAMD64_OpAMD64ANDLconst_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDLconstmodify_0(v *Value) bool { + // match: (ANDLconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ANDLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64ANDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ANDLconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (ANDLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ANDLload_0(v *Value) bool { b := v.Block _ = b @@ -3637,6 +3791,62 @@ func rewriteValueAMD64_OpAMD64ANDLload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDLmodify_0(v *Value) bool { + // match: (ANDLmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ANDLmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ANDLmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ANDLmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ANDLmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDLmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ANDQ_0(v *Value) bool { b := v.Block _ = b @@ -3959,6 +4169,58 @@ func rewriteValueAMD64_OpAMD64ANDQconst_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDQconstmodify_0(v *Value) bool { + // match: (ANDQconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ANDQconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64ANDQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ANDQconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (ANDQconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ANDQload_0(v *Value) bool { b := v.Block _ = b @@ -4050,6 +4312,62 @@ func rewriteValueAMD64_OpAMD64ANDQload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDQmodify_0(v *Value) bool { + // match: (ANDQmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ANDQmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ANDQmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ANDQmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ANDQmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDQmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64BSFQ_0(v *Value) bool { b := v.Block _ = b @@ -8758,6 +9076,248 @@ func rewriteValueAMD64_OpAMD64CMPXCHGQlock_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64DIVSD_0(v *Value) bool { + // match: (DIVSD x l:(MOVSDload [off] {sym} ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (DIVSDload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != OpAMD64MOVSDload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(OpAMD64DIVSDload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64DIVSDload_0(v *Value) bool { + // match: (DIVSDload [off1] {sym} val (ADDQconst [off2] base) mem) + // cond: is32Bit(off1+off2) + // result: (DIVSDload [off1+off2] {sym} val base mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpAMD64ADDQconst { + break + } + off2 := v_1.AuxInt + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64DIVSDload) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (DIVSDload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (DIVSDload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpAMD64LEAQ { + break + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64DIVSDload) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64DIVSS_0(v *Value) bool { + // match: (DIVSS x l:(MOVSSload [off] {sym} ptr mem)) + // cond: canMergeLoad(v, l, x) && clobber(l) + // result: (DIVSSload x [off] {sym} ptr mem) + for { + _ = v.Args[1] + x := v.Args[0] + l := v.Args[1] + if l.Op != OpAMD64MOVSSload { + break + } + off := l.AuxInt + sym := l.Aux + _ = l.Args[1] + ptr := l.Args[0] + mem := l.Args[1] + if !(canMergeLoad(v, l, x) && clobber(l)) { + break + } + v.reset(OpAMD64DIVSSload) + v.AuxInt = off + v.Aux = sym + v.AddArg(x) + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64DIVSSload_0(v *Value) bool { + // match: (DIVSSload [off1] {sym} val (ADDQconst [off2] base) mem) + // cond: is32Bit(off1+off2) + // result: (DIVSSload [off1+off2] {sym} val base mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpAMD64ADDQconst { + break + } + off2 := v_1.AuxInt + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64DIVSSload) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (DIVSSload [off1] {sym1} val (LEAQ [off2] {sym2} base) mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (DIVSSload [off1+off2] {mergeSym(sym1,sym2)} val base mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + val := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpAMD64LEAQ { + break + } + off2 := v_1.AuxInt + sym2 := v_1.Aux + base := v_1.Args[0] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64DIVSSload) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(val) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64HMULL_0(v *Value) bool { + // match: (HMULL x y) + // cond: !x.rematerializeable() && y.rematerializeable() + // result: (HMULL y x) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + if !(!x.rematerializeable() && y.rematerializeable()) { + break + } + v.reset(OpAMD64HMULL) + v.AddArg(y) + v.AddArg(x) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64HMULLU_0(v *Value) bool { + // match: (HMULLU x y) + // cond: !x.rematerializeable() && y.rematerializeable() + // result: (HMULLU y x) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + if !(!x.rematerializeable() && y.rematerializeable()) { + break + } + v.reset(OpAMD64HMULLU) + v.AddArg(y) + v.AddArg(x) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64HMULQ_0(v *Value) bool { + // match: (HMULQ x y) + // cond: !x.rematerializeable() && y.rematerializeable() + // result: (HMULQ y x) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + if !(!x.rematerializeable() && y.rematerializeable()) { + break + } + v.reset(OpAMD64HMULQ) + v.AddArg(y) + v.AddArg(x) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64HMULQU_0(v *Value) bool { + // match: (HMULQU x y) + // cond: !x.rematerializeable() && y.rematerializeable() + // result: (HMULQU y x) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + if !(!x.rematerializeable() && y.rematerializeable()) { + break + } + v.reset(OpAMD64HMULQU) + v.AddArg(y) + v.AddArg(x) + return true + } + return false +} func rewriteValueAMD64_OpAMD64LEAL_0(v *Value) bool { // match: (LEAL [c] {s} (ADDLconst [d] x)) // cond: is32Bit(c+d) @@ -10220,6 +10780,19 @@ func rewriteValueAMD64_OpAMD64MOVBQZX_0(v *Value) bool { v0.AddArg(mem) return true } + // match: (MOVBQZX x) + // cond: zeroUpper56Bits(x,3) + // result: x + for { + x := v.Args[0] + if !(zeroUpper56Bits(x, 3)) { + break + } + v.reset(OpCopy) + v.Type = x.Type + v.AddArg(x) + return true + } // match: (MOVBQZX x:(MOVBloadidx1 [off] {sym} ptr idx mem)) // cond: x.Uses == 1 && clobber(x) // result: @x.Block (MOVBloadidx1 [off] {sym} ptr idx mem) @@ -14333,6 +14906,548 @@ func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool { v.AddArg(mem) return true } + // match: (MOVLstore {sym} [off] ptr y:(ADDLload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ADDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDLload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ADDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ANDLload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ANDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDLload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ANDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ORLload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORLload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(XORLload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (XORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORLload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64XORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ADDL l:(MOVLload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ADDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDL { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ADDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ADDL x l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ADDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDL { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ADDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64MOVLstore_20(v *Value) bool { + // match: (MOVLstore {sym} [off] ptr y:(SUBL l:(MOVLload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (SUBLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64SUBL { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64SUBLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ANDL l:(MOVLload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ANDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDL { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ANDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ANDL x l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ANDLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDL { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ANDLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ORL l:(MOVLload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORL { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(ORL x l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORL { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(XORL l:(MOVLload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (XORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORL { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64XORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVLstore {sym} [off] ptr y:(XORL x l:(MOVLload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (XORLmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORL { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64XORLmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } // match: (MOVLstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) // result: (ADDLconstmodify {sym} [makeValAndOff(c,off)] ptr mem) @@ -14372,6 +15487,126 @@ func rewriteValueAMD64_OpAMD64MOVLstore_10(v *Value) bool { v.AddArg(mem) return true } + // match: (MOVLstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (ANDLconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64ANDLconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64ANDLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MOVLstore [off] {sym} ptr a:(ORLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (ORLconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64ORLconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64ORLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64MOVLstore_30(v *Value) bool { + // match: (MOVLstore [off] {sym} ptr a:(XORLconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (XORLconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64XORLconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVLload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64XORLconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } // match: (MOVLstore [off] {sym} ptr (MOVLf2i val) mem) // cond: // result: (MOVSSstore [off] {sym} ptr val mem) @@ -16319,6 +17554,551 @@ func rewriteValueAMD64_OpAMD64MOVQstore_0(v *Value) bool { v.AddArg(mem) return true } + // match: (MOVQstore {sym} [off] ptr y:(ADDQload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ADDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDQload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ADDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ANDQload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ANDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDQload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ANDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64MOVQstore_10(v *Value) bool { + // match: (MOVQstore {sym} [off] ptr y:(ORQload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (ORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORQload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64ORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(XORQload x [off] {sym} ptr mem) mem) + // cond: y.Uses==1 && clobber(y) + // result: (XORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORQload { + break + } + if y.AuxInt != off { + break + } + if y.Aux != sym { + break + } + _ = y.Args[2] + x := y.Args[0] + if ptr != y.Args[1] { + break + } + mem := y.Args[2] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && clobber(y)) { + break + } + v.reset(OpAMD64XORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ADDQ l:(MOVQload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ADDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDQ { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ADDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ADDQ x l:(MOVQload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ADDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ADDQ { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ADDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(SUBQ l:(MOVQload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (SUBQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64SUBQ { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64SUBQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ANDQ l:(MOVQload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ANDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDQ { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ANDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ANDQ x l:(MOVQload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ANDQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ANDQ { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ANDQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ORQ l:(MOVQload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORQ { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(ORQ x l:(MOVQload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (ORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64ORQ { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64ORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + // match: (MOVQstore {sym} [off] ptr y:(XORQ l:(MOVQload [off] {sym} ptr mem) x) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (XORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORQ { + break + } + _ = y.Args[1] + l := y.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + x := y.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64XORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64MOVQstore_20(v *Value) bool { + // match: (MOVQstore {sym} [off] ptr y:(XORQ x l:(MOVQload [off] {sym} ptr mem)) mem) + // cond: y.Uses==1 && l.Uses==1 && clobber(y) && clobber(l) + // result: (XORQmodify [off] {sym} ptr x mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + y := v.Args[1] + if y.Op != OpAMD64XORQ { + break + } + _ = y.Args[1] + x := y.Args[0] + l := y.Args[1] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + if ptr != l.Args[0] { + break + } + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(y.Uses == 1 && l.Uses == 1 && clobber(y) && clobber(l)) { + break + } + v.reset(OpAMD64XORQmodify) + v.AuxInt = off + v.Aux = sym + v.AddArg(ptr) + v.AddArg(x) + v.AddArg(mem) + return true + } // match: (MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) // result: (ADDQconstmodify {sym} [makeValAndOff(c,off)] ptr mem) @@ -16358,6 +18138,123 @@ func rewriteValueAMD64_OpAMD64MOVQstore_0(v *Value) bool { v.AddArg(mem) return true } + // match: (MOVQstore [off] {sym} ptr a:(ANDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (ANDQconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64ANDQconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64ANDQconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MOVQstore [off] {sym} ptr a:(ORQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (ORQconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64ORQconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64ORQconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (MOVQstore [off] {sym} ptr a:(XORQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) + // result: (XORQconstmodify {sym} [makeValAndOff(c,off)] ptr mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + ptr := v.Args[0] + a := v.Args[1] + if a.Op != OpAMD64XORQconst { + break + } + c := a.AuxInt + l := a.Args[0] + if l.Op != OpAMD64MOVQload { + break + } + if l.AuxInt != off { + break + } + if l.Aux != sym { + break + } + _ = l.Args[1] + ptr2 := l.Args[0] + mem := l.Args[1] + if mem != v.Args[2] { + break + } + if !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c, off)) { + break + } + v.reset(OpAMD64XORQconstmodify) + v.AuxInt = makeValAndOff(c, off) + v.Aux = sym + v.AddArg(ptr) + v.AddArg(mem) + return true + } // match: (MOVQstore [off] {sym} ptr (MOVQf2i val) mem) // cond: // result: (MOVSDstore [off] {sym} ptr val mem) @@ -18606,6 +20503,19 @@ func rewriteValueAMD64_OpAMD64MOVWQZX_0(v *Value) bool { v0.AddArg(mem) return true } + // match: (MOVWQZX x) + // cond: zeroUpper48Bits(x,3) + // result: x + for { + x := v.Args[0] + if !(zeroUpper48Bits(x, 3)) { + break + } + v.reset(OpCopy) + v.Type = x.Type + v.AddArg(x) + return true + } // match: (MOVWQZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) // cond: x.Uses == 1 && clobber(x) // result: @x.Block (MOVWloadidx1 [off] {sym} ptr idx mem) @@ -30845,6 +32755,58 @@ func rewriteValueAMD64_OpAMD64ORLconst_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORLconstmodify_0(v *Value) bool { + // match: (ORLconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ORLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64ORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ORLconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (ORLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ORLload_0(v *Value) bool { b := v.Block _ = b @@ -30936,6 +32898,62 @@ func rewriteValueAMD64_OpAMD64ORLload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORLmodify_0(v *Value) bool { + // match: (ORLmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ORLmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ORLmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ORLmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ORLmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORLmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ORQ_0(v *Value) bool { b := v.Block _ = b @@ -41754,6 +43772,58 @@ func rewriteValueAMD64_OpAMD64ORQconst_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORQconstmodify_0(v *Value) bool { + // match: (ORQconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (ORQconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64ORQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (ORQconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (ORQconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ORQload_0(v *Value) bool { b := v.Block _ = b @@ -41845,6 +43915,62 @@ func rewriteValueAMD64_OpAMD64ORQload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORQmodify_0(v *Value) bool { + // match: (ORQmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (ORQmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64ORQmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (ORQmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (ORQmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORQmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ROLB_0(v *Value) bool { // match: (ROLB x (NEGQ y)) // cond: @@ -50555,6 +52681,62 @@ func rewriteValueAMD64_OpAMD64SUBLload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64SUBLmodify_0(v *Value) bool { + // match: (SUBLmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (SUBLmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64SUBLmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (SUBLmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (SUBLmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64SUBLmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64SUBQ_0(v *Value) bool { b := v.Block _ = b @@ -50793,6 +52975,62 @@ func rewriteValueAMD64_OpAMD64SUBQload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64SUBQmodify_0(v *Value) bool { + // match: (SUBQmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (SUBQmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64SUBQmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (SUBQmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (SUBQmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64SUBQmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64SUBSD_0(v *Value) bool { // match: (SUBSD x l:(MOVSDload [off] {sym} ptr mem)) // cond: canMergeLoad(v, l, x) && clobber(l) @@ -52250,6 +54488,58 @@ func rewriteValueAMD64_OpAMD64XORLconst_10(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORLconstmodify_0(v *Value) bool { + // match: (XORLconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (XORLconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64XORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (XORLconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (XORLconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORLconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64XORLload_0(v *Value) bool { b := v.Block _ = b @@ -52341,6 +54631,62 @@ func rewriteValueAMD64_OpAMD64XORLload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORLmodify_0(v *Value) bool { + // match: (XORLmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (XORLmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64XORLmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (XORLmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (XORLmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORLmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64XORQ_0(v *Value) bool { b := v.Block _ = b @@ -52664,6 +55010,58 @@ func rewriteValueAMD64_OpAMD64XORQconst_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORQconstmodify_0(v *Value) bool { + // match: (XORQconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) + // result: (XORQconstmodify [ValAndOff(valoff1).add(off2)] {sym} base mem) + for { + valoff1 := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2)) { + break + } + v.reset(OpAMD64XORQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = sym + v.AddArg(base) + v.AddArg(mem) + return true + } + // match: (XORQconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2) + // result: (XORQconstmodify [ValAndOff(valoff1).add(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + mem := v.Args[1] + if !(ValAndOff(valoff1).canAdd(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORQconstmodify) + v.AuxInt = ValAndOff(valoff1).add(off2) + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64XORQload_0(v *Value) bool { b := v.Block _ = b @@ -52755,6 +55153,62 @@ func rewriteValueAMD64_OpAMD64XORQload_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORQmodify_0(v *Value) bool { + // match: (XORQmodify [off1] {sym} (ADDQconst [off2] base) val mem) + // cond: is32Bit(off1+off2) + // result: (XORQmodify [off1+off2] {sym} base val mem) + for { + off1 := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := v_0.AuxInt + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1 + off2)) { + break + } + v.reset(OpAMD64XORQmodify) + v.AuxInt = off1 + off2 + v.Aux = sym + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (XORQmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) + // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2) + // result: (XORQmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) + for { + off1 := v.AuxInt + sym1 := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := v_0.AuxInt + sym2 := v_0.Aux + base := v_0.Args[0] + val := v.Args[1] + mem := v.Args[2] + if !(is32Bit(off1+off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORQmodify) + v.AuxInt = off1 + off2 + v.Aux = mergeSym(sym1, sym2) + v.AddArg(base) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueAMD64_OpAdd16_0(v *Value) bool { // match: (Add16 x y) // cond: @@ -56369,6 +58823,43 @@ func rewriteValueAMD64_OpLoad_0(v *Value) bool { } return false } +func rewriteValueAMD64_OpLocalAddr_0(v *Value) bool { + b := v.Block + _ = b + config := b.Func.Config + _ = config + // match: (LocalAddr {sym} base _) + // cond: config.PtrSize == 8 + // result: (LEAQ {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + if !(config.PtrSize == 8) { + break + } + v.reset(OpAMD64LEAQ) + v.Aux = sym + v.AddArg(base) + return true + } + // match: (LocalAddr {sym} base _) + // cond: config.PtrSize == 4 + // result: (LEAL {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + if !(config.PtrSize == 4) { + break + } + v.reset(OpAMD64LEAL) + v.Aux = sym + v.AddArg(base) + return true + } + return false +} func rewriteValueAMD64_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b @@ -58342,6 +60833,62 @@ func rewriteValueAMD64_OpPopCount8_0(v *Value) bool { return true } } +func rewriteValueAMD64_OpRotateLeft16_0(v *Value) bool { + // match: (RotateLeft16 a b) + // cond: + // result: (ROLW a b) + for { + _ = v.Args[1] + a := v.Args[0] + b := v.Args[1] + v.reset(OpAMD64ROLW) + v.AddArg(a) + v.AddArg(b) + return true + } +} +func rewriteValueAMD64_OpRotateLeft32_0(v *Value) bool { + // match: (RotateLeft32 a b) + // cond: + // result: (ROLL a b) + for { + _ = v.Args[1] + a := v.Args[0] + b := v.Args[1] + v.reset(OpAMD64ROLL) + v.AddArg(a) + v.AddArg(b) + return true + } +} +func rewriteValueAMD64_OpRotateLeft64_0(v *Value) bool { + // match: (RotateLeft64 a b) + // cond: + // result: (ROLQ a b) + for { + _ = v.Args[1] + a := v.Args[0] + b := v.Args[1] + v.reset(OpAMD64ROLQ) + v.AddArg(a) + v.AddArg(b) + return true + } +} +func rewriteValueAMD64_OpRotateLeft8_0(v *Value) bool { + // match: (RotateLeft8 a b) + // cond: + // result: (ROLB a b) + for { + _ = v.Args[1] + a := v.Args[0] + b := v.Args[1] + v.reset(OpAMD64ROLB) + v.AddArg(a) + v.AddArg(b) + return true + } +} func rewriteValueAMD64_OpRound32F_0(v *Value) bool { // match: (Round32F x) // cond: diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go index 1eb32285cd..966413ab25 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM.go +++ b/src/cmd/compile/internal/ssa/rewriteARM.go @@ -619,6 +619,8 @@ func rewriteValueARM(v *Value) bool { return rewriteValueARM_OpLess8U_0(v) case OpLoad: return rewriteValueARM_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueARM_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueARM_OpLsh16x16_0(v) case OpLsh16x32: @@ -2848,6 +2850,20 @@ func rewriteValueARM_OpARMADDconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (ADDconst [c] x) + // cond: objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && uint32(-c)<=0xffff + // result: (SUBconst [int64(int32(-c))] x) + for { + c := v.AuxInt + x := v.Args[0] + if !(objabi.GOARM == 7 && !isARMImmRot(uint32(c)) && uint32(c) > 0xffff && uint32(-c) <= 0xffff) { + break + } + v.reset(OpARMSUBconst) + v.AuxInt = int64(int32(-c)) + v.AddArg(x) + return true + } // match: (ADDconst [c] (MOVWconst [d])) // cond: // result: (MOVWconst [int64(int32(c+d))]) @@ -3668,6 +3684,20 @@ func rewriteValueARM_OpARMANDconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (ANDconst [c] x) + // cond: objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && ^uint32(c)<=0xffff + // result: (BICconst [int64(int32(^uint32(c)))] x) + for { + c := v.AuxInt + x := v.Args[0] + if !(objabi.GOARM == 7 && !isARMImmRot(uint32(c)) && uint32(c) > 0xffff && ^uint32(c) <= 0xffff) { + break + } + v.reset(OpARMBICconst) + v.AuxInt = int64(int32(^uint32(c))) + v.AddArg(x) + return true + } // match: (ANDconst [c] (MOVWconst [d])) // cond: // result: (MOVWconst [c&d]) @@ -4241,6 +4271,20 @@ func rewriteValueARM_OpARMBICconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (BICconst [c] x) + // cond: objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && ^uint32(c)<=0xffff + // result: (ANDconst [int64(int32(^uint32(c)))] x) + for { + c := v.AuxInt + x := v.Args[0] + if !(objabi.GOARM == 7 && !isARMImmRot(uint32(c)) && uint32(c) > 0xffff && ^uint32(c) <= 0xffff) { + break + } + v.reset(OpARMANDconst) + v.AuxInt = int64(int32(^uint32(c))) + v.AddArg(x) + return true + } // match: (BICconst [c] (MOVWconst [d])) // cond: // result: (MOVWconst [d&^c]) @@ -15241,6 +15285,20 @@ func rewriteValueARM_OpARMSUBconst_0(v *Value) bool { v.AddArg(x) return true } + // match: (SUBconst [c] x) + // cond: objabi.GOARM==7 && !isARMImmRot(uint32(c)) && uint32(c)>0xffff && uint32(-c)<=0xffff + // result: (ANDconst [int64(int32(-c))] x) + for { + c := v.AuxInt + x := v.Args[0] + if !(objabi.GOARM == 7 && !isARMImmRot(uint32(c)) && uint32(c) > 0xffff && uint32(-c) <= 0xffff) { + break + } + v.reset(OpARMANDconst) + v.AuxInt = int64(int32(-c)) + v.AddArg(x) + return true + } // match: (SUBconst [c] (MOVWconst [d])) // cond: // result: (MOVWconst [int64(int32(d-c))]) @@ -19344,6 +19402,20 @@ func rewriteValueARM_OpLoad_0(v *Value) bool { } return false } +func rewriteValueARM_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVWaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpARMMOVWaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueARM_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b @@ -22184,8 +22256,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUB x y)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 // result: (EQ (CMP x y) yes no) for { v := b.Control @@ -22195,13 +22267,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUB { + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) v0.AddArg(x) @@ -22210,8 +22285,41 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBconst [c] x)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (EQ (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMEQ + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 // result: (EQ (CMPconst [c] x) yes no) for { v := b.Control @@ -22221,12 +22329,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBconst { + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c @@ -22235,8 +22346,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftLL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftLL x y [c]) yes no) for { v := b.Control @@ -22246,14 +22357,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftLL { + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c @@ -22263,8 +22377,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftRL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftRL x y [c]) yes no) for { v := b.Control @@ -22274,14 +22388,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRL { + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c @@ -22291,8 +22408,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftRA x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftRA x y [c]) yes no) for { v := b.Control @@ -22302,14 +22419,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRA { + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c @@ -22319,8 +22439,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftLLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftLLreg x y z) yes no) for { v := b.Control @@ -22330,14 +22450,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftLLreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -22347,8 +22470,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftRLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftRLreg x y z) yes no) for { v := b.Control @@ -22358,14 +22481,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRLreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -22375,8 +22501,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (SUBshiftRAreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMPshiftRAreg x y z) yes no) for { v := b.Control @@ -22386,14 +22512,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRAreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -22403,8 +22532,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADD x y)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 // result: (EQ (CMN x y) yes no) for { v := b.Control @@ -22414,13 +22543,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADD { + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) v0.AddArg(x) @@ -22429,8 +22561,41 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDconst [c] x)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (EQ (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMEQ + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 // result: (EQ (CMNconst [c] x) yes no) for { v := b.Control @@ -22440,12 +22605,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDconst { + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c @@ -22454,8 +22622,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftLL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftLL x y [c]) yes no) for { v := b.Control @@ -22465,14 +22633,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftLL { + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c @@ -22482,8 +22653,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftRL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftRL x y [c]) yes no) for { v := b.Control @@ -22493,14 +22664,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRL { + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c @@ -22510,8 +22684,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftRA x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftRA x y [c]) yes no) for { v := b.Control @@ -22521,14 +22695,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRA { + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c @@ -22538,8 +22715,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftLLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftLLreg x y z) yes no) for { v := b.Control @@ -22549,14 +22726,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftLLreg { + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -22566,8 +22746,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftRLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftRLreg x y z) yes no) for { v := b.Control @@ -22577,14 +22757,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRLreg { + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -22594,8 +22777,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ADDshiftRAreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (CMNshiftRAreg x y z) yes no) for { v := b.Control @@ -22605,14 +22788,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRAreg { + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -22622,8 +22808,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (AND x y)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 // result: (EQ (TST x y) yes no) for { v := b.Control @@ -22633,13 +22819,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMAND { + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) v0.AddArg(x) @@ -22648,8 +22837,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDconst [c] x)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 // result: (EQ (TSTconst [c] x) yes no) for { v := b.Control @@ -22659,12 +22848,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDconst { + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = c @@ -22673,8 +22865,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftLL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftLL x y [c]) yes no) for { v := b.Control @@ -22684,14 +22876,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftLL { + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = c @@ -22701,8 +22896,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftRL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftRL x y [c]) yes no) for { v := b.Control @@ -22712,14 +22907,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRL { + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = c @@ -22729,8 +22927,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftRA x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftRA x y [c]) yes no) for { v := b.Control @@ -22740,14 +22938,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRA { + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = c @@ -22757,8 +22958,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftLLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftLLreg x y z) yes no) for { v := b.Control @@ -22768,14 +22969,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftLLreg { + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -22785,8 +22989,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftRLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftRLreg x y z) yes no) for { v := b.Control @@ -22796,14 +23000,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRLreg { + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -22813,8 +23020,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (ANDshiftRAreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TSTshiftRAreg x y z) yes no) for { v := b.Control @@ -22824,14 +23031,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRAreg { + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -22841,8 +23051,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XOR x y)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 // result: (EQ (TEQ x y) yes no) for { v := b.Control @@ -22852,13 +23062,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXOR { + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg(x) @@ -22867,8 +23080,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORconst [c] x)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 // result: (EQ (TEQconst [c] x) yes no) for { v := b.Control @@ -22878,12 +23091,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORconst { + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = c @@ -22892,8 +23108,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftLL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftLL x y [c]) yes no) for { v := b.Control @@ -22903,14 +23119,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftLL { + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = c @@ -22920,8 +23139,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftRL x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftRL x y [c]) yes no) for { v := b.Control @@ -22931,14 +23150,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRL { + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = c @@ -22948,8 +23170,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftRA x y [c])) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftRA x y [c]) yes no) for { v := b.Control @@ -22959,14 +23181,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRA { + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = c @@ -22976,8 +23201,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftLLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftLLreg x y z) yes no) for { v := b.Control @@ -22987,14 +23212,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftLLreg { + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -23004,8 +23232,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftRLreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftRLreg x y z) yes no) for { v := b.Control @@ -23015,14 +23243,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRLreg { + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -23032,8 +23263,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (EQ (CMPconst [0] (XORshiftRAreg x y z)) yes no) - // cond: + // match: (EQ (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (EQ (TEQshiftRAreg x y z) yes no) for { v := b.Control @@ -23043,14 +23274,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRAreg { + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMEQ v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -23142,6 +23376,1044 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } + // match: (GE (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 + // result: (GE (CMP x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (GE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GE (CMPconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMPshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 + // result: (GE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (GE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GE (CMNconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (CMNshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 + // result: (GE (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GE (TSTconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TSTshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 + // result: (GE (TEQ x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GE (TEQconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GE (TEQshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockARMGT: // match: (GT (FlagEQ) yes no) // cond: @@ -23225,6 +24497,1044 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } + // match: (GT (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 + // result: (GT (CMP x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (GT (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GT (CMPconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMPshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 + // result: (GT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GT (CMNconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (CMNshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 + // result: (GT (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (GT (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GT (TSTconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TSTshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 + // result: (GT (TEQ x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (GT (TEQconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (GT (TEQshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMGT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockIf: // match: (If (Equal cc) yes no) // cond: @@ -23463,6 +25773,1044 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } + // match: (LE (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 + // result: (LE (CMP x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (LE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LE (CMPconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMPshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 + // result: (LE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (LE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LE (CMNconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (CMNshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 + // result: (LE (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LE (TSTconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TSTshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 + // result: (LE (TEQ x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LE (TEQconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LE (TEQshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLE + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockARMLT: // match: (LT (FlagEQ) yes no) // cond: @@ -23546,6 +26894,1044 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } + // match: (LT (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 + // result: (LT (CMP x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (LT (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LT (CMPconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMPshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 + // result: (LT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (LT (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LT (CMNconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (CMNshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 + // result: (LT (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LT (TSTconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TSTshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 + // result: (LT (TEQ x y) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 + // result: (LT (TEQconst [c] x) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftLL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftRL x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftRA x y [c]) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftLLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftRLreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 + // result: (LT (TEQshiftRAreg x y z) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMLT + v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + v0.AddArg(z) + b.SetControl(v0) + b.Aux = nil + return true + } case BlockARMNE: // match: (NE (CMPconst [0] (Equal cc)) yes no) // cond: @@ -23837,8 +28223,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUB x y)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUB x y)) yes no) + // cond: l.Uses==1 // result: (NE (CMP x y) yes no) for { v := b.Control @@ -23848,13 +28234,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUB { + l := v.Args[0] + if l.Op != OpARMSUB { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) v0.AddArg(x) @@ -23863,8 +28252,41 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBconst [c] x)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(MULS x y a)) yes no) + // cond: l.Uses==1 + // result: (NE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULS { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMNE + v0 := b.NewValue0(v.Pos, OpARMCMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] l:(SUBconst [c] x)) yes no) + // cond: l.Uses==1 // result: (NE (CMPconst [c] x) yes no) for { v := b.Control @@ -23874,12 +28296,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBconst { + l := v.Args[0] + if l.Op != OpARMSUBconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPconst, types.TypeFlags) v0.AuxInt = c @@ -23888,8 +28313,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftLL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftLL x y [c]) yes no) for { v := b.Control @@ -23899,14 +28324,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftLL { + l := v.Args[0] + if l.Op != OpARMSUBshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftLL, types.TypeFlags) v0.AuxInt = c @@ -23916,8 +28344,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftRL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftRL x y [c]) yes no) for { v := b.Control @@ -23927,14 +28355,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRL { + l := v.Args[0] + if l.Op != OpARMSUBshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftRL, types.TypeFlags) v0.AuxInt = c @@ -23944,8 +28375,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftRA x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftRA x y [c]) yes no) for { v := b.Control @@ -23955,14 +28386,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRA { + l := v.Args[0] + if l.Op != OpARMSUBshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftRA, types.TypeFlags) v0.AuxInt = c @@ -23972,8 +28406,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftLLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftLLreg x y z) yes no) for { v := b.Control @@ -23983,14 +28417,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftLLreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -24000,8 +28437,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftRLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftRLreg x y z) yes no) for { v := b.Control @@ -24011,14 +28448,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRLreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -24028,8 +28468,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (SUBshiftRAreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMPshiftRAreg x y z) yes no) for { v := b.Control @@ -24039,14 +28479,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMSUBshiftRAreg { + l := v.Args[0] + if l.Op != OpARMSUBshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMPshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -24056,8 +28499,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADD x y)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADD x y)) yes no) + // cond: l.Uses==1 // result: (NE (CMN x y) yes no) for { v := b.Control @@ -24067,13 +28510,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADD { + l := v.Args[0] + if l.Op != OpARMADD { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) v0.AddArg(x) @@ -24082,8 +28528,41 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDconst [c] x)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(MULA x y a)) yes no) + // cond: l.Uses==1 + // result: (NE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARMCMPconst { + break + } + if v.AuxInt != 0 { + break + } + l := v.Args[0] + if l.Op != OpARMMULA { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + a := l.Args[2] + if !(l.Uses == 1) { + break + } + b.Kind = BlockARMNE + v0 := b.NewValue0(v.Pos, OpARMCMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARMMUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] l:(ADDconst [c] x)) yes no) + // cond: l.Uses==1 // result: (NE (CMNconst [c] x) yes no) for { v := b.Control @@ -24093,12 +28572,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDconst { + l := v.Args[0] + if l.Op != OpARMADDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNconst, types.TypeFlags) v0.AuxInt = c @@ -24107,8 +28589,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftLL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftLL x y [c]) yes no) for { v := b.Control @@ -24118,14 +28600,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftLL { + l := v.Args[0] + if l.Op != OpARMADDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftLL, types.TypeFlags) v0.AuxInt = c @@ -24135,8 +28620,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftRL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftRL x y [c]) yes no) for { v := b.Control @@ -24146,14 +28631,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRL { + l := v.Args[0] + if l.Op != OpARMADDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftRL, types.TypeFlags) v0.AuxInt = c @@ -24163,8 +28651,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftRA x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftRA x y [c]) yes no) for { v := b.Control @@ -24174,14 +28662,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRA { + l := v.Args[0] + if l.Op != OpARMADDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftRA, types.TypeFlags) v0.AuxInt = c @@ -24191,8 +28682,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftLLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftLLreg x y z) yes no) for { v := b.Control @@ -24202,14 +28693,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftLLreg { + l := v.Args[0] + if l.Op != OpARMADDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -24219,8 +28713,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftRLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftRLreg x y z) yes no) for { v := b.Control @@ -24230,14 +28724,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRLreg { + l := v.Args[0] + if l.Op != OpARMADDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -24247,8 +28744,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ADDshiftRAreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (CMNshiftRAreg x y z) yes no) for { v := b.Control @@ -24258,14 +28755,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMADDshiftRAreg { + l := v.Args[0] + if l.Op != OpARMADDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMCMNshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -24275,8 +28775,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (AND x y)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(AND x y)) yes no) + // cond: l.Uses==1 // result: (NE (TST x y) yes no) for { v := b.Control @@ -24286,13 +28786,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMAND { + l := v.Args[0] + if l.Op != OpARMAND { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTST, types.TypeFlags) v0.AddArg(x) @@ -24301,8 +28804,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDconst [c] x)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDconst [c] x)) yes no) + // cond: l.Uses==1 // result: (NE (TSTconst [c] x) yes no) for { v := b.Control @@ -24312,12 +28815,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDconst { + l := v.Args[0] + if l.Op != OpARMANDconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTconst, types.TypeFlags) v0.AuxInt = c @@ -24326,8 +28832,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftLL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftLL x y [c]) yes no) for { v := b.Control @@ -24337,14 +28843,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftLL { + l := v.Args[0] + if l.Op != OpARMANDshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftLL, types.TypeFlags) v0.AuxInt = c @@ -24354,8 +28863,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftRL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftRL x y [c]) yes no) for { v := b.Control @@ -24365,14 +28874,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRL { + l := v.Args[0] + if l.Op != OpARMANDshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftRL, types.TypeFlags) v0.AuxInt = c @@ -24382,8 +28894,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftRA x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftRA x y [c]) yes no) for { v := b.Control @@ -24393,14 +28905,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRA { + l := v.Args[0] + if l.Op != OpARMANDshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftRA, types.TypeFlags) v0.AuxInt = c @@ -24410,8 +28925,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftLLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftLLreg x y z) yes no) for { v := b.Control @@ -24421,14 +28936,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftLLreg { + l := v.Args[0] + if l.Op != OpARMANDshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -24438,8 +28956,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftRLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftRLreg x y z) yes no) for { v := b.Control @@ -24449,14 +28967,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRLreg { + l := v.Args[0] + if l.Op != OpARMANDshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -24466,8 +28987,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (ANDshiftRAreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(ANDshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TSTshiftRAreg x y z) yes no) for { v := b.Control @@ -24477,14 +28998,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMANDshiftRAreg { + l := v.Args[0] + if l.Op != OpARMANDshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTSTshiftRAreg, types.TypeFlags) v0.AddArg(x) @@ -24494,8 +29018,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XOR x y)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XOR x y)) yes no) + // cond: l.Uses==1 // result: (NE (TEQ x y) yes no) for { v := b.Control @@ -24505,13 +29029,16 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXOR { + l := v.Args[0] + if l.Op != OpARMXOR { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQ, types.TypeFlags) v0.AddArg(x) @@ -24520,8 +29047,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORconst [c] x)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORconst [c] x)) yes no) + // cond: l.Uses==1 // result: (NE (TEQconst [c] x) yes no) for { v := b.Control @@ -24531,12 +29058,15 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORconst { + l := v.Args[0] + if l.Op != OpARMXORconst { + break + } + c := l.AuxInt + x := l.Args[0] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - x := v_0.Args[0] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQconst, types.TypeFlags) v0.AuxInt = c @@ -24545,8 +29075,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftLL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftLL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftLL x y [c]) yes no) for { v := b.Control @@ -24556,14 +29086,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftLL { + l := v.Args[0] + if l.Op != OpARMXORshiftLL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftLL, types.TypeFlags) v0.AuxInt = c @@ -24573,8 +29106,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftRL x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftRL x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftRL x y [c]) yes no) for { v := b.Control @@ -24584,14 +29117,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRL { + l := v.Args[0] + if l.Op != OpARMXORshiftRL { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftRL, types.TypeFlags) v0.AuxInt = c @@ -24601,8 +29137,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftRA x y [c])) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftRA x y [c])) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftRA x y [c]) yes no) for { v := b.Control @@ -24612,14 +29148,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRA { + l := v.Args[0] + if l.Op != OpARMXORshiftRA { + break + } + c := l.AuxInt + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1) { break } - c := v_0.AuxInt - _ = v_0.Args[1] - x := v_0.Args[0] - y := v_0.Args[1] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftRA, types.TypeFlags) v0.AuxInt = c @@ -24629,8 +29168,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftLLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftLLreg x y z) yes no) for { v := b.Control @@ -24640,14 +29179,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftLLreg { + l := v.Args[0] + if l.Op != OpARMXORshiftLLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftLLreg, types.TypeFlags) v0.AddArg(x) @@ -24657,8 +29199,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftRLreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftRLreg x y z) yes no) for { v := b.Control @@ -24668,14 +29210,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRLreg { + l := v.Args[0] + if l.Op != OpARMXORshiftRLreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftRLreg, types.TypeFlags) v0.AddArg(x) @@ -24685,8 +29230,8 @@ func rewriteBlockARM(b *Block) bool { b.Aux = nil return true } - // match: (NE (CMPconst [0] (XORshiftRAreg x y z)) yes no) - // cond: + // match: (NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) + // cond: l.Uses==1 // result: (NE (TEQshiftRAreg x y z) yes no) for { v := b.Control @@ -24696,14 +29241,17 @@ func rewriteBlockARM(b *Block) bool { if v.AuxInt != 0 { break } - v_0 := v.Args[0] - if v_0.Op != OpARMXORshiftRAreg { + l := v.Args[0] + if l.Op != OpARMXORshiftRAreg { + break + } + _ = l.Args[2] + x := l.Args[0] + y := l.Args[1] + z := l.Args[2] + if !(l.Uses == 1) { break } - _ = v_0.Args[2] - x := v_0.Args[0] - y := v_0.Args[1] - z := v_0.Args[2] b.Kind = BlockARMNE v0 := b.NewValue0(v.Pos, OpARMTEQshiftRAreg, types.TypeFlags) v0.AddArg(x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index d039c731d3..fbdf352998 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -16,7 +16,7 @@ var _ = types.TypeMem // in case not otherwise used func rewriteValueARM64(v *Value) bool { switch v.Op { case OpARM64ADD: - return rewriteValueARM64_OpARM64ADD_0(v) + return rewriteValueARM64_OpARM64ADD_0(v) || rewriteValueARM64_OpARM64ADD_10(v) case OpARM64ADDconst: return rewriteValueARM64_OpARM64ADDconst_0(v) case OpARM64ADDshiftLL: @@ -45,6 +45,8 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpARM64BICshiftRL_0(v) case OpARM64CMN: return rewriteValueARM64_OpARM64CMN_0(v) + case OpARM64CMNW: + return rewriteValueARM64_OpARM64CMNW_0(v) case OpARM64CMNWconst: return rewriteValueARM64_OpARM64CMNWconst_0(v) case OpARM64CMNconst: @@ -89,12 +91,20 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpARM64FMOVDgpfp_0(v) case OpARM64FMOVDload: return rewriteValueARM64_OpARM64FMOVDload_0(v) + case OpARM64FMOVDloadidx: + return rewriteValueARM64_OpARM64FMOVDloadidx_0(v) case OpARM64FMOVDstore: return rewriteValueARM64_OpARM64FMOVDstore_0(v) + case OpARM64FMOVDstoreidx: + return rewriteValueARM64_OpARM64FMOVDstoreidx_0(v) case OpARM64FMOVSload: return rewriteValueARM64_OpARM64FMOVSload_0(v) + case OpARM64FMOVSloadidx: + return rewriteValueARM64_OpARM64FMOVSloadidx_0(v) case OpARM64FMOVSstore: return rewriteValueARM64_OpARM64FMOVSstore_0(v) + case OpARM64FMOVSstoreidx: + return rewriteValueARM64_OpARM64FMOVSstoreidx_0(v) case OpARM64FMULD: return rewriteValueARM64_OpARM64FMULD_0(v) case OpARM64FMULS: @@ -276,7 +286,7 @@ func rewriteValueARM64(v *Value) bool { case OpARM64STP: return rewriteValueARM64_OpARM64STP_0(v) case OpARM64SUB: - return rewriteValueARM64_OpARM64SUB_0(v) + return rewriteValueARM64_OpARM64SUB_0(v) || rewriteValueARM64_OpARM64SUB_10(v) case OpARM64SUBconst: return rewriteValueARM64_OpARM64SUBconst_0(v) case OpARM64SUBshiftLL: @@ -287,6 +297,8 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpARM64SUBshiftRL_0(v) case OpARM64TST: return rewriteValueARM64_OpARM64TST_0(v) + case OpARM64TSTW: + return rewriteValueARM64_OpARM64TSTW_0(v) case OpARM64TSTWconst: return rewriteValueARM64_OpARM64TSTWconst_0(v) case OpARM64TSTconst: @@ -603,6 +615,8 @@ func rewriteValueARM64(v *Value) bool { return rewriteValueARM64_OpLess8U_0(v) case OpLoad: return rewriteValueARM64_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueARM64_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueARM64_OpLsh16x16_0(v) case OpLsh16x32: @@ -895,6 +909,185 @@ func rewriteValueARM64_OpARM64ADD_0(v *Value) bool { v.AddArg(x) return true } + // match: (ADD a l:(MUL x y)) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADD a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MUL { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADD) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD l:(MUL x y) a) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADD a x y) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != OpARM64MUL { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + a := v.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADD) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD a l:(MNEG x y)) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUB a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MNEG { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUB) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD l:(MNEG x y) a) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUB a x y) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != OpARM64MNEG { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + a := v.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUB) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD a l:(MULW x y)) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADDW a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MULW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADDW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD l:(MULW x y) a) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADDW a x y) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != OpARM64MULW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + a := v.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADDW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD a l:(MNEGW x y)) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUBW a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MNEGW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUBW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (ADD l:(MNEGW x y) a) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUBW a x y) + for { + _ = v.Args[1] + l := v.Args[0] + if l.Op != OpARM64MNEGW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + a := v.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUBW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + return false +} +func rewriteValueARM64_OpARM64ADD_10(v *Value) bool { // match: (ADD x (NEG y)) // cond: // result: (SUB x y) @@ -2186,6 +2379,57 @@ func rewriteValueARM64_OpARM64CMN_0(v *Value) bool { v.AddArg(x) return true } + // match: (CMN (MOVDconst [c]) x) + // cond: + // result: (CMNconst [c] x) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + x := v.Args[1] + v.reset(OpARM64CMNconst) + v.AuxInt = c + v.AddArg(x) + return true + } + return false +} +func rewriteValueARM64_OpARM64CMNW_0(v *Value) bool { + // match: (CMNW x (MOVDconst [c])) + // cond: + // result: (CMNWconst [c] x) + for { + _ = v.Args[1] + x := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + v.reset(OpARM64CMNWconst) + v.AuxInt = c + v.AddArg(x) + return true + } + // match: (CMNW (MOVDconst [c]) x) + // cond: + // result: (CMNWconst [c] x) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + x := v.Args[1] + v.reset(OpARM64CMNWconst) + v.AuxInt = c + v.AddArg(x) + return true + } return false } func rewriteValueARM64_OpARM64CMNWconst_0(v *Value) bool { @@ -3769,6 +4013,30 @@ func rewriteValueARM64_OpARM64FMOVDload_0(v *Value) bool { v.AddArg(mem) return true } + // match: (FMOVDload [off] {sym} (ADD ptr idx) mem) + // cond: off == 0 && sym == nil + // result: (FMOVDloadidx ptr idx mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64ADD { + break + } + _ = v_0.Args[1] + ptr := v_0.Args[0] + idx := v_0.Args[1] + mem := v.Args[1] + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVDloadidx) + v.AddArg(ptr) + v.AddArg(idx) + v.AddArg(mem) + return true + } // match: (FMOVDload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) @@ -3796,6 +4064,45 @@ func rewriteValueARM64_OpARM64FMOVDload_0(v *Value) bool { } return false } +func rewriteValueARM64_OpARM64FMOVDloadidx_0(v *Value) bool { + // match: (FMOVDloadidx ptr (MOVDconst [c]) mem) + // cond: + // result: (FMOVDload [c] ptr mem) + for { + _ = v.Args[2] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + mem := v.Args[2] + v.reset(OpARM64FMOVDload) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (FMOVDloadidx (MOVDconst [c]) ptr mem) + // cond: + // result: (FMOVDload [c] ptr mem) + for { + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + ptr := v.Args[1] + mem := v.Args[2] + v.reset(OpARM64FMOVDload) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} func rewriteValueARM64_OpARM64FMOVDstore_0(v *Value) bool { b := v.Block _ = b @@ -3845,6 +4152,32 @@ func rewriteValueARM64_OpARM64FMOVDstore_0(v *Value) bool { v.AddArg(mem) return true } + // match: (FMOVDstore [off] {sym} (ADD ptr idx) val mem) + // cond: off == 0 && sym == nil + // result: (FMOVDstoreidx ptr idx val mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpARM64ADD { + break + } + _ = v_0.Args[1] + ptr := v_0.Args[0] + idx := v_0.Args[1] + val := v.Args[1] + mem := v.Args[2] + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVDstoreidx) + v.AddArg(ptr) + v.AddArg(idx) + v.AddArg(val) + v.AddArg(mem) + return true + } // match: (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) @@ -3874,6 +4207,49 @@ func rewriteValueARM64_OpARM64FMOVDstore_0(v *Value) bool { } return false } +func rewriteValueARM64_OpARM64FMOVDstoreidx_0(v *Value) bool { + // match: (FMOVDstoreidx ptr (MOVDconst [c]) val mem) + // cond: + // result: (FMOVDstore [c] ptr val mem) + for { + _ = v.Args[3] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + val := v.Args[2] + mem := v.Args[3] + v.reset(OpARM64FMOVDstore) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (FMOVDstoreidx (MOVDconst [c]) idx val mem) + // cond: + // result: (FMOVDstore [c] idx val mem) + for { + _ = v.Args[3] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + idx := v.Args[1] + val := v.Args[2] + mem := v.Args[3] + v.reset(OpARM64FMOVDstore) + v.AuxInt = c + v.AddArg(idx) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueARM64_OpARM64FMOVSload_0(v *Value) bool { b := v.Block _ = b @@ -3903,6 +4279,30 @@ func rewriteValueARM64_OpARM64FMOVSload_0(v *Value) bool { v.AddArg(mem) return true } + // match: (FMOVSload [off] {sym} (ADD ptr idx) mem) + // cond: off == 0 && sym == nil + // result: (FMOVSloadidx ptr idx mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64ADD { + break + } + _ = v_0.Args[1] + ptr := v_0.Args[0] + idx := v_0.Args[1] + mem := v.Args[1] + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVSloadidx) + v.AddArg(ptr) + v.AddArg(idx) + v.AddArg(mem) + return true + } // match: (FMOVSload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) @@ -3930,6 +4330,45 @@ func rewriteValueARM64_OpARM64FMOVSload_0(v *Value) bool { } return false } +func rewriteValueARM64_OpARM64FMOVSloadidx_0(v *Value) bool { + // match: (FMOVSloadidx ptr (MOVDconst [c]) mem) + // cond: + // result: (FMOVSload [c] ptr mem) + for { + _ = v.Args[2] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + mem := v.Args[2] + v.reset(OpARM64FMOVSload) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(mem) + return true + } + // match: (FMOVSloadidx (MOVDconst [c]) ptr mem) + // cond: + // result: (FMOVSload [c] ptr mem) + for { + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + ptr := v.Args[1] + mem := v.Args[2] + v.reset(OpARM64FMOVSload) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(mem) + return true + } + return false +} func rewriteValueARM64_OpARM64FMOVSstore_0(v *Value) bool { b := v.Block _ = b @@ -3961,6 +4400,32 @@ func rewriteValueARM64_OpARM64FMOVSstore_0(v *Value) bool { v.AddArg(mem) return true } + // match: (FMOVSstore [off] {sym} (ADD ptr idx) val mem) + // cond: off == 0 && sym == nil + // result: (FMOVSstoreidx ptr idx val mem) + for { + off := v.AuxInt + sym := v.Aux + _ = v.Args[2] + v_0 := v.Args[0] + if v_0.Op != OpARM64ADD { + break + } + _ = v_0.Args[1] + ptr := v_0.Args[0] + idx := v_0.Args[1] + val := v.Args[1] + mem := v.Args[2] + if !(off == 0 && sym == nil) { + break + } + v.reset(OpARM64FMOVSstoreidx) + v.AddArg(ptr) + v.AddArg(idx) + v.AddArg(val) + v.AddArg(mem) + return true + } // match: (FMOVSstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) // cond: canMergeSym(sym1,sym2) && is32Bit(off1+off2) && (ptr.Op != OpSB || !config.ctxt.Flag_shared) // result: (FMOVSstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) @@ -3990,6 +4455,49 @@ func rewriteValueARM64_OpARM64FMOVSstore_0(v *Value) bool { } return false } +func rewriteValueARM64_OpARM64FMOVSstoreidx_0(v *Value) bool { + // match: (FMOVSstoreidx ptr (MOVDconst [c]) val mem) + // cond: + // result: (FMOVSstore [c] ptr val mem) + for { + _ = v.Args[3] + ptr := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + val := v.Args[2] + mem := v.Args[3] + v.reset(OpARM64FMOVSstore) + v.AuxInt = c + v.AddArg(ptr) + v.AddArg(val) + v.AddArg(mem) + return true + } + // match: (FMOVSstoreidx (MOVDconst [c]) idx val mem) + // cond: + // result: (FMOVSstore [c] idx val mem) + for { + _ = v.Args[3] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + idx := v.Args[1] + val := v.Args[2] + mem := v.Args[3] + v.reset(OpARM64FMOVSstore) + v.AuxInt = c + v.AddArg(idx) + v.AddArg(val) + v.AddArg(mem) + return true + } + return false +} func rewriteValueARM64_OpARM64FMULD_0(v *Value) bool { // match: (FMULD (FNEGD x) y) // cond: @@ -24350,6 +24858,94 @@ func rewriteValueARM64_OpARM64SUB_0(v *Value) bool { v.AddArg(x) return true } + // match: (SUB a l:(MUL x y)) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUB a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MUL { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUB) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (SUB a l:(MNEG x y)) + // cond: l.Uses==1 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADD a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MNEG { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADD) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (SUB a l:(MULW x y)) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MSUBW a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MULW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MSUBW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } + // match: (SUB a l:(MNEGW x y)) + // cond: l.Uses==1 && a.Type.Size() != 8 && x.Op!=OpARM64MOVDconst && y.Op!=OpARM64MOVDconst && a.Op!=OpARM64MOVDconst && clobber(l) + // result: (MADDW a x y) + for { + _ = v.Args[1] + a := v.Args[0] + l := v.Args[1] + if l.Op != OpARM64MNEGW { + break + } + _ = l.Args[1] + x := l.Args[0] + y := l.Args[1] + if !(l.Uses == 1 && a.Type.Size() != 8 && x.Op != OpARM64MOVDconst && y.Op != OpARM64MOVDconst && a.Op != OpARM64MOVDconst && clobber(l)) { + break + } + v.reset(OpARM64MADDW) + v.AddArg(a) + v.AddArg(x) + v.AddArg(y) + return true + } // match: (SUB x x) // cond: // result: (MOVDconst [0]) @@ -24447,6 +25043,9 @@ func rewriteValueARM64_OpARM64SUB_0(v *Value) bool { v.AddArg(y) return true } + return false +} +func rewriteValueARM64_OpARM64SUB_10(v *Value) bool { // match: (SUB x0 x1:(SRAconst [c] y)) // cond: clobberIfDead(x1) // result: (SUBshiftRA x0 y [c]) @@ -24675,6 +25274,57 @@ func rewriteValueARM64_OpARM64TST_0(v *Value) bool { v.AddArg(x) return true } + // match: (TST (MOVDconst [c]) x) + // cond: + // result: (TSTconst [c] x) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + x := v.Args[1] + v.reset(OpARM64TSTconst) + v.AuxInt = c + v.AddArg(x) + return true + } + return false +} +func rewriteValueARM64_OpARM64TSTW_0(v *Value) bool { + // match: (TSTW x (MOVDconst [c])) + // cond: + // result: (TSTWconst [c] x) + for { + _ = v.Args[1] + x := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpARM64MOVDconst { + break + } + c := v_1.AuxInt + v.reset(OpARM64TSTWconst) + v.AuxInt = c + v.AddArg(x) + return true + } + // match: (TSTW (MOVDconst [c]) x) + // cond: + // result: (TSTWconst [c] x) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpARM64MOVDconst { + break + } + c := v_0.AuxInt + x := v.Args[1] + v.reset(OpARM64TSTWconst) + v.AuxInt = c + v.AddArg(x) + return true + } return false } func rewriteValueARM64_OpARM64TSTWconst_0(v *Value) bool { @@ -28229,6 +28879,20 @@ func rewriteValueARM64_OpLoad_0(v *Value) bool { } return false } +func rewriteValueARM64_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVDaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpARM64MOVDaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueARM64_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b @@ -32176,7 +32840,7 @@ func rewriteBlockARM64(b *Block) bool { } // match: (EQ (CMPWconst [0] z:(AND x y)) yes no) // cond: z.Uses == 1 - // result: (EQ (TST x y) yes no) + // result: (EQ (TSTW x y) yes no) for { v := b.Control if v.Op != OpARM64CMPWconst { @@ -32196,7 +32860,7 @@ func rewriteBlockARM64(b *Block) bool { break } b.Kind = BlockARM64EQ - v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) v0.AddArg(x) v0.AddArg(y) b.SetControl(v0) @@ -32231,6 +32895,62 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (EQ (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (EQ (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (EQ (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (EQ (CMPconst [0] z:(ADD x y)) yes no) // cond: z.Uses == 1 // result: (EQ (CMN x y) yes no) @@ -32260,6 +32980,35 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (EQ (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (EQ (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (EQ (CMP x z:(NEG y)) yes no) // cond: z.Uses == 1 // result: (EQ (CMN x y) yes no) @@ -32286,6 +33035,32 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (EQ (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (EQ (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (EQ (CMPconst [0] x) yes no) // cond: // result: (Z x yes no) @@ -32320,6 +33095,138 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (EQ (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (EQ (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (EQ (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (EQ (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (EQ (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (EQ (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64EQ + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (EQ (TSTconst [c] x) yes no) // cond: oneBit(c) // result: (TBZ {ntz(c)} x yes no) @@ -32468,6 +33375,64 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (GE (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (TSTW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (GE (CMPconst [0] x:(ANDconst [c] y)) yes no) // cond: x.Uses == 1 // result: (GE (TSTconst [c] y) yes no) @@ -32496,6 +33461,304 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (GE (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (GE (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (GE (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (GE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMP x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (GE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMP { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (GE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (GE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (GE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (GE (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GE (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (GE (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GE + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (GE (CMPWconst [0] x) yes no) // cond: // result: (TBZ {int64(31)} x yes no) @@ -32640,6 +33903,64 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (GT (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (TSTW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (GT (CMPconst [0] x:(ANDconst [c] y)) yes no) // cond: x.Uses == 1 // result: (GT (TSTconst [c] y) yes no) @@ -32668,6 +33989,304 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (GT (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (GT (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (GT (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (GT (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMP x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (GT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMP { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (GT (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (GT (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (GT (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (GT (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (GT (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (GT (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64GT + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (GT (FlagEQ) yes no) // cond: // result: (First nil no yes) @@ -32932,6 +34551,64 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (LE (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (TSTW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (LE (CMPconst [0] x:(ANDconst [c] y)) yes no) // cond: x.Uses == 1 // result: (LE (TSTconst [c] y) yes no) @@ -32960,6 +34637,304 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (LE (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (LE (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (LE (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (LE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMP x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (LE (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMP { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (LE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (LE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (LE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (LE (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LE (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (LE (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LE + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (LE (FlagEQ) yes no) // cond: // result: (First nil yes no) @@ -33070,6 +35045,64 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (LT (CMPconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (TST x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] z:(AND x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (TSTW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64AND { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (LT (CMPconst [0] x:(ANDconst [c] y)) yes no) // cond: x.Uses == 1 // result: (LT (TSTconst [c] y) yes no) @@ -33098,6 +35131,304 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (LT (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (LT (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (LT (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (LT (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMP x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (LT (CMN x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMP { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (LT (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (LT (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (LT (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (LT (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (LT (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (LT (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64LT + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (LT (CMPWconst [0] x) yes no) // cond: // result: (TBNZ {int64(31)} x yes no) @@ -33274,7 +35605,7 @@ func rewriteBlockARM64(b *Block) bool { } // match: (NE (CMPWconst [0] z:(AND x y)) yes no) // cond: z.Uses == 1 - // result: (NE (TST x y) yes no) + // result: (NE (TSTW x y) yes no) for { v := b.Control if v.Op != OpARM64CMPWconst { @@ -33294,7 +35625,7 @@ func rewriteBlockARM64(b *Block) bool { break } b.Kind = BlockARM64NE - v0 := b.NewValue0(v.Pos, OpARM64TST, types.TypeFlags) + v0 := b.NewValue0(v.Pos, OpARM64TSTW, types.TypeFlags) v0.AddArg(x) v0.AddArg(y) b.SetControl(v0) @@ -33329,6 +35660,62 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (NE (CMPconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (NE (CMNconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMNconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPWconst [0] x:(ADDconst [c] y)) yes no) + // cond: x.Uses == 1 + // result: (NE (CMNWconst [c] y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + x := v.Args[0] + if x.Op != OpARM64ADDconst { + break + } + c := x.AuxInt + y := x.Args[0] + if !(x.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMNWconst, types.TypeFlags) + v0.AuxInt = c + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (NE (CMPconst [0] z:(ADD x y)) yes no) // cond: z.Uses == 1 // result: (NE (CMN x y) yes no) @@ -33358,6 +35745,35 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (NE (CMPWconst [0] z:(ADD x y)) yes no) + // cond: z.Uses == 1 + // result: (NE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64ADD { + break + } + _ = z.Args[1] + x := z.Args[0] + y := z.Args[1] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (NE (CMP x z:(NEG y)) yes no) // cond: z.Uses == 1 // result: (NE (CMN x y) yes no) @@ -33384,6 +35800,32 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (NE (CMPW x z:(NEG y)) yes no) + // cond: z.Uses == 1 + // result: (NE (CMNW x y) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPW { + break + } + _ = v.Args[1] + x := v.Args[0] + z := v.Args[1] + if z.Op != OpARM64NEG { + break + } + y := z.Args[0] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(x) + v0.AddArg(y) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (NE (CMPconst [0] x) yes no) // cond: // result: (NZ x yes no) @@ -33418,6 +35860,138 @@ func rewriteBlockARM64(b *Block) bool { b.Aux = nil return true } + // match: (NE (CMPconst [0] z:(MADD a x y)) yes no) + // cond: z.Uses==1 + // result: (NE (CMN a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADD { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMN, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPconst [0] z:(MSUB a x y)) yes no) + // cond: z.Uses==1 + // result: (NE (CMP a (MUL x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUB { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMP, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MUL, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPWconst [0] z:(MADDW a x y)) yes no) + // cond: z.Uses==1 + // result: (NE (CMNW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MADDW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMNW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } + // match: (NE (CMPWconst [0] z:(MSUBW a x y)) yes no) + // cond: z.Uses==1 + // result: (NE (CMPW a (MULW x y)) yes no) + for { + v := b.Control + if v.Op != OpARM64CMPWconst { + break + } + if v.AuxInt != 0 { + break + } + z := v.Args[0] + if z.Op != OpARM64MSUBW { + break + } + _ = z.Args[2] + a := z.Args[0] + x := z.Args[1] + y := z.Args[2] + if !(z.Uses == 1) { + break + } + b.Kind = BlockARM64NE + v0 := b.NewValue0(v.Pos, OpARM64CMPW, types.TypeFlags) + v0.AddArg(a) + v1 := b.NewValue0(v.Pos, OpARM64MULW, x.Type) + v1.AddArg(x) + v1.AddArg(y) + v0.AddArg(v1) + b.SetControl(v0) + b.Aux = nil + return true + } // match: (NE (TSTconst [c] x) yes no) // cond: oneBit(c) // result: (TBNZ {ntz(c)} x yes no) diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS.go b/src/cmd/compile/internal/ssa/rewriteMIPS.go index c101e91636..231949644e 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS.go @@ -213,6 +213,8 @@ func rewriteValueMIPS(v *Value) bool { return rewriteValueMIPS_OpLess8U_0(v) case OpLoad: return rewriteValueMIPS_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueMIPS_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueMIPS_OpLsh16x16_0(v) case OpLsh16x32: @@ -2511,6 +2513,20 @@ func rewriteValueMIPS_OpLoad_0(v *Value) bool { } return false } +func rewriteValueMIPS_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVWaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpMIPSMOVWaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueMIPS_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/rewriteMIPS64.go b/src/cmd/compile/internal/ssa/rewriteMIPS64.go index 084463a10f..9cd0050e26 100644 --- a/src/cmd/compile/internal/ssa/rewriteMIPS64.go +++ b/src/cmd/compile/internal/ssa/rewriteMIPS64.go @@ -253,6 +253,8 @@ func rewriteValueMIPS64(v *Value) bool { return rewriteValueMIPS64_OpLess8U_0(v) case OpLoad: return rewriteValueMIPS64_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueMIPS64_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueMIPS64_OpLsh16x16_0(v) case OpLsh16x32: @@ -2924,6 +2926,20 @@ func rewriteValueMIPS64_OpLoad_0(v *Value) bool { } return false } +func rewriteValueMIPS64_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVVaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpMIPS64MOVVaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueMIPS64_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 8dc3d008b0..ba6a862989 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -275,6 +275,8 @@ func rewriteValuePPC64(v *Value) bool { return rewriteValuePPC64_OpLess8U_0(v) case OpLoad: return rewriteValuePPC64_OpLoad_0(v) + case OpLocalAddr: + return rewriteValuePPC64_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValuePPC64_OpLsh16x16_0(v) case OpLsh16x32: @@ -3048,6 +3050,20 @@ func rewriteValuePPC64_OpLoad_0(v *Value) bool { } return false } +func rewriteValuePPC64_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVDaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpPPC64MOVDaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValuePPC64_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/rewriteS390X.go b/src/cmd/compile/internal/ssa/rewriteS390X.go index d5d392b94a..95c9a0d0fc 100644 --- a/src/cmd/compile/internal/ssa/rewriteS390X.go +++ b/src/cmd/compile/internal/ssa/rewriteS390X.go @@ -275,6 +275,8 @@ func rewriteValueS390X(v *Value) bool { return rewriteValueS390X_OpLess8U_0(v) case OpLoad: return rewriteValueS390X_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueS390X_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueS390X_OpLsh16x16_0(v) case OpLsh16x32: @@ -381,6 +383,18 @@ func rewriteValueS390X(v *Value) bool { return rewriteValueS390X_OpOr8_0(v) case OpOrB: return rewriteValueS390X_OpOrB_0(v) + case OpPopCount16: + return rewriteValueS390X_OpPopCount16_0(v) + case OpPopCount32: + return rewriteValueS390X_OpPopCount32_0(v) + case OpPopCount64: + return rewriteValueS390X_OpPopCount64_0(v) + case OpPopCount8: + return rewriteValueS390X_OpPopCount8_0(v) + case OpRotateLeft32: + return rewriteValueS390X_OpRotateLeft32_0(v) + case OpRotateLeft64: + return rewriteValueS390X_OpRotateLeft64_0(v) case OpRound: return rewriteValueS390X_OpRound_0(v) case OpRound32F: @@ -655,6 +669,10 @@ func rewriteValueS390X(v *Value) bool { return rewriteValueS390X_OpS390XORconst_0(v) case OpS390XORload: return rewriteValueS390X_OpS390XORload_0(v) + case OpS390XRLL: + return rewriteValueS390X_OpS390XRLL_0(v) + case OpS390XRLLG: + return rewriteValueS390X_OpS390XRLLG_0(v) case OpS390XSLD: return rewriteValueS390X_OpS390XSLD_0(v) || rewriteValueS390X_OpS390XSLD_10(v) case OpS390XSLW: @@ -689,6 +707,12 @@ func rewriteValueS390X(v *Value) bool { return rewriteValueS390X_OpS390XSUBconst_0(v) case OpS390XSUBload: return rewriteValueS390X_OpS390XSUBload_0(v) + case OpS390XSumBytes2: + return rewriteValueS390X_OpS390XSumBytes2_0(v) + case OpS390XSumBytes4: + return rewriteValueS390X_OpS390XSumBytes4_0(v) + case OpS390XSumBytes8: + return rewriteValueS390X_OpS390XSumBytes8_0(v) case OpS390XXOR: return rewriteValueS390X_OpS390XXOR_0(v) || rewriteValueS390X_OpS390XXOR_10(v) case OpS390XXORW: @@ -3477,6 +3501,20 @@ func rewriteValueS390X_OpLoad_0(v *Value) bool { } return false } +func rewriteValueS390X_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (MOVDaddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpS390XMOVDaddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueS390X_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b @@ -5295,6 +5333,108 @@ func rewriteValueS390X_OpOrB_0(v *Value) bool { return true } } +func rewriteValueS390X_OpPopCount16_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (PopCount16 x) + // cond: + // result: (MOVBZreg (SumBytes2 (POPCNT x))) + for { + x := v.Args[0] + v.reset(OpS390XMOVBZreg) + v0 := b.NewValue0(v.Pos, OpS390XSumBytes2, typ.UInt8) + v1 := b.NewValue0(v.Pos, OpS390XPOPCNT, typ.UInt16) + v1.AddArg(x) + v0.AddArg(v1) + v.AddArg(v0) + return true + } +} +func rewriteValueS390X_OpPopCount32_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (PopCount32 x) + // cond: + // result: (MOVBZreg (SumBytes4 (POPCNT x))) + for { + x := v.Args[0] + v.reset(OpS390XMOVBZreg) + v0 := b.NewValue0(v.Pos, OpS390XSumBytes4, typ.UInt8) + v1 := b.NewValue0(v.Pos, OpS390XPOPCNT, typ.UInt32) + v1.AddArg(x) + v0.AddArg(v1) + v.AddArg(v0) + return true + } +} +func rewriteValueS390X_OpPopCount64_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (PopCount64 x) + // cond: + // result: (MOVBZreg (SumBytes8 (POPCNT x))) + for { + x := v.Args[0] + v.reset(OpS390XMOVBZreg) + v0 := b.NewValue0(v.Pos, OpS390XSumBytes8, typ.UInt8) + v1 := b.NewValue0(v.Pos, OpS390XPOPCNT, typ.UInt64) + v1.AddArg(x) + v0.AddArg(v1) + v.AddArg(v0) + return true + } +} +func rewriteValueS390X_OpPopCount8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (PopCount8 x) + // cond: + // result: (POPCNT (MOVBZreg x)) + for { + x := v.Args[0] + v.reset(OpS390XPOPCNT) + v0 := b.NewValue0(v.Pos, OpS390XMOVBZreg, typ.UInt64) + v0.AddArg(x) + v.AddArg(v0) + return true + } +} +func rewriteValueS390X_OpRotateLeft32_0(v *Value) bool { + // match: (RotateLeft32 x y) + // cond: + // result: (RLL x y) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + v.reset(OpS390XRLL) + v.AddArg(x) + v.AddArg(y) + return true + } +} +func rewriteValueS390X_OpRotateLeft64_0(v *Value) bool { + // match: (RotateLeft64 x y) + // cond: + // result: (RLLG x y) + for { + _ = v.Args[1] + x := v.Args[0] + y := v.Args[1] + v.reset(OpS390XRLLG) + v.AddArg(x) + v.AddArg(y) + return true + } +} func rewriteValueS390X_OpRound_0(v *Value) bool { // match: (Round x) // cond: @@ -38540,6 +38680,44 @@ func rewriteValueS390X_OpS390XORload_0(v *Value) bool { } return false } +func rewriteValueS390X_OpS390XRLL_0(v *Value) bool { + // match: (RLL x (MOVDconst [c])) + // cond: + // result: (RLLconst x [c&31]) + for { + _ = v.Args[1] + x := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpS390XMOVDconst { + break + } + c := v_1.AuxInt + v.reset(OpS390XRLLconst) + v.AuxInt = c & 31 + v.AddArg(x) + return true + } + return false +} +func rewriteValueS390X_OpS390XRLLG_0(v *Value) bool { + // match: (RLLG x (MOVDconst [c])) + // cond: + // result: (RLLGconst x [c&63]) + for { + _ = v.Args[1] + x := v.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpS390XMOVDconst { + break + } + c := v_1.AuxInt + v.reset(OpS390XRLLGconst) + v.AuxInt = c & 63 + v.AddArg(x) + return true + } + return false +} func rewriteValueS390X_OpS390XSLD_0(v *Value) bool { b := v.Block _ = b @@ -40401,6 +40579,67 @@ func rewriteValueS390X_OpS390XSUBload_0(v *Value) bool { } return false } +func rewriteValueS390X_OpS390XSumBytes2_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (SumBytes2 x) + // cond: + // result: (ADDW (SRWconst x [8]) x) + for { + x := v.Args[0] + v.reset(OpS390XADDW) + v0 := b.NewValue0(v.Pos, OpS390XSRWconst, typ.UInt8) + v0.AuxInt = 8 + v0.AddArg(x) + v.AddArg(v0) + v.AddArg(x) + return true + } +} +func rewriteValueS390X_OpS390XSumBytes4_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (SumBytes4 x) + // cond: + // result: (SumBytes2 (ADDW (SRWconst x [16]) x)) + for { + x := v.Args[0] + v.reset(OpS390XSumBytes2) + v0 := b.NewValue0(v.Pos, OpS390XADDW, typ.UInt16) + v1 := b.NewValue0(v.Pos, OpS390XSRWconst, typ.UInt16) + v1.AuxInt = 16 + v1.AddArg(x) + v0.AddArg(v1) + v0.AddArg(x) + v.AddArg(v0) + return true + } +} +func rewriteValueS390X_OpS390XSumBytes8_0(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ + // match: (SumBytes8 x) + // cond: + // result: (SumBytes4 (ADDW (SRDconst x [32]) x)) + for { + x := v.Args[0] + v.reset(OpS390XSumBytes4) + v0 := b.NewValue0(v.Pos, OpS390XADDW, typ.UInt32) + v1 := b.NewValue0(v.Pos, OpS390XSRDconst, typ.UInt32) + v1.AuxInt = 32 + v1.AddArg(x) + v0.AddArg(v1) + v0.AddArg(x) + v.AddArg(v0) + return true + } +} func rewriteValueS390X_OpS390XXOR_0(v *Value) bool { // match: (XOR x (MOVDconst [c])) // cond: isU32Bit(c) diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go index 26dd254952..c07651ef0e 100644 --- a/src/cmd/compile/internal/ssa/rewriteWasm.go +++ b/src/cmd/compile/internal/ssa/rewriteWasm.go @@ -237,6 +237,8 @@ func rewriteValueWasm(v *Value) bool { return rewriteValueWasm_OpLess8U_0(v) case OpLoad: return rewriteValueWasm_OpLoad_0(v) + case OpLocalAddr: + return rewriteValueWasm_OpLocalAddr_0(v) case OpLsh16x16: return rewriteValueWasm_OpLsh16x16_0(v) case OpLsh16x32: @@ -2496,6 +2498,20 @@ func rewriteValueWasm_OpLoad_0(v *Value) bool { } return false } +func rewriteValueWasm_OpLocalAddr_0(v *Value) bool { + // match: (LocalAddr {sym} base _) + // cond: + // result: (LoweredAddr {sym} base) + for { + sym := v.Aux + _ = v.Args[1] + base := v.Args[0] + v.reset(OpWasmLoweredAddr) + v.Aux = sym + v.AddArg(base) + return true + } +} func rewriteValueWasm_OpLsh16x16_0(v *Value) bool { b := v.Block _ = b diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 357be76937..81bebede46 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -114,7 +114,7 @@ func rewriteValuegeneric(v *Value) bool { case OpEqInter: return rewriteValuegeneric_OpEqInter_0(v) case OpEqPtr: - return rewriteValuegeneric_OpEqPtr_0(v) || rewriteValuegeneric_OpEqPtr_10(v) + return rewriteValuegeneric_OpEqPtr_0(v) || rewriteValuegeneric_OpEqPtr_10(v) || rewriteValuegeneric_OpEqPtr_20(v) case OpEqSlice: return rewriteValuegeneric_OpEqSlice_0(v) case OpGeq16: @@ -300,7 +300,7 @@ func rewriteValuegeneric(v *Value) bool { case OpNeqInter: return rewriteValuegeneric_OpNeqInter_0(v) case OpNeqPtr: - return rewriteValuegeneric_OpNeqPtr_0(v) || rewriteValuegeneric_OpNeqPtr_10(v) + return rewriteValuegeneric_OpNeqPtr_0(v) || rewriteValuegeneric_OpNeqPtr_10(v) || rewriteValuegeneric_OpNeqPtr_20(v) case OpNeqSlice: return rewriteValuegeneric_OpNeqSlice_0(v) case OpNilCheck: @@ -10542,6 +10542,48 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool { v.AuxInt = b2i(a == b) return true } + // match: (EqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) + // cond: + // result: (ConstBool [b2i(a == b)]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + a := v_0.Aux + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + b := v_1.Aux + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = b2i(a == b) + return true + } + // match: (EqPtr (LocalAddr {b} _ _) (LocalAddr {a} _ _)) + // cond: + // result: (ConstBool [b2i(a == b)]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + b := v_0.Aux + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + a := v_1.Aux + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = b2i(a == b) + return true + } // match: (EqPtr (OffPtr [o1] p1) p2) // cond: isSamePtr(p1, p2) // result: (ConstBool [b2i(o1 == 0)]) @@ -10647,6 +10689,13 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool { v.AuxInt = b2i(c == d) return true } + return false +} +func rewriteValuegeneric_OpEqPtr_10(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (EqPtr (Const32 [d]) (Const32 [c])) // cond: // result: (ConstBool [b2i(c == d)]) @@ -10685,13 +10734,6 @@ func rewriteValuegeneric_OpEqPtr_0(v *Value) bool { v.AuxInt = b2i(c == d) return true } - return false -} -func rewriteValuegeneric_OpEqPtr_10(v *Value) bool { - b := v.Block - _ = b - typ := &b.Func.Config.Types - _ = typ // match: (EqPtr (Const64 [d]) (Const64 [c])) // cond: // result: (ConstBool [b2i(c == d)]) @@ -10711,6 +10753,78 @@ func rewriteValuegeneric_OpEqPtr_10(v *Value) bool { v.AuxInt = b2i(c == d) return true } + // match: (EqPtr (LocalAddr _ _) (Addr _)) + // cond: + // result: (ConstBool [0]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpAddr { + break + } + v.reset(OpConstBool) + v.AuxInt = 0 + return true + } + // match: (EqPtr (Addr _) (LocalAddr _ _)) + // cond: + // result: (ConstBool [0]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAddr { + break + } + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = 0 + return true + } + // match: (EqPtr (Addr _) (LocalAddr _ _)) + // cond: + // result: (ConstBool [0]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAddr { + break + } + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = 0 + return true + } + // match: (EqPtr (LocalAddr _ _) (Addr _)) + // cond: + // result: (ConstBool [0]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpAddr { + break + } + v.reset(OpConstBool) + v.AuxInt = 0 + return true + } // match: (EqPtr (AddPtr p1 o1) p2) // cond: isSamePtr(p1, p2) // result: (Not (IsNonNil o1)) @@ -10774,6 +10888,13 @@ func rewriteValuegeneric_OpEqPtr_10(v *Value) bool { v.AddArg(v0) return true } + return false +} +func rewriteValuegeneric_OpEqPtr_20(v *Value) bool { + b := v.Block + _ = b + typ := &b.Func.Config.Types + _ = typ // match: (EqPtr p (Const32 [0])) // cond: // result: (Not (IsNonNil p)) @@ -12525,6 +12646,19 @@ func rewriteValuegeneric_OpIsNonNil_0(v *Value) bool { v.AuxInt = 1 return true } + // match: (IsNonNil (LocalAddr _ _)) + // cond: + // result: (ConstBool [1]) + for { + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + _ = v_0.Args[1] + v.reset(OpConstBool) + v.AuxInt = 1 + return true + } return false } func rewriteValuegeneric_OpIsSliceInBounds_0(v *Value) bool { @@ -13349,7 +13483,7 @@ func rewriteValuegeneric_OpLoad_0(v *Value) bool { } // match: (Load p1 (Store {t2} p2 (Const32 [x]) _)) // cond: isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitFloat(t1) - // result: (Const32F [f2i(float64(math.Float32frombits(uint32(x))))]) + // result: (Const32F [f2i(extend32Fto64F(math.Float32frombits(uint32(x))))]) for { t1 := v.Type _ = v.Args[1] @@ -13370,7 +13504,7 @@ func rewriteValuegeneric_OpLoad_0(v *Value) bool { break } v.reset(OpConst32F) - v.AuxInt = f2i(float64(math.Float32frombits(uint32(x)))) + v.AuxInt = f2i(extend32Fto64F(math.Float32frombits(uint32(x)))) return true } // match: (Load p1 (Store {t2} p2 (Const64F [x]) _)) @@ -13401,7 +13535,7 @@ func rewriteValuegeneric_OpLoad_0(v *Value) bool { } // match: (Load p1 (Store {t2} p2 (Const32F [x]) _)) // cond: isSamePtr(p1,p2) && sizeof(t2) == 4 && is32BitInt(t1) - // result: (Const32 [int64(int32(math.Float32bits(float32(i2f(x)))))]) + // result: (Const32 [int64(int32(math.Float32bits(truncate64Fto32F(i2f(x)))))]) for { t1 := v.Type _ = v.Args[1] @@ -13422,7 +13556,7 @@ func rewriteValuegeneric_OpLoad_0(v *Value) bool { break } v.reset(OpConst32) - v.AuxInt = int64(int32(math.Float32bits(float32(i2f(x))))) + v.AuxInt = int64(int32(math.Float32bits(truncate64Fto32F(i2f(x))))) return true } // match: (Load op:(OffPtr [o1] p1) (Store {t2} p2 _ mem:(Zero [n] p3 _))) @@ -20810,6 +20944,48 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool { v.AuxInt = b2i(a != b) return true } + // match: (NeqPtr (LocalAddr {a} _ _) (LocalAddr {b} _ _)) + // cond: + // result: (ConstBool [b2i(a != b)]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + a := v_0.Aux + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + b := v_1.Aux + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = b2i(a != b) + return true + } + // match: (NeqPtr (LocalAddr {b} _ _) (LocalAddr {a} _ _)) + // cond: + // result: (ConstBool [b2i(a != b)]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + b := v_0.Aux + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + a := v_1.Aux + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = b2i(a != b) + return true + } // match: (NeqPtr (OffPtr [o1] p1) p2) // cond: isSamePtr(p1, p2) // result: (ConstBool [b2i(o1 != 0)]) @@ -20915,6 +21091,9 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool { v.AuxInt = b2i(c != d) return true } + return false +} +func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool { // match: (NeqPtr (Const32 [d]) (Const32 [c])) // cond: // result: (ConstBool [b2i(c != d)]) @@ -20953,9 +21132,6 @@ func rewriteValuegeneric_OpNeqPtr_0(v *Value) bool { v.AuxInt = b2i(c != d) return true } - return false -} -func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool { // match: (NeqPtr (Const64 [d]) (Const64 [c])) // cond: // result: (ConstBool [b2i(c != d)]) @@ -20975,6 +21151,78 @@ func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool { v.AuxInt = b2i(c != d) return true } + // match: (NeqPtr (LocalAddr _ _) (Addr _)) + // cond: + // result: (ConstBool [1]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpAddr { + break + } + v.reset(OpConstBool) + v.AuxInt = 1 + return true + } + // match: (NeqPtr (Addr _) (LocalAddr _ _)) + // cond: + // result: (ConstBool [1]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAddr { + break + } + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = 1 + return true + } + // match: (NeqPtr (Addr _) (LocalAddr _ _)) + // cond: + // result: (ConstBool [1]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpAddr { + break + } + v_1 := v.Args[1] + if v_1.Op != OpLocalAddr { + break + } + _ = v_1.Args[1] + v.reset(OpConstBool) + v.AuxInt = 1 + return true + } + // match: (NeqPtr (LocalAddr _ _) (Addr _)) + // cond: + // result: (ConstBool [1]) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpLocalAddr { + break + } + _ = v_0.Args[1] + v_1 := v.Args[1] + if v_1.Op != OpAddr { + break + } + v.reset(OpConstBool) + v.AuxInt = 1 + return true + } // match: (NeqPtr (AddPtr p1 o1) p2) // cond: isSamePtr(p1, p2) // result: (IsNonNil o1) @@ -21032,6 +21280,9 @@ func rewriteValuegeneric_OpNeqPtr_10(v *Value) bool { v.AddArg(p) return true } + return false +} +func rewriteValuegeneric_OpNeqPtr_20(v *Value) bool { // match: (NeqPtr p (Const32 [0])) // cond: // result: (IsNonNil p) @@ -24654,6 +24905,32 @@ func rewriteValuegeneric_OpRsh16Ux64_0(v *Value) bool { v.AddArg(v0) return true } + // match: (Rsh16Ux64 (Rsh16x64 x _) (Const64 [15])) + // cond: + // result: (Rsh16Ux64 x (Const64 [15])) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpRsh16x64 { + break + } + _ = v_0.Args[1] + x := v_0.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if v_1.AuxInt != 15 { + break + } + v.reset(OpRsh16Ux64) + v.AddArg(x) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = 15 + v.AddArg(v0) + return true + } // match: (Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Rsh16Ux64 x (Const64 [c1-c2+c3])) @@ -25198,6 +25475,32 @@ func rewriteValuegeneric_OpRsh32Ux64_0(v *Value) bool { v.AddArg(v0) return true } + // match: (Rsh32Ux64 (Rsh32x64 x _) (Const64 [31])) + // cond: + // result: (Rsh32Ux64 x (Const64 [31])) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpRsh32x64 { + break + } + _ = v_0.Args[1] + x := v_0.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if v_1.AuxInt != 31 { + break + } + v.reset(OpRsh32Ux64) + v.AddArg(x) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = 31 + v.AddArg(v0) + return true + } // match: (Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Rsh32Ux64 x (Const64 [c1-c2+c3])) @@ -25804,6 +26107,32 @@ func rewriteValuegeneric_OpRsh64Ux64_0(v *Value) bool { v.AddArg(v0) return true } + // match: (Rsh64Ux64 (Rsh64x64 x _) (Const64 [63])) + // cond: + // result: (Rsh64Ux64 x (Const64 [63])) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpRsh64x64 { + break + } + _ = v_0.Args[1] + x := v_0.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if v_1.AuxInt != 63 { + break + } + v.reset(OpRsh64Ux64) + v.AddArg(x) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = 63 + v.AddArg(v0) + return true + } // match: (Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Rsh64Ux64 x (Const64 [c1-c2+c3])) @@ -26472,6 +26801,32 @@ func rewriteValuegeneric_OpRsh8Ux64_0(v *Value) bool { v.AddArg(v0) return true } + // match: (Rsh8Ux64 (Rsh8x64 x _) (Const64 [7])) + // cond: + // result: (Rsh8Ux64 x (Const64 [7] )) + for { + _ = v.Args[1] + v_0 := v.Args[0] + if v_0.Op != OpRsh8x64 { + break + } + _ = v_0.Args[1] + x := v_0.Args[0] + v_1 := v.Args[1] + if v_1.Op != OpConst64 { + break + } + t := v_1.Type + if v_1.AuxInt != 7 { + break + } + v.reset(OpRsh8Ux64) + v.AddArg(x) + v0 := b.NewValue0(v.Pos, OpConst64, t) + v0.AuxInt = 7 + v.AddArg(v0) + return true + } // match: (Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3])) // cond: uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3) // result: (Rsh8Ux64 x (Const64 [c1-c2+c3])) @@ -27344,6 +27699,20 @@ func rewriteValuegeneric_OpStaticCall_0(v *Value) bool { v.AddArg(mem) return true } + // match: (StaticCall {sym} x) + // cond: needRaceCleanup(sym,v) + // result: x + for { + sym := v.Aux + x := v.Args[0] + if !(needRaceCleanup(sym, v)) { + break + } + v.reset(OpCopy) + v.Type = x.Type + v.AddArg(x) + return true + } return false } func rewriteValuegeneric_OpStore_0(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index c62c0c47e2..f1783a9532 100644 --- a/src/cmd/compile/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go @@ -310,7 +310,6 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value // A constant bound allows this to be stack-allocated. 64 is // enough to cover almost every storeOrder call. stores := make([]*Value, 0, 64) - var vardefs map[interface{}]*Value // OpAddr must depend on Vardef for Node hasNilCheck := false sset.clear() // sset is the set of stores that are used in other values for _, v := range values { @@ -324,12 +323,6 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value if v.Op == OpNilCheck { hasNilCheck = true } - if v.Op == OpVarDef { - if vardefs == nil { // Lazy init, not all blocks have vardefs - vardefs = make(map[interface{}]*Value) - } - vardefs[v.Aux] = v - } } if len(stores) == 0 || !hasNilCheck && f.pass.name == "nilcheckelim" { // there is no store, the order does not matter @@ -393,20 +386,7 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value stack = stack[:len(stack)-1] continue } - if w.Op == OpAddr { - // OpAddr depends only on relevant VarDef - vn := int32(0) - if vardefs != nil { - if a := vardefs[w.Aux]; a != nil { // if nil, it is in some other block, or global or arg - vn = storeNumber[a.ID] - } - } - vn += 2 - storeNumber[w.ID] = vn - count[vn]++ - stack = stack[:len(stack)-1] - continue - } + max := int32(0) // latest store dependency argsdone := true for _, a := range w.Args { diff --git a/src/cmd/compile/internal/ssa/stmtlines_test.go b/src/cmd/compile/internal/ssa/stmtlines_test.go index 443b5f9f56..1081f83f6d 100644 --- a/src/cmd/compile/internal/ssa/stmtlines_test.go +++ b/src/cmd/compile/internal/ssa/stmtlines_test.go @@ -39,22 +39,6 @@ type Line struct { Line int } -type File struct { - lines []string -} - -var fileCache = map[string]*File{} - -func (f *File) Get(lineno int) (string, bool) { - if f == nil { - return "", false - } - if lineno-1 < 0 || lineno-1 >= len(f.lines) { - return "", false - } - return f.lines[lineno-1], true -} - func TestStmtLines(t *testing.T) { if runtime.GOOS == "plan9" { t.Skip("skipping on plan9; no DWARF symbol table in executables") diff --git a/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts b/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts index 089d176c60..7eb1d3a35b 100644 --- a/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts +++ b/src/cmd/compile/internal/ssa/testdata/hist.dlv-opt.nexts @@ -2,149 +2,82 @@ 55: func test() { 57: l := line{point{1 + zero, 2 + zero}, point{3 + zero, 4 + zero}} 58: tinycall() // this forces l etc to stack -57: l := line{point{1 + zero, 2 + zero}, point{3 + zero, 4 + zero}} 59: dx := l.end.x - l.begin.x //gdb-dbg=(l.begin.x,l.end.y)//gdb-opt=(l,dx/O,dy/O) 60: dy := l.end.y - l.begin.y //gdb-opt=(dx,dy/O) 61: sink = dx + dy //gdb-opt=(dx,dy) 63: hist := make([]int, 7) //gdb-opt=(dx/O,dy/O) // TODO sink is missing if this code is in 'test' instead of 'main' 64: var reader io.Reader = strings.NewReader(cannedInput) //gdb-dbg=(hist/A) // TODO cannedInput/A is missing if this code is in 'test' instead of 'main' 65: if len(os.Args) > 1 { -73: scanner := bufio.NewScanner(reader) -63: hist := make([]int, 7) //gdb-opt=(dx/O,dy/O) // TODO sink is missing if this code is in 'test' instead of 'main' -74: for scanner.Scan() { //gdb-opt=(scanner/A) -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 76: i, err := strconv.ParseInt(s, 10, 64) 77: if err != nil { //gdb-dbg=(i) //gdb-opt=(err,hist,i) -76: i, err := strconv.ParseInt(s, 10, 64) 81: hist = ensure(int(i), hist) 82: hist[int(i)]++ -81: hist = ensure(int(i), hist) 74: for scanner.Scan() { //gdb-opt=(scanner/A) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) -86: for i, a := range hist { 91: n += a 90: t += i * a 92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -86: for i, a := range hist { -90: t += i * a -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) -86: for i, a := range hist { 91: n += a 90: t += i * a 92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -86: for i, a := range hist { -90: t += i * a -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) -86: for i, a := range hist { 91: n += a 90: t += i * a 92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -86: for i, a := range hist { -90: t += i * a -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) -86: for i, a := range hist { 91: n += a 90: t += i * a 92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -90: t += i * a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) -86: for i, a := range hist { -90: t += i * a -91: n += a -92: fmt.Fprintf(os.Stderr, "%d\t%d\t%d\t%d\t%d\n", i, a, n, i*a, t) //gdb-dbg=(n,i,t) 86: for i, a := range hist { 87: if a == 0 { //gdb-opt=(a,n,t) 86: for i, a := range hist { diff --git a/src/cmd/compile/internal/ssa/testdata/scopes.dlv-opt.nexts b/src/cmd/compile/internal/ssa/testdata/scopes.dlv-opt.nexts index 1af55df4a0..3cc2ec5121 100644 --- a/src/cmd/compile/internal/ssa/testdata/scopes.dlv-opt.nexts +++ b/src/cmd/compile/internal/ssa/testdata/scopes.dlv-opt.nexts @@ -4,32 +4,17 @@ 24: y := id(0) 25: fmt.Println(x) 26: for i := x; i < 3; i++ { -30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) -26: for i := x; i < 3; i++ { -30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) +27: x := i * i +28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) 26: for i := x; i < 3; i++ { 27: x := i * i 28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) 26: for i := x; i < 3; i++ { -28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) -30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) -26: for i := x; i < 3; i++ { 27: x := i * i 28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) 26: for i := x; i < 3; i++ { -28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) -30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) -26: for i := x; i < 3; i++ { -27: x := i * i -28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) -26: for i := x; i < 3; i++ { -28: y += id(x) //gdb-dbg=(x,y)//gdb-opt=(x,y) -30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) -26: for i := x; i < 3; i++ { 31: fmt.Println(x, y) 30: y = x + y //gdb-dbg=(x,y)//gdb-opt=(x,y) -31: fmt.Println(x, y) -22: func test() { 33: for x := 0; x <= 1; x++ { // From delve scopetest.go 35: f1(a) 38: f2(b) @@ -49,11 +34,9 @@ 54: f = id(2) 56: for i := 0; i <= 5; i++ { 58: if i == f { -56: for i := 0; i <= 5; i++ { 62: sleepytime() 56: for i := 0; i <= 5; i++ { 58: if i == f { -56: for i := 0; i <= 5; i++ { 62: sleepytime() 56: for i := 0; i <= 5; i++ { 58: if i == f { diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index a1ab0e54e7..7e869f29c9 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -25,7 +25,7 @@ type Value struct { Op Op // The type of this value. Normally this will be a Go type, but there - // are a few other pseudo-types, see type.go. + // are a few other pseudo-types, see ../types/type.go. Type *types.Type // Auxiliary info for this value. The type of this information depends on the opcode and type. diff --git a/src/cmd/compile/internal/ssa/writebarrier.go b/src/cmd/compile/internal/ssa/writebarrier.go index 92b8b006b7..2366e0bfbf 100644 --- a/src/cmd/compile/internal/ssa/writebarrier.go +++ b/src/cmd/compile/internal/ssa/writebarrier.go @@ -306,7 +306,7 @@ func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Va t := val.Type.Elem() tmp = b.Func.fe.Auto(val.Pos, t) mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem) - tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), tmp, sp) + tmpaddr := b.NewValue2A(pos, OpLocalAddr, t.PtrTo(), tmp, sp, mem) siz := t.Size() mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem) mem.Aux = t @@ -359,10 +359,8 @@ func IsStackAddr(v *Value) bool { v = v.Args[0] } switch v.Op { - case OpSP: + case OpSP, OpLocalAddr: return true - case OpAddr: - return v.Args[0].Op == OpSP } return false } @@ -374,7 +372,7 @@ func IsSanitizerSafeAddr(v *Value) bool { v = v.Args[0] } switch v.Op { - case OpSP: + case OpSP, OpLocalAddr: // Stack addresses are always safe. return true case OpITab, OpStringPtr, OpGetClosurePtr: @@ -382,19 +380,14 @@ func IsSanitizerSafeAddr(v *Value) bool { // read-only once initialized. return true case OpAddr: - switch v.Args[0].Op { - case OpSP: + sym := v.Aux.(*obj.LSym) + // TODO(mdempsky): Find a cleaner way to + // detect this. It would be nice if we could + // test sym.Type==objabi.SRODATA, but we don't + // initialize sym.Type until after function + // compilation. + if strings.HasPrefix(sym.Name, `"".statictmp_`) { return true - case OpSB: - sym := v.Aux.(*obj.LSym) - // TODO(mdempsky): Find a cleaner way to - // detect this. It would be nice if we could - // test sym.Type==objabi.SRODATA, but we don't - // initialize sym.Type until after function - // compilation. - if strings.HasPrefix(sym.Name, `"".statictmp_`) { - return true - } } } return false diff --git a/src/cmd/compile/internal/x86/387.go b/src/cmd/compile/internal/x86/387.go index 7a3622405c..18838fb4ca 100644 --- a/src/cmd/compile/internal/x86/387.go +++ b/src/cmd/compile/internal/x86/387.go @@ -22,11 +22,29 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) { switch v.Op { case ssa.Op386MOVSSconst, ssa.Op386MOVSDconst: - p := s.Prog(loadPush(v.Type)) - p.From.Type = obj.TYPE_FCONST - p.From.Val = math.Float64frombits(uint64(v.AuxInt)) - p.To.Type = obj.TYPE_REG - p.To.Reg = x86.REG_F0 + iv := uint64(v.AuxInt) + if iv == 0x0000000000000000 { // +0.0 + s.Prog(x86.AFLDZ) + } else if iv == 0x3ff0000000000000 { // +1.0 + s.Prog(x86.AFLD1) + } else if iv == 0x8000000000000000 { // -0.0 + s.Prog(x86.AFLDZ) + s.Prog(x86.AFCHS) + } else if iv == 0xbff0000000000000 { // -1.0 + s.Prog(x86.AFLD1) + s.Prog(x86.AFCHS) + } else if iv == 0x400921fb54442d18 { // +pi + s.Prog(x86.AFLDPI) + } else if iv == 0xc00921fb54442d18 { // -pi + s.Prog(x86.AFLDPI) + s.Prog(x86.AFCHS) + } else { // others + p := s.Prog(loadPush(v.Type)) + p.From.Type = obj.TYPE_FCONST + p.From.Val = math.Float64frombits(iv) + p.To.Type = obj.TYPE_REG + p.To.Reg = x86.REG_F0 + } popAndSave(s, v) case ssa.Op386MOVSSconst2, ssa.Op386MOVSDconst2: diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go index b781d95725..a53b63ab92 100644 --- a/src/cmd/compile/internal/x86/ssa.go +++ b/src/cmd/compile/internal/x86/ssa.go @@ -417,6 +417,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = v.Args[0].Reg() + case ssa.Op386CMPLload, ssa.Op386CMPWload, ssa.Op386CMPBload: + p := s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_MEM + p.From.Reg = v.Args[0].Reg() + gc.AddAux(&p.From, v) + p.To.Type = obj.TYPE_REG + p.To.Reg = v.Args[1].Reg() + case ssa.Op386CMPLconstload, ssa.Op386CMPWconstload, ssa.Op386CMPBconstload: + sc := v.AuxValAndOff() + p := s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_MEM + p.From.Reg = v.Args[0].Reg() + gc.AddAux2(&p.From, v, sc.Off()) + p.To.Type = obj.TYPE_CONST + p.To.Offset = sc.Val() case ssa.Op386MOVLconst: x := v.Reg() @@ -510,8 +525,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { gc.AddAux(&p.From, v) p.To.Type = obj.TYPE_REG p.To.Reg = v.Reg() - case ssa.Op386ADDLload, ssa.Op386SUBLload, ssa.Op386ANDLload, ssa.Op386ORLload, ssa.Op386XORLload, - ssa.Op386ADDSDload, ssa.Op386ADDSSload, ssa.Op386SUBSDload, ssa.Op386SUBSSload, ssa.Op386MULSDload, ssa.Op386MULSSload: + case ssa.Op386ADDLload, ssa.Op386SUBLload, ssa.Op386MULLload, + ssa.Op386ANDLload, ssa.Op386ORLload, ssa.Op386XORLload, + ssa.Op386ADDSDload, ssa.Op386ADDSSload, ssa.Op386SUBSDload, ssa.Op386SUBSSload, + ssa.Op386MULSDload, ssa.Op386MULSSload, ssa.Op386DIVSSload, ssa.Op386DIVSDload: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_MEM p.From.Reg = v.Args[1].Reg() @@ -529,6 +546,33 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { p.To.Type = obj.TYPE_MEM p.To.Reg = v.Args[0].Reg() gc.AddAux(&p.To, v) + case ssa.Op386ADDLconstmodify: + var p *obj.Prog = nil + sc := v.AuxValAndOff() + off := sc.Off() + val := sc.Val() + if val == 1 { + p = s.Prog(x86.AINCL) + } else if val == -1 { + p = s.Prog(x86.ADECL) + } else { + p = s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_CONST + p.From.Offset = val + } + p.To.Type = obj.TYPE_MEM + p.To.Reg = v.Args[0].Reg() + gc.AddAux2(&p.To, v, off) + case ssa.Op386ANDLconstmodify, ssa.Op386ORLconstmodify, ssa.Op386XORLconstmodify: + sc := v.AuxValAndOff() + off := sc.Off() + val := sc.Val() + p := s.Prog(v.Op.Asm()) + p.From.Type = obj.TYPE_CONST + p.From.Offset = val + p.To.Type = obj.TYPE_MEM + p.To.Reg = v.Args[0].Reg() + gc.AddAux2(&p.To, v, off) case ssa.Op386MOVSDstoreidx8: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_REG diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go index f496f4cff6..54cf4be25e 100644 --- a/src/cmd/cover/cover.go +++ b/src/cmd/cover/cover.go @@ -16,7 +16,6 @@ import ( "log" "os" "sort" - "strconv" "cmd/internal/edit" "cmd/internal/objabi" @@ -294,17 +293,6 @@ func (f *File) Visit(node ast.Node) ast.Visitor { return f } -// unquote returns the unquoted string. -func unquote(s string) string { - t, err := strconv.Unquote(s) - if err != nil { - log.Fatalf("cover: improperly quoted string %q\n", s) - } - return t -} - -var slashslash = []byte("//") - func annotate(name string) { fset := token.NewFileSet() content, err := ioutil.ReadFile(name) diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go index c818819c39..8eb7124aad 100644 --- a/src/cmd/cover/cover_test.go +++ b/src/cmd/cover/cover_test.go @@ -314,7 +314,7 @@ func TestCoverHTML(t *testing.T) { // Compare at the line level, stopping at first different line so // we don't generate tons of output if there's an inserted or deleted line. for i, goldenLine := range goldenLines { - if i > len(outLines) { + if i >= len(outLines) { t.Fatalf("output shorter than golden; stops before line %d: %s\n", i+1, goldenLine) } // Convert all white space to simple spaces, for easy comparison. diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go index 1673fbf315..fe64374189 100644 --- a/src/cmd/cover/func.go +++ b/src/cmd/cover/func.go @@ -8,13 +8,20 @@ package main import ( "bufio" + "bytes" + "encoding/json" + "errors" "fmt" "go/ast" - "go/build" "go/parser" "go/token" + "io" "os" + "os/exec" + "path" "path/filepath" + "runtime" + "strings" "text/tabwriter" ) @@ -36,6 +43,11 @@ func funcOutput(profile, outputFile string) error { return err } + dirs, err := findPkgs(profiles) + if err != nil { + return err + } + var out *bufio.Writer if outputFile == "" { out = bufio.NewWriter(os.Stdout) @@ -55,7 +67,7 @@ func funcOutput(profile, outputFile string) error { var total, covered int64 for _, profile := range profiles { fn := profile.FileName - file, err := findFile(fn) + file, err := findFile(dirs, fn) if err != nil { return err } @@ -154,14 +166,72 @@ func (f *FuncExtent) coverage(profile *Profile) (num, den int64) { return covered, total } -// findFile finds the location of the named file in GOROOT, GOPATH etc. -func findFile(file string) (string, error) { - dir, file := filepath.Split(file) - pkg, err := build.Import(dir, ".", build.FindOnly) - if err != nil { - return "", fmt.Errorf("can't find %q: %v", file, err) +// Pkg describes a single package, compatible with the JSON output from 'go list'; see 'go help list'. +type Pkg struct { + ImportPath string + Dir string + Error *struct { + Err string } - return filepath.Join(pkg.Dir, file), nil +} + +func findPkgs(profiles []*Profile) (map[string]*Pkg, error) { + // Run go list to find the location of every package we care about. + pkgs := make(map[string]*Pkg) + var list []string + for _, profile := range profiles { + if strings.HasPrefix(profile.FileName, ".") || filepath.IsAbs(profile.FileName) { + // Relative or absolute path. + continue + } + pkg := path.Dir(profile.FileName) + if _, ok := pkgs[pkg]; !ok { + pkgs[pkg] = nil + list = append(list, pkg) + } + } + + // Note: usually run as "go tool cover" in which case $GOROOT is set, + // in which case runtime.GOROOT() does exactly what we want. + goTool := filepath.Join(runtime.GOROOT(), "bin/go") + cmd := exec.Command(goTool, append([]string{"list", "-e", "-json"}, list...)...) + var stderr bytes.Buffer + cmd.Stderr = &stderr + stdout, err := cmd.Output() + if err != nil { + return nil, fmt.Errorf("cannot run go list: %v\n%s", err, stderr.Bytes()) + } + dec := json.NewDecoder(bytes.NewReader(stdout)) + for { + var pkg Pkg + err := dec.Decode(&pkg) + if err == io.EOF { + break + } + if err != nil { + return nil, fmt.Errorf("decoding go list json: %v", err) + } + pkgs[pkg.ImportPath] = &pkg + } + return pkgs, nil +} + +// findFile finds the location of the named file in GOROOT, GOPATH etc. +func findFile(pkgs map[string]*Pkg, file string) (string, error) { + if strings.HasPrefix(file, ".") || filepath.IsAbs(file) { + // Relative or absolute path. + return file, nil + } + pkg := pkgs[path.Dir(file)] + if pkg != nil { + if pkg.Dir != "" { + return filepath.Join(pkg.Dir, path.Base(file)), nil + } + if pkg.Error != nil { + return "", errors.New(pkg.Error.Err) + } + } + return "", fmt.Errorf("did not find package for %s in go list output", file) } func percent(covered, total int64) float64 { diff --git a/src/cmd/cover/html.go b/src/cmd/cover/html.go index 2179728216..7940e78f22 100644 --- a/src/cmd/cover/html.go +++ b/src/cmd/cover/html.go @@ -29,12 +29,17 @@ func htmlOutput(profile, outfile string) error { var d templateData + dirs, err := findPkgs(profiles) + if err != nil { + return err + } + for _, profile := range profiles { fn := profile.FileName if profile.Mode == "set" { d.Set = true } - file, err := findFile(fn) + file, err := findFile(dirs, fn) if err != nil { return err } diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index 616e76dfe7..d4f9dc4fbb 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -219,10 +219,7 @@ func xinit() { // Use a build cache separate from the default user one. // Also one that will be wiped out during startup, so that // make.bash really does start from a clean slate. - // But if the user has specified no caching, don't cache. - if os.Getenv("GOCACHE") != "off" { - os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) - } + os.Setenv("GOCACHE", pathf("%s/pkg/obj/go-build", goroot)) // Make the environment more predictable. os.Setenv("LANG", "C") @@ -808,10 +805,14 @@ func runInstall(dir string, ch chan struct{}) { compile = append(compile, "-asmhdr", pathf("%s/go_asm.h", workdir)) } compile = append(compile, gofiles...) - run(path, CheckExit|ShowOutput, compile...) + var wg sync.WaitGroup + // We use bgrun and immediately wait for it instead of calling run() synchronously. + // This executes all jobs through the bgwork channel and allows the process + // to exit cleanly in case an error occurs. + bgrun(&wg, path, compile...) + bgwait(&wg) // Compile the files. - var wg sync.WaitGroup for _, p := range files { if !strings.HasSuffix(p, ".s") { continue @@ -861,7 +862,8 @@ func runInstall(dir string, ch chan struct{}) { // Remove target before writing it. xremove(link[targ]) - run("", CheckExit|ShowOutput, link...) + bgrun(&wg, "", link...) + bgwait(&wg) } // matchfield reports whether the field (x,y,z) matches this build. @@ -1063,12 +1065,16 @@ func cmdenv() { format = "set %s=%s\r\n" } - xprintf(format, "GOROOT", goroot) - xprintf(format, "GOBIN", gobin) xprintf(format, "GOARCH", goarch) - xprintf(format, "GOOS", goos) + xprintf(format, "GOBIN", gobin) + xprintf(format, "GOCACHE", os.Getenv("GOCACHE")) + xprintf(format, "GODEBUG", os.Getenv("GODEBUG")) xprintf(format, "GOHOSTARCH", gohostarch) xprintf(format, "GOHOSTOS", gohostos) + xprintf(format, "GOOS", goos) + xprintf(format, "GOPROXY", os.Getenv("GOPROXY")) + xprintf(format, "GOROOT", goroot) + xprintf(format, "GOTMPDIR", os.Getenv("GOTMPDIR")) xprintf(format, "GOTOOLDIR", tooldir) if goarch == "arm" { xprintf(format, "GOARM", goarm) @@ -1302,9 +1308,14 @@ func cmdbootstrap() { os.Setenv("CC", compilerEnvLookup(defaultcc, goos, goarch)) xprintf("Building packages and commands for target, %s/%s.\n", goos, goarch) } - goInstall(goBootstrap, "std", "cmd") - checkNotStale(goBootstrap, "std", "cmd") - checkNotStale(cmdGo, "std", "cmd") + targets := []string{"std", "cmd"} + if goos == "js" && goarch == "wasm" { + // Skip the cmd tools for js/wasm. They're not usable. + targets = targets[:1] + } + goInstall(goBootstrap, targets...) + checkNotStale(goBootstrap, targets...) + checkNotStale(cmdGo, targets...) if debug { run("", ShowOutput|CheckExit, pathf("%s/compile", tooldir), "-V=full") run("", ShowOutput|CheckExit, pathf("%s/buildid", tooldir), pathf("%s/pkg/%s_%s/runtime/internal/sys.a", goroot, goos, goarch)) @@ -1416,6 +1427,7 @@ var cgoEnabled = map[string]bool{ "solaris/amd64": true, "windows/386": true, "windows/amd64": true, + "windows/arm": false, } func needCC() bool { diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go index 216dc01798..2f6a1b0dce 100644 --- a/src/cmd/dist/sys_windows.go +++ b/src/cmd/dist/sys_windows.go @@ -32,6 +32,7 @@ type systeminfo struct { const ( PROCESSOR_ARCHITECTURE_AMD64 = 9 PROCESSOR_ARCHITECTURE_INTEL = 0 + PROCESSOR_ARCHITECTURE_ARM = 5 ) var sysinfo systeminfo @@ -43,6 +44,8 @@ func sysinit() { gohostarch = "amd64" case PROCESSOR_ARCHITECTURE_INTEL: gohostarch = "386" + case PROCESSOR_ARCHITECTURE_ARM: + gohostarch = "arm" default: fatalf("unknown processor architecture") } diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index 5be4bcfa65..4cd854773f 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -645,7 +645,7 @@ func (t *tester) registerTests() { return nil }, }) - if cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch)); cxx != "" { + if t.hasCxx() { t.tests = append(t.tests, distTest{ name: "swig_callback", heading: "../misc/swig/callback", @@ -705,7 +705,7 @@ func (t *tester) registerTests() { if gohostos == "linux" && goarch == "amd64" { t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go") } - if goos == "linux" && (goarch == "amd64" || goarch == "arm64") { + if mSanSupported(goos, goarch) { t.registerHostTest("testsanitizers/msan", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".") } if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" { @@ -1065,6 +1065,12 @@ func (t *tester) cgoTest(dt *distTest) error { t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`) if goos != "android" { t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) + t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`) + // -static in CGO_LDFLAGS triggers a different code path + // than -static in -extldflags, so test both. + // See issue #16651. + cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static") + cmd.Env = append(os.Environ(), "CGO_LDFLAGS=-static -pthread") } } @@ -1243,6 +1249,11 @@ func (t *tester) hasBash() bool { return true } +func (t *tester) hasCxx() bool { + cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch)) + return cxx != "" +} + func (t *tester) hasSwig() bool { swig, err := exec.LookPath("swig") if err != nil { @@ -1318,13 +1329,26 @@ func (t *tester) hasSwig() bool { } func (t *tester) raceDetectorSupported() bool { - switch gohostos { - case "linux", "darwin", "freebsd", "windows": - // The race detector doesn't work on Alpine Linux: - // golang.org/issue/14481 - return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux() + if gohostos != goos { + return false } - return false + if !t.cgoEnabled { + return false + } + if !raceDetectorSupported(goos, goarch) { + return false + } + // The race detector doesn't work on Alpine Linux: + // golang.org/issue/14481 + if isAlpineLinux() { + return false + } + // NetBSD support is unfinished. + // golang.org/issue/26403 + if goos == "netbsd" { + return false + } + return true } func isAlpineLinux() bool { @@ -1348,7 +1372,7 @@ func (t *tester) runFlag(rx string) string { func (t *tester) raceTest(dt *distTest) error { t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec") t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race") - t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob") + t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob") // We don't want the following line, because it // slows down all.bash (by 10 seconds on my laptop). // The race builder should catch any error here, but doesn't. @@ -1439,3 +1463,26 @@ func (t *tester) packageHasBenchmarks(pkg string) bool { } return false } + +// raceDetectorSupported is a copy of the function +// cmd/internal/sys.RaceDetectorSupported, which can't be used here +// because cmd/dist has to be buildable by Go 1.4. +func raceDetectorSupported(goos, goarch string) bool { + switch goos { + case "linux", "darwin", "freebsd", "netbsd", "windows": + return goarch == "amd64" || goarch == "ppc64le" + default: + return false + } +} + +// mSanSupported is a copy of the function cmd/internal/sys.MSanSupported, +// which can't be used here because cmd/dist has to be buildable by Go 1.4. +func mSanSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "arm64" + default: + return false + } +} diff --git a/src/cmd/doc/dirs.go b/src/cmd/doc/dirs.go index f5fb795dc7..24bd797eb5 100644 --- a/src/cmd/doc/dirs.go +++ b/src/cmd/doc/dirs.go @@ -5,32 +5,41 @@ package main import ( + "bytes" "log" "os" - "path" + "os/exec" "path/filepath" "strings" + "sync" ) +// A Dir describes a directory holding code by specifying +// the expected import path and the file system directory. +type Dir struct { + importPath string // import path for that dir + dir string // file system directory +} + // Dirs is a structure for scanning the directory tree. // Its Next method returns the next Go source directory it finds. // Although it can be used to scan the tree multiple times, it // only walks the tree once, caching the data it finds. type Dirs struct { - scan chan string // directories generated by walk. - paths []string // Cache of known paths. - offset int // Counter for Next. + scan chan Dir // Directories generated by walk. + hist []Dir // History of reported Dirs. + offset int // Counter for Next. } var dirs Dirs // dirsInit starts the scanning of package directories in GOROOT and GOPATH. Any // extra paths passed to it are included in the channel. -func dirsInit(extra ...string) { - dirs.paths = make([]string, 0, 1000) - dirs.paths = append(dirs.paths, extra...) - dirs.scan = make(chan string) - go dirs.walk() +func dirsInit(extra ...Dir) { + dirs.hist = make([]Dir, 0, 1000) + dirs.hist = append(dirs.hist, extra...) + dirs.scan = make(chan Dir) + go dirs.walk(codeRoots()) } // Reset puts the scan back at the beginning. @@ -40,25 +49,24 @@ func (d *Dirs) Reset() { // Next returns the next directory in the scan. The boolean // is false when the scan is done. -func (d *Dirs) Next() (string, bool) { - if d.offset < len(d.paths) { - path := d.paths[d.offset] +func (d *Dirs) Next() (Dir, bool) { + if d.offset < len(d.hist) { + dir := d.hist[d.offset] d.offset++ - return path, true + return dir, true } - path, ok := <-d.scan + dir, ok := <-d.scan if !ok { - return "", false + return Dir{}, false } - d.paths = append(d.paths, path) + d.hist = append(d.hist, dir) d.offset++ - return path, ok + return dir, ok } // walk walks the trees in GOROOT and GOPATH. -func (d *Dirs) walk() { - d.bfsWalkRoot(buildCtx.GOROOT) - for _, root := range splitGopath() { +func (d *Dirs) walk(roots []Dir) { + for _, root := range roots { d.bfsWalkRoot(root) } close(d.scan) @@ -66,13 +74,13 @@ func (d *Dirs) walk() { // bfsWalkRoot walks a single directory hierarchy in breadth-first lexical order. // Each Go source directory it finds is delivered on d.scan. -func (d *Dirs) bfsWalkRoot(root string) { - root = path.Join(root, "src") +func (d *Dirs) bfsWalkRoot(root Dir) { + root.dir = filepath.Clean(root.dir) // because filepath.Join will do it anyway // this is the queue of directories to examine in this pass. this := []string{} // next is the queue of directories to examine in the next pass. - next := []string{root} + next := []string{root.dir} for len(next) > 0 { this, next = next, this[0:0] @@ -105,14 +113,83 @@ func (d *Dirs) bfsWalkRoot(root string) { if name[0] == '.' || name[0] == '_' || name == "testdata" { continue } + // Ignore vendor when using modules. + if usingModules && name == "vendor" { + continue + } // Remember this (fully qualified) directory for the next pass. next = append(next, filepath.Join(dir, name)) } if hasGoFiles { // It's a candidate. - d.scan <- dir + importPath := root.importPath + if len(dir) > len(root.dir) { + if importPath != "" { + importPath += "/" + } + importPath += filepath.ToSlash(dir[len(root.dir)+1:]) + } + d.scan <- Dir{importPath, dir} } } } } + +var testGOPATH = false // force GOPATH use for testing + +// codeRoots returns the code roots to search for packages. +// In GOPATH mode this is GOROOT/src and GOPATH/src, with empty import paths. +// In module mode, this is each module root, with an import path set to its module path. +func codeRoots() []Dir { + codeRootsCache.once.Do(func() { + codeRootsCache.roots = findCodeRoots() + }) + return codeRootsCache.roots +} + +var codeRootsCache struct { + once sync.Once + roots []Dir +} + +var usingModules bool + +func findCodeRoots() []Dir { + list := []Dir{{"", filepath.Join(buildCtx.GOROOT, "src")}} + + if !testGOPATH { + // Check for use of modules by 'go env GOMOD', + // which reports a go.mod file path if modules are enabled. + stdout, _ := exec.Command("go", "env", "GOMOD").Output() + usingModules = bytes.Contains(stdout, []byte("go.mod")) + } + + if !usingModules { + for _, root := range splitGopath() { + list = append(list, Dir{"", filepath.Join(root, "src")}) + } + return list + } + + // Find module root directories from go list. + // Eventually we want golang.org/x/tools/go/packages + // to handle the entire file system search and become go/packages, + // but for now enumerating the module roots lets us fit modules + // into the current code with as few changes as possible. + cmd := exec.Command("go", "list", "-m", "-f={{.Path}}\t{{.Dir}}", "all") + cmd.Stderr = os.Stderr + out, _ := cmd.Output() + for _, line := range strings.Split(string(out), "\n") { + i := strings.Index(line, "\t") + if i < 0 { + continue + } + path, dir := line[:i], line[i+1:] + if dir != "" { + list = append(list, Dir{path, dir}) + } + } + + return list +} diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index e68e95f3fb..6010f04b56 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -18,6 +18,7 @@ import ( func TestMain(m *testing.M) { // Clear GOPATH so we don't access the user's own packages in the test. buildCtx.GOPATH = "" + testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt // Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test. // Normally testdata directories are ignored, but sending it to dirs.scan directly is @@ -26,7 +27,7 @@ func TestMain(m *testing.M) { if err != nil { panic(err) } - dirsInit(testdataDir, filepath.Join(testdataDir, "nested"), filepath.Join(testdataDir, "nested", "nested")) + dirsInit(Dir{"testdata", testdataDir}, Dir{"testdata/nested", filepath.Join(testdataDir, "nested")}, Dir{"testdata/nested/nested", filepath.Join(testdataDir, "nested", "nested")}) os.Exit(m.Run()) } @@ -537,7 +538,7 @@ func TestDoc(t *testing.T) { var flagSet flag.FlagSet err := do(&b, &flagSet, test.args) if err != nil { - t.Fatalf("%s: %s\n", test.name, err) + t.Fatalf("%s %v: %s\n", test.name, test.args, err) } output := b.Bytes() failed := false diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go index bf0c7723f8..982c8e054a 100644 --- a/src/cmd/doc/main.go +++ b/src/cmd/doc/main.go @@ -39,6 +39,7 @@ import ( "io" "log" "os" + "path" "path/filepath" "strings" "unicode" @@ -189,6 +190,10 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo // Done below. case 2: // Package must be findable and importable. + pkg, err := build.Import(args[0], "", build.ImportComment) + if err == nil { + return pkg, args[0], args[1], false + } for { packagePath, ok := findNextPackage(arg) if !ok { @@ -355,14 +360,22 @@ func findNextPackage(pkg string) (string, bool) { if pkg == "" || isUpper(pkg) { // Upper case symbol cannot be a package name. return "", false } - pkgString := filepath.Clean(string(filepath.Separator) + pkg) + if filepath.IsAbs(pkg) { + if dirs.offset == 0 { + dirs.offset = -1 + return pkg, true + } + return "", false + } + pkg = path.Clean(pkg) + pkgSuffix := "/" + pkg for { - path, ok := dirs.Next() + d, ok := dirs.Next() if !ok { return "", false } - if strings.HasSuffix(path, pkgString) { - return path, true + if d.importPath == pkg || strings.HasSuffix(d.importPath, pkgSuffix) { + return d.dir, true } } } diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 8ff9ff57ac..14e41b9106 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -425,12 +425,36 @@ func (pkg *Package) packageClause(checkUserPath bool) { return } } + importPath := pkg.build.ImportComment if importPath == "" { importPath = pkg.build.ImportPath } + + // If we're using modules, the import path derived from module code locations wins. + // If we did a file system scan, we knew the import path when we found the directory. + // But if we started with a directory name, we never knew the import path. + // Either way, we don't know it now, and it's cheap to (re)compute it. + if usingModules { + for _, root := range codeRoots() { + if pkg.build.Dir == root.dir { + importPath = root.importPath + break + } + if strings.HasPrefix(pkg.build.Dir, root.dir+string(filepath.Separator)) { + suffix := filepath.ToSlash(pkg.build.Dir[len(root.dir)+1:]) + if root.importPath == "" { + importPath = suffix + } else { + importPath = root.importPath + "/" + suffix + } + break + } + } + } + pkg.Printf("package %s // import %q\n\n", pkg.name, importPath) - if importPath != pkg.build.ImportPath { + if !usingModules && importPath != pkg.build.ImportPath { pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath) } } diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index fd281460b1..35cabcac14 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -9,7 +9,7 @@ // // Usage: // -// go command [arguments] +// go [arguments] // // The commands are: // @@ -23,14 +23,15 @@ // generate generate Go files by processing source // get download and install packages and dependencies // install compile and install packages and dependencies -// list list packages +// list list packages or modules +// mod module maintenance // run compile and run Go program // test test packages // tool run specified go tool // version print Go version // vet report likely mistakes in packages // -// Use "go help [command]" for more information about a command. +// Use "go help " for more information about a command. // // Additional help topics: // @@ -39,13 +40,18 @@ // cache build and test caching // environment environment variables // filetype file types +// go.mod the go.mod file // gopath GOPATH environment variable +// gopath-get legacy GOPATH go get +// goproxy module proxy protocol // importpath import path syntax -// packages package lists +// modules modules, module versions, and more +// module-get module-aware go get +// packages package lists and patterns // testflag testing flags // testfunc testing functions // -// Use "go help [topic]" for more information about that topic. +// Use "go help " for more information about that topic. // // // Start a bug report @@ -137,6 +143,9 @@ // -linkshared // link against shared libraries previously created with // -buildmode=shared. +// -mod mode +// module download mode to use: readonly, release, or vendor. +// See 'go help modules' for more. // -pkgdir dir // install and load all packages from dir instead of the usual locations. // For example, when building with a non-standard configuration, @@ -185,7 +194,7 @@ // // Usage: // -// go clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages] +// go clean [clean flags] [build flags] [packages] // // Clean removes object files from package source directories. // The go command builds most objects in a temporary directory, @@ -228,6 +237,10 @@ // The -testcache flag causes clean to expire all test results in the // go build cache. // +// The -modcache flag causes clean to remove the entire module +// download cache, including unpacked source code of versioned +// dependencies. +// // For more about build flags, see 'go help build'. // // For more about specifying packages, see 'go help packages'. @@ -512,7 +525,7 @@ // // Usage: // -// go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [-v] [build flags] [packages] +// go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages] // // Get downloads the packages named by the import paths, along with their // dependencies. It then installs the named packages, like 'go install'. @@ -562,6 +575,12 @@ // For more about how 'go get' finds source code to // download, see 'go help importpath'. // +// This text describes the behavior of get when using GOPATH +// to manage source code and dependencies. +// If instead the go command is running in module-aware mode, +// the details of get's flags and effects change, as does 'go help get'. +// See 'go help modules' and 'go help module-get'. +// // See also: go build, go install, go clean. // // @@ -581,13 +600,16 @@ // See also: go build, go get, go clean. // // -// List packages +// List packages or modules // // Usage: // -// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages] +// go list [-f format] [-json] [-m] [list flags] [build flags] [packages] // -// List lists the packages named by the import paths, one per line. +// List lists the named packages, one per line. +// The most commonly-used flags are -f and -json, which control the form +// of the output printed for each package. Other list flags, documented below, +// control more specific details. // // The default output shows the package import path: // @@ -597,43 +619,46 @@ // golang.org/x/net/html // // The -f flag specifies an alternate format for the list, using the -// syntax of package template. The default output is equivalent to -f -// '{{.ImportPath}}'. The struct being passed to the template is: +// syntax of package template. The default output is equivalent +// to -f '{{.ImportPath}}'. The struct being passed to the template is: // // type Package struct { -// Dir string // directory containing package sources -// ImportPath string // import path of package in dir -// ImportComment string // path in import comment on package statement -// Name string // package name -// Doc string // package documentation string -// Target string // install path -// Shlib string // the shared library that contains this package (only set when -linkshared) -// Goroot bool // is this package in the Go root? -// Standard bool // is this package part of the standard Go library? -// Stale bool // would 'go install' do anything for this package? -// StaleReason string // explanation for Stale==true -// Root string // Go root or Go path dir containing this package -// ConflictDir string // this directory shadows Dir in $GOPATH -// BinaryOnly bool // binary-only package: cannot be recompiled from sources -// ForTest string // package is only for use in named test -// DepOnly bool // package is only a dependency, not explicitly listed -// Export string // file containing export data (when using -export) +// Dir string // directory containing package sources +// ImportPath string // import path of package in dir +// ImportComment string // path in import comment on package statement +// Name string // package name +// Doc string // package documentation string +// Target string // install path +// Shlib string // the shared library that contains this package (only set when -linkshared) +// Goroot bool // is this package in the Go root? +// Standard bool // is this package part of the standard Go library? +// Stale bool // would 'go install' do anything for this package? +// StaleReason string // explanation for Stale==true +// Root string // Go root or Go path dir containing this package +// ConflictDir string // this directory shadows Dir in $GOPATH +// BinaryOnly bool // binary-only package: cannot be recompiled from sources +// ForTest string // package is only for use in named test +// Export string // file containing export data (when using -export) +// Module *Module // info about package's containing module, if any (can be nil) +// Match []string // command-line patterns matching this package +// DepOnly bool // package is only a dependency, not explicitly listed // // // Source files -// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) -// CgoFiles []string // .go sources files that import "C" -// IgnoredGoFiles []string // .go sources ignored due to build constraints -// CFiles []string // .c source files -// CXXFiles []string // .cc, .cxx and .cpp source files -// MFiles []string // .m source files -// HFiles []string // .h, .hh, .hpp and .hxx source files -// FFiles []string // .f, .F, .for and .f90 Fortran source files -// SFiles []string // .s source files -// SwigFiles []string // .swig files -// SwigCXXFiles []string // .swigcxx files -// SysoFiles []string // .syso object files to add to archive -// TestGoFiles []string // _test.go files in package -// XTestGoFiles []string // _test.go files outside package +// GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) +// CgoFiles []string // .go source files that import "C" +// CompiledGoFiles []string // .go files presented to compiler (when using -compiled) +// IgnoredGoFiles []string // .go source files ignored due to build constraints +// CFiles []string // .c source files +// CXXFiles []string // .cc, .cxx and .cpp source files +// MFiles []string // .m source files +// HFiles []string // .h, .hh, .hpp and .hxx source files +// FFiles []string // .f, .F, .for and .f90 Fortran source files +// SFiles []string // .s source files +// SwigFiles []string // .swig files +// SwigCXXFiles []string // .swigcxx files +// SysoFiles []string // .syso object files to add to archive +// TestGoFiles []string // _test.go files in package +// XTestGoFiles []string // _test.go files outside package // // // Cgo directives // CgoCFLAGS []string // cgo: flags for C compiler @@ -644,10 +669,11 @@ // CgoPkgConfig []string // cgo: pkg-config names // // // Dependency information -// Imports []string // import paths used by this package -// Deps []string // all (recursively) imported dependencies -// TestImports []string // imports from TestGoFiles -// XTestImports []string // imports from XTestGoFiles +// Imports []string // import paths used by this package +// ImportMap map[string]string // map from source import to ImportPath (identity entries omitted) +// Deps []string // all (recursively) imported dependencies +// TestImports []string // imports from TestGoFiles +// XTestImports []string // imports from XTestGoFiles // // // Error information // Incomplete bool // this package or a dependency has an error @@ -659,7 +685,7 @@ // path to the vendor directory (for example, "d/vendor/p" instead of "p"), // so that the ImportPath uniquely identifies a given copy of a package. // The Imports, Deps, TestImports, and XTestImports lists also contain these -// expanded imports paths. See golang.org/s/go15vendor for more about vendoring. +// expanded import paths. See golang.org/s/go15vendor for more about vendoring. // // The error information, if any, is // @@ -669,22 +695,25 @@ // Err string // the error itself // } // +// The module information is a Module struct, defined in the discussion +// of list -m below. +// // The template function "join" calls strings.Join. // // The template function "context" returns the build context, defined as: // -// type Context struct { -// GOARCH string // target architecture -// GOOS string // target operating system -// GOROOT string // Go root -// GOPATH string // Go path -// CgoEnabled bool // whether cgo can be used -// UseAllFiles bool // use files regardless of +build lines, file names -// Compiler string // compiler to assume when computing target paths -// BuildTags []string // build constraints to match in +build lines -// ReleaseTags []string // releases the current release is compatible with -// InstallSuffix string // suffix to use in the name of the install dir -// } +// type Context struct { +// GOARCH string // target architecture +// GOOS string // target operating system +// GOROOT string // Go root +// GOPATH string // Go path +// CgoEnabled bool // whether cgo can be used +// UseAllFiles bool // use files regardless of +build lines, file names +// Compiler string // compiler to assume when computing target paths +// BuildTags []string // build constraints to match in +build lines +// ReleaseTags []string // releases the current release is compatible with +// InstallSuffix string // suffix to use in the name of the install dir +// } // // For more information about the meaning of these fields see the documentation // for the go/build package's Context type. @@ -692,9 +721,11 @@ // The -json flag causes the package data to be printed in JSON format // instead of using the template format. // -// The -cgo flag causes list to set CgoFiles not to the original *.go files -// importing "C" but instead to the translated files generated by the cgo -// command. +// The -compiled flag causes list to set CompiledGoFiles to the Go source +// files presented to the compiler. Typically this means that it repeats +// the files listed in GoFiles and then also adds the Go code generated +// by processing CgoFiles and SwigFiles. The Imports list contains the +// union of all imports from both GoFiles and CompiledGoFiles. // // The -deps flag causes list to iterate over not just the named packages // but also all their dependencies. It visits them in a depth-first post-order @@ -715,6 +746,9 @@ // The -export flag causes list to set the Export field to the name of a // file containing up-to-date export information for the given package. // +// The -find flag causes list to identify the named packages but not +// resolve their dependencies: the Imports and Deps lists will be empty. +// // The -test flag causes list to report not only the named packages // but also their test binaries (for packages with tests), to convey to // source code analysis tools exactly how test binaries are constructed. @@ -734,14 +768,344 @@ // // By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir // (that is, paths relative to Dir, not absolute paths). -// The extra entries added by the -cgo and -test flags are absolute paths -// referring to cached copies of generated Go source files. +// The generated files added when using the -compiled and -test flags +// are absolute paths referring to cached copies of generated Go source files. // Although they are Go source files, the paths may not end in ".go". // +// The -m flag causes list to list modules instead of packages. +// +// When listing modules, the -f flag still specifies a format template +// applied to a Go struct, but now a Module struct: +// +// type Module struct { +// Path string // module path +// Version string // module version +// Versions []string // available module versions (with -versions) +// Replace *Module // replaced by this module +// Time *time.Time // time version was created +// Update *Module // available update, if any (with -u) +// Main bool // is this the main module? +// Indirect bool // is this module only an indirect dependency of main module? +// Dir string // directory holding files for this module, if any +// GoMod string // path to go.mod file for this module, if any +// Error *ModuleError // error loading module +// } +// +// type ModuleError struct { +// Err string // the error itself +// } +// +// The default output is to print the module path and then +// information about the version and replacement if any. +// For example, 'go list -m all' might print: +// +// my/main/module +// golang.org/x/text v0.3.0 => /tmp/text +// rsc.io/pdf v0.1.1 +// +// The Module struct has a String method that formats this +// line of output, so that the default format is equivalent +// to -f '{{.String}}'. +// +// Note that when a module has been replaced, its Replace field +// describes the replacement module, and its Dir field is set to +// the replacement's source code, if present. (That is, if Replace +// is non-nil, then Dir is set to Replace.Dir, with no access to +// the replaced source code.) +// +// The -u flag adds information about available upgrades. +// When the latest version of a given module is newer than +// the current one, list -u sets the Module's Update field +// to information about the newer module. +// The Module's String method indicates an available upgrade by +// formatting the newer version in brackets after the current version. +// For example, 'go list -m -u all' might print: +// +// my/main/module +// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text +// rsc.io/pdf v0.1.1 [v0.1.2] +// +// (For tools, 'go list -m -u -json all' may be more convenient to parse.) +// +// The -versions flag causes list to set the Module's Versions field +// to a list of all known versions of that module, ordered according +// to semantic versioning, earliest to latest. The flag also changes +// the default output format to display the module path followed by the +// space-separated version list. +// +// The arguments to list -m are interpreted as a list of modules, not packages. +// The main module is the module containing the current directory. +// The active modules are the main module and its dependencies. +// With no arguments, list -m shows the main module. +// With arguments, list -m shows the modules specified by the arguments. +// Any of the active modules can be specified by its module path. +// The special pattern "all" specifies all the active modules, first the main +// module and then dependencies sorted by module path. +// A pattern containing "..." specifies the active modules whose +// module paths match the pattern. +// A query of the form path@version specifies the result of that query, +// which is not limited to active modules. +// See 'go help modules' for more about module queries. +// +// The template function "module" takes a single string argument +// that must be a module path or query and returns the specified +// module as a Module struct. If an error occurs, the result will +// be a Module struct with a non-nil Error field. +// // For more about build flags, see 'go help build'. // // For more about specifying packages, see 'go help packages'. // +// For more about modules, see 'go help modules'. +// +// +// Module maintenance +// +// Go mod provides access to operations on modules. +// +// Note that support for modules is built into all the go commands, +// not just 'go mod'. For example, day-to-day adding, removing, upgrading, +// and downgrading of dependencies should be done using 'go get'. +// See 'go help modules' for an overview of module functionality. +// +// Usage: +// +// go mod [arguments] +// +// The commands are: +// +// download download modules to local cache +// edit edit go.mod from tools or scripts +// graph print module requirement graph +// init initialize new module in current directory +// tidy add missing and remove unused modules +// vendor make vendored copy of dependencies +// verify verify dependencies have expected content +// why explain why packages or modules are needed +// +// Use "go help mod " for more information about a command. +// +// Download modules to local cache +// +// Usage: +// +// go mod download [-json] [modules] +// +// Download downloads the named modules, which can be module patterns selecting +// dependencies of the main module or module queries of the form path@version. +// With no arguments, download applies to all dependencies of the main module. +// +// The go command will automatically download modules as needed during ordinary +// execution. The "go mod download" command is useful mainly for pre-filling +// the local cache or to compute the answers for a Go module proxy. +// +// By default, download reports errors to standard error but is otherwise silent. +// The -json flag causes download to print a sequence of JSON objects +// to standard output, describing each downloaded module (or failure), +// corresponding to this Go struct: +// +// type Module struct { +// Path string // module path +// Version string // module version +// Error string // error loading module +// Info string // absolute path to cached .info file +// GoMod string // absolute path to cached .mod file +// Zip string // absolute path to cached .zip file +// Dir string // absolute path to cached source root directory +// Sum string // checksum for path, version (as in go.sum) +// GoModSum string // checksum for go.mod (as in go.sum) +// } +// +// See 'go help modules' for more about module queries. +// +// +// Edit go.mod from tools or scripts +// +// Usage: +// +// go mod edit [editing flags] [go.mod] +// +// Edit provides a command-line interface for editing go.mod, +// for use primarily by tools or scripts. It reads only go.mod; +// it does not look up information about the modules involved. +// By default, edit reads and writes the go.mod file of the main module, +// but a different target file can be specified after the editing flags. +// +// The editing flags specify a sequence of editing operations. +// +// The -fmt flag reformats the go.mod file without making other changes. +// This reformatting is also implied by any other modifications that use or +// rewrite the go.mod file. The only time this flag is needed is if no other +// flags are specified, as in 'go mod edit -fmt'. +// +// The -module flag changes the module's path (the go.mod file's module line). +// +// The -require=path@version and -droprequire=path flags +// add and drop a requirement on the given module path and version. +// Note that -require overrides any existing requirements on path. +// These flags are mainly for tools that understand the module graph. +// Users should prefer 'go get path@version' or 'go get path@none', +// which make other go.mod adjustments as needed to satisfy +// constraints imposed by other modules. +// +// The -exclude=path@version and -dropexclude=path@version flags +// add and drop an exclusion for the given module path and version. +// Note that -exclude=path@version is a no-op if that exclusion already exists. +// +// The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags +// add and drop a replacement of the given module path and version pair. +// If the @v in old@v is omitted, the replacement applies to all versions +// with the old module path. If the @v in new@v is omitted, the new path +// should be a local module root directory, not a module path. +// Note that -replace overrides any existing replacements for old[@v]. +// +// The -require, -droprequire, -exclude, -dropexclude, -replace, +// and -dropreplace editing flags may be repeated, and the changes +// are applied in the order given. +// +// The -print flag prints the final go.mod in its text format instead of +// writing it back to go.mod. +// +// The -json flag prints the final go.mod file in JSON format instead of +// writing it back to go.mod. The JSON output corresponds to these Go types: +// +// type Module struct { +// Path string +// Version string +// } +// +// type GoMod struct { +// Module Module +// Require []Require +// Exclude []Module +// Replace []Replace +// } +// +// type Require struct { +// Path string +// Version string +// Indirect bool +// } +// +// type Replace struct { +// Old Module +// New Module +// } +// +// Note that this only describes the go.mod file itself, not other modules +// referred to indirectly. For the full set of modules available to a build, +// use 'go list -m -json all'. +// +// For example, a tool can obtain the go.mod as a data structure by +// parsing the output of 'go mod edit -json' and can then make changes +// by invoking 'go mod edit' with -require, -exclude, and so on. +// +// +// Print module requirement graph +// +// Usage: +// +// go mod graph +// +// Graph prints the module requirement graph (with replacements applied) +// in text form. Each line in the output has two space-separated fields: a module +// and one of its requirements. Each module is identified as a string of the form +// path@version, except for the main module, which has no @version suffix. +// +// +// Initialize new module in current directory +// +// Usage: +// +// go mod init [module] +// +// Init initializes and writes a new go.mod to the current directory, +// in effect creating a new module rooted at the current directory. +// The file go.mod must not already exist. +// If possible, init will guess the module path from import comments +// (see 'go help importpath') or from version control configuration. +// To override this guess, supply the module path as an argument. +// +// +// Add missing and remove unused modules +// +// Usage: +// +// go mod tidy [-v] +// +// Tidy makes sure go.mod matches the source code in the module. +// It adds any missing modules necessary to build the current module's +// packages and dependencies, and it removes unused modules that +// don't provide any relevant packages. It also adds any missing entries +// to go.sum and removes any unnecessary ones. +// +// The -v flag causes tidy to print information about removed modules +// to standard error. +// +// +// Make vendored copy of dependencies +// +// Usage: +// +// go mod vendor [-v] +// +// Vendor resets the main module's vendor directory to include all packages +// needed to build and test all the main module's packages. +// It does not include test code for vendored packages. +// +// The -v flag causes vendor to print the names of vendored +// modules and packages to standard error. +// +// +// Verify dependencies have expected content +// +// Usage: +// +// go mod verify +// +// Verify checks that the dependencies of the current module, +// which are stored in a local downloaded source cache, have not been +// modified since being downloaded. If all the modules are unmodified, +// verify prints "all modules verified." Otherwise it reports which +// modules have been changed and causes 'go mod' to exit with a +// non-zero status. +// +// +// Explain why packages or modules are needed +// +// Usage: +// +// go mod why [-m] [-vendor] packages... +// +// Why shows a shortest path in the import graph from the main module to +// each of the listed packages. If the -m flag is given, why treats the +// arguments as a list of modules and finds a path to any package in each +// of the modules. +// +// By default, why queries the graph of packages matched by "go list all", +// which includes tests for reachable packages. The -vendor flag causes why +// to exclude tests of dependencies. +// +// The output is a sequence of stanzas, one for each package or module +// name on the command line, separated by blank lines. Each stanza begins +// with a comment line "# package" or "# module" giving the target +// package or module. Subsequent lines give a path through the import +// graph, one package per line. If the package or module is not +// referenced from the main module, the stanza will display a single +// parenthesized note indicating that fact. +// +// For example: +// +// $ go mod why golang.org/x/text/language golang.org/x/text/encoding +// # golang.org/x/text/language +// rsc.io/quote +// rsc.io/sampler +// golang.org/x/text/language +// +// # golang.org/x/text/encoding +// (main module does not need package golang.org/x/text/encoding) +// $ +// // // Compile and run Go program // @@ -1064,11 +1428,18 @@ // GOCACHE // The directory where the go command will store cached // information for reuse in future builds. +// GOFLAGS +// A space-separated list of -flag=value settings to apply +// to go commands by default, when the given flag is known by +// the current command. Flags listed on the command-line +// are applied after this list and therefore override it. // GOOS // The operating system for which to compile code. // Examples are linux, darwin, windows, netbsd. // GOPATH // For more details see: 'go help gopath'. +// GOPROXY +// URL of Go module proxy. See 'go help goproxy'. // GORACE // Options for the race detector. // See https://golang.org/doc/articles/race_detector.html. @@ -1077,10 +1448,6 @@ // GOTMPDIR // The directory where the go command will write // temporary source files, packages, and binaries. -// GOTOOLDIR -// The directory where the go tools (compile, cover, doc, etc...) -// are installed. This is printed by go env, but setting the -// environment variable has no effect. // // Environment variables for use with cgo: // @@ -1150,6 +1517,20 @@ // with git fetch/clone. If set, any scheme not explicitly mentioned will be // considered insecure by 'go get'. // +// Additional information available from 'go env' but not read from the environment: +// +// GOEXE +// The executable file name suffix (".exe" on Windows, "" on other systems). +// GOHOSTARCH +// The architecture (GOARCH) of the Go toolchain binaries. +// GOHOSTOS +// The operating system (GOOS) of the Go toolchain binaries. +// GOMOD +// The absolute path to the go.mod of the main module, +// or the empty string if not using modules. +// GOTOOLDIR +// The directory where the go tools (compile, cover, doc, etc...) are installed. +// // // File types // @@ -1196,6 +1577,85 @@ // command. // // +// The go.mod file +// +// A module version is defined by a tree of source files, with a go.mod +// file in its root. When the go command is run, it looks in the current +// directory and then successive parent directories to find the go.mod +// marking the root of the main (current) module. +// +// The go.mod file itself is line-oriented, with // comments but +// no /* */ comments. Each line holds a single directive, made up of a +// verb followed by arguments. For example: +// +// module my/thing +// require other/thing v1.0.2 +// require new/thing v2.3.4 +// exclude old/thing v1.2.3 +// replace bad/thing v1.4.5 => good/thing v1.4.5 +// +// The verbs are module, to define the module path; require, to require +// a particular module at a given version or later; exclude, to exclude +// a particular module version from use; and replace, to replace a module +// version with a different module version. Exclude and replace apply only +// in the main module's go.mod and are ignored in dependencies. +// See https://research.swtch.com/vgo-mvs for details. +// +// The leading verb can be factored out of adjacent lines to create a block, +// like in Go imports: +// +// require ( +// new/thing v2.3.4 +// old/thing v1.2.3 +// ) +// +// The go.mod file is designed both to be edited directly and to be +// easily updated by tools. The 'go mod edit' command can be used to +// parse and edit the go.mod file from programs and tools. +// See 'go help mod edit'. +// +// The go command automatically updates go.mod each time it uses the +// module graph, to make sure go.mod always accurately reflects reality +// and is properly formatted. For example, consider this go.mod file: +// +// module M +// +// require ( +// A v1 +// B v1.0.0 +// C v1.0.0 +// D v1.2.3 +// E dev +// ) +// +// exclude D v1.2.3 +// +// The update rewrites non-canonical version identifiers to semver form, +// so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the +// latest commit on the dev branch, perhaps v0.0.0-20180523231146-b3f5c0f6e5f1. +// +// The update modifies requirements to respect exclusions, so the +// requirement on the excluded D v1.2.3 is updated to use the next +// available version of D, perhaps D v1.2.4 or D v1.3.0. +// +// The update removes redundant or misleading requirements. +// For example, if A v1.0.0 itself requires B v1.2.0 and C v1.0.0, +// then go.mod's requirement of B v1.0.0 is misleading (superseded by +// A's need for v1.2.0), and its requirement of C v1.0.0 is redundant +// (implied by A's need for the same version), so both will be removed. +// If module M contains packages that directly import packages from B or +// C, then the requirements will be kept but updated to the actual +// versions being used. +// +// Finally, the update reformats the go.mod in a canonical formatting, so +// that future mechanical changes will result in minimal diffs. +// +// Because the module graph defines the meaning of import statements, any +// commands that load packages also use and therefore update go.mod, +// including go build, go get, go install, go list, go test, go mod graph, +// go mod tidy, and go mod why. +// +// // GOPATH environment variable // // The Go path is used to resolve import statements. @@ -1262,6 +1722,12 @@ // // See https://golang.org/doc/code.html for an example. // +// GOPATH and Modules +// +// When using modules, GOPATH is no longer used for resolving imports. +// However, it is still used to store downloaded source code (in GOPATH/pkg/mod) +// and compiled commands (in GOPATH/bin). +// // Internal Directories // // Code in or below a directory named "internal" is importable only @@ -1345,6 +1811,69 @@ // See https://golang.org/s/go15vendor for details. // // +// Module proxy protocol +// +// The go command by default downloads modules from version control systems +// directly, just as 'go get' always has. The GOPROXY environment variable allows +// further control over the download source. If GOPROXY is unset, is the empty string, +// or is the string "direct", downloads use the default direct connection to version +// control systems. Setting GOPROXY to "off" disallows downloading modules from +// any source. Otherwise, GOPROXY is expected to be the URL of a module proxy, +// in which case the go command will fetch all modules from that proxy. +// No matter the source of the modules, downloaded modules must match existing +// entries in go.sum (see 'go help modules' for discussion of verification). +// +// A Go module proxy is any web server that can respond to GET requests for +// URLs of a specified form. The requests have no query parameters, so even +// a site serving from a fixed file system (including a file:/// URL) +// can be a module proxy. +// +// The GET requests sent to a Go module proxy are: +// +// GET $GOPROXY//@v/list returns a list of all known versions of the +// given module, one per line. +// +// GET $GOPROXY//@v/.info returns JSON-formatted metadata +// about that version of the given module. +// +// GET $GOPROXY//@v/.mod returns the go.mod file +// for that version of the given module. +// +// GET $GOPROXY//@v/.zip returns the zip archive +// for that version of the given module. +// +// To avoid problems when serving from case-sensitive file systems, +// the and elements are case-encoded, replacing every +// uppercase letter with an exclamation mark followed by the corresponding +// lower-case letter: github.com/Azure encodes as github.com/!azure. +// +// The JSON-formatted metadata about a given module corresponds to +// this Go data structure, which may be expanded in the future: +// +// type Info struct { +// Version string // version string +// Time time.Time // commit time +// } +// +// The zip archive for a specific version of a given module is a +// standard zip file that contains the file tree corresponding +// to the module's source code and related files. The archive uses +// slash-separated paths, and every file path in the archive must +// begin with @/, where the module and version are +// substituted directly, not case-encoded. The root of the module +// file tree corresponds to the @/ prefix in the +// archive. +// +// Even when downloading directly from version control systems, +// the go command synthesizes explicit info, mod, and zip files +// and stores them in its local cache, $GOPATH/pkg/mod/cache/download, +// the same as if it had downloaded them directly from a proxy. +// The cache layout is the same as the proxy URL space, so +// serving $GOPATH/pkg/mod/cache/download at (or copying it to) +// https://example.com/proxy would let other users access those +// cached module versions with GOPROXY=https://example.com/proxy. +// +// // Import path syntax // // An import path (see 'go help packages') denotes a package stored in the local @@ -1422,6 +1951,7 @@ // that repository. The supported version control systems are: // // Bazaar .bzr +// Fossil .fossil // Git .git // Mercurial .hg // Subversion .svn @@ -1465,7 +1995,7 @@ // In particular, it should appear before any raw JavaScript or CSS, // to avoid confusing the go command's restricted parser. // -// The vcs is one of "git", "hg", "svn", etc, +// The vcs is one of "bzr", "fossil", "git", "hg", "svn". // // The repo-root is the root of the version control system // containing a scheme and not containing a .vcs qualifier. @@ -1487,12 +2017,22 @@ // same meta tag and then git clone https://code.org/r/p/exproj into // GOPATH/src/example.org. // -// New downloaded packages are written to the first directory listed in the GOPATH -// environment variable (For more details see: 'go help gopath'). +// When using GOPATH, downloaded packages are written to the first directory +// listed in the GOPATH environment variable. +// (See 'go help gopath-get' and 'go help gopath'.) // -// The go command attempts to download the version of the -// package appropriate for the Go release being used. -// Run 'go help get' for more. +// When using modules, downloaded packages are stored in the module cache. +// (See 'go help modules-get' and 'go help goproxy'.) +// +// When using modules, an additional variant of the go-import meta tag is +// recognized and is preferred over those listing version control systems. +// That variant uses "mod" as the vcs in the content value, as in: +// +// +// +// This tag means to fetch modules with paths beginning with example.org +// from the module proxy available at the URL https://code.org/moduleproxy. +// See 'go help goproxy' for details about the proxy protocol. // // Import path checking // @@ -1515,10 +2055,484 @@ // This makes it possible to copy code into alternate locations in vendor trees // without needing to update import comments. // +// Import path checking is also disabled when using modules. +// Import path comments are obsoleted by the go.mod file's module statement. +// // See https://golang.org/s/go14customimport for details. // // -// Package lists +// Modules, module versions, and more +// +// A module is a collection of related Go packages. +// Modules are the unit of source code interchange and versioning. +// The go command has direct support for working with modules, +// including recording and resolving dependencies on other modules. +// Modules replace the old GOPATH-based approach to specifying +// which source files are used in a given build. +// +// Preliminary module support +// +// Go 1.11 includes preliminary support for Go modules, +// including a new module-aware 'go get' command. +// We intend to keep revising this support, while preserving compatibility, +// until it can be declared official (no longer preliminary), +// and then at a later point we may remove support for work +// in GOPATH and the old 'go get' command. +// +// The quickest way to take advantage of the new Go 1.11 module support +// is to check out your repository into a directory outside GOPATH/src, +// create a go.mod file (described in the next section) there, and run +// go commands from within that file tree. +// +// For more fine-grained control, the module support in Go 1.11 respects +// a temporary environment variable, GO111MODULE, which can be set to one +// of three string values: off, on, or auto (the default). +// If GO111MODULE=off, then the go command never uses the +// new module support. Instead it looks in vendor directories and GOPATH +// to find dependencies; we now refer to this as "GOPATH mode." +// If GO111MODULE=on, then the go command requires the use of modules, +// never consulting GOPATH. We refer to this as the command being +// module-aware or running in "module-aware mode". +// If GO111MODULE=auto or is unset, then the go command enables or +// disables module support based on the current directory. +// Module support is enabled only when the current directory is outside +// GOPATH/src and itself contains a go.mod file or is below a directory +// containing a go.mod file. +// +// In module-aware mode, GOPATH no longer defines the meaning of imports +// during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod) +// and installed commands (in GOPATH/bin, unless GOBIN is set). +// +// Defining a module +// +// A module is defined by a tree of Go source files with a go.mod file +// in the tree's root directory. The directory containing the go.mod file +// is called the module root. Typically the module root will also correspond +// to a source code repository root (but in general it need not). +// The module is the set of all Go packages in the module root and its +// subdirectories, but excluding subtrees with their own go.mod files. +// +// The "module path" is the import path prefix corresponding to the module root. +// The go.mod file defines the module path and lists the specific versions +// of other modules that should be used when resolving imports during a build, +// by giving their module paths and versions. +// +// For example, this go.mod declares that the directory containing it is the root +// of the module with path example.com/m, and it also declares that the module +// depends on specific versions of golang.org/x/text and gopkg.in/yaml.v2: +// +// module example.com/m +// +// require ( +// golang.org/x/text v0.3.0 +// gopkg.in/yaml.v2 v2.1.0 +// ) +// +// The go.mod file can also specify replacements and excluded versions +// that only apply when building the module directly; they are ignored +// when the module is incorporated into a larger build. +// For more about the go.mod file, see 'go help go.mod'. +// +// To start a new module, simply create a go.mod file in the root of the +// module's directory tree, containing only a module statement. +// The 'go mod init' command can be used to do this: +// +// go mod init example.com/m +// +// In a project already using an existing dependency management tool like +// godep, glide, or dep, 'go mod init' will also add require statements +// matching the existing configuration. +// +// Once the go.mod file exists, no additional steps are required: +// go commands like 'go build', 'go test', or even 'go list' will automatically +// add new dependencies as needed to satisfy imports. +// +// The main module and the build list +// +// The "main module" is the module containing the directory where the go command +// is run. The go command finds the module root by looking for a go.mod in the +// current directory, or else the current directory's parent directory, +// or else the parent's parent directory, and so on. +// +// The main module's go.mod file defines the precise set of packages available +// for use by the go command, through require, replace, and exclude statements. +// Dependency modules, found by following require statements, also contribute +// to the definition of that set of packages, but only through their go.mod +// files' require statements: any replace and exclude statements in dependency +// modules are ignored. The replace and exclude statements therefore allow the +// main module complete control over its own build, without also being subject +// to complete control by dependencies. +// +// The set of modules providing packages to builds is called the "build list". +// The build list initially contains only the main module. Then the go command +// adds to the list the exact module versions required by modules already +// on the list, recursively, until there is nothing left to add to the list. +// If multiple versions of a particular module are added to the list, +// then at the end only the latest version (according to semantic version +// ordering) is kept for use in the build. +// +// The 'go list' command provides information about the main module +// and the build list. For example: +// +// go list -m # print path of main module +// go list -m -f={{.Dir}} # print root directory of main module +// go list -m all # print build list +// +// Maintaining module requirements +// +// The go.mod file is meant to be readable and editable by both +// programmers and tools. The go command itself automatically updates the go.mod file +// to maintain a standard formatting and the accuracy of require statements. +// +// Any go command that finds an unfamiliar import will look up the module +// containing that import and add the latest version of that module +// to go.mod automatically. In most cases, therefore, it suffices to +// add an import to source code and run 'go build', 'go test', or even 'go list': +// as part of analyzing the package, the go command will discover +// and resolve the import and update the go.mod file. +// +// Any go command can determine that a module requirement is +// missing and must be added, even when considering only a single +// package from the module. On the other hand, determining that a module requirement +// is no longer necessary and can be deleted requires a full view of +// all packages in the module, across all possible build configurations +// (architectures, operating systems, build tags, and so on). +// The 'go mod tidy' command builds that view and then +// adds any missing module requirements and removes unnecessary ones. +// +// As part of maintaining the require statements in go.mod, the go command +// tracks which ones provide packages imported directly by the current module +// and which ones provide packages only used indirectly by other module +// dependencies. Requirements needed only for indirect uses are marked with a +// "// indirect" comment in the go.mod file. Indirect requirements are +// automatically removed from the go.mod file once they are implied by other +// direct requirements. Indirect requirements only arise when using modules +// that fail to state some of their own dependencies or when explicitly +// upgrading a module's dependencies ahead of its own stated requirements. +// +// Because of this automatic maintenance, the information in go.mod is an +// up-to-date, readable description of the build. +// +// The 'go get' command updates go.mod to change the module versions used in a +// build. An upgrade of one module may imply upgrading others, and similarly a +// downgrade of one module may imply downgrading others. The 'go get' command +// makes these implied changes as well. If go.mod is edited directly, commands +// like 'go build' or 'go list' will assume that an upgrade is intended and +// automatically make any implied upgrades and update go.mod to reflect them. +// +// The 'go mod' command provides other functionality for use in maintaining +// and understanding modules and go.mod files. See 'go help mod'. +// +// The -mod build flag provides additional control over updating and use of go.mod. +// +// If invoked with -mod=readonly, the go command is disallowed from the implicit +// automatic updating of go.mod described above. Instead, it fails when any changes +// to go.mod are needed. This setting is most useful to check that go.mod does +// not need updates, such as in a continuous integration and testing system. +// The "go get" command remains permitted to update go.mod even with -mod=readonly, +// and the "go mod" commands do not take the -mod flag (or any other build flags). +// +// If invoked with -mod=vendor, the go command assumes that the vendor +// directory holds the correct copies of dependencies and ignores +// the dependency descriptions in go.mod. +// +// Pseudo-versions +// +// The go.mod file and the go command more generally use semantic versions as +// the standard form for describing module versions, so that versions can be +// compared to determine which should be considered earlier or later than another. +// A module version like v1.2.3 is introduced by tagging a revision in the +// underlying source repository. Untagged revisions can be referred to +// using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef, +// where the time is the commit time in UTC and the final suffix is the prefix +// of the commit hash. The time portion ensures that two pseudo-versions can +// be compared to determine which happened later, the commit hash identifes +// the underlying commit, and the prefix (v0.0.0- in this example) is derived from +// the most recent tagged version in the commit graph before this commit. +// +// There are three pseudo-version forms: +// +// vX.0.0-yyyymmddhhmmss-abcdefabcdef is used when there is no earlier +// versioned commit with an appropriate major version before the target commit. +// (This was originally the only form, so some older go.mod files use this form +// even for commits that do follow tags.) +// +// vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef is used when the most +// recent versioned commit before the target commit is vX.Y.Z-pre. +// +// vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef is used when the most +// recent versioned commit before the target commit is vX.Y.Z. +// +// Pseudo-versions never need to be typed by hand: the go command will accept +// the plain commit hash and translate it into a pseudo-version (or a tagged +// version if available) automatically. This conversion is an example of a +// module query. +// +// Module queries +// +// The go command accepts a "module query" in place of a module version +// both on the command line and in the main module's go.mod file. +// (After evaluating a query found in the main module's go.mod file, +// the go command updates the file to replace the query with its result.) +// +// A fully-specified semantic version, such as "v1.2.3", +// evaluates to that specific version. +// +// A semantic version prefix, such as "v1" or "v1.2", +// evaluates to the latest available tagged version with that prefix. +// +// A semantic version comparison, such as "=v1.5.6", +// evaluates to the available tagged version nearest to the comparison target +// (the latest version for < and <=, the earliest version for > and >=). +// +// The string "latest" matches the latest available tagged version, +// or else the underlying source repository's latest untagged revision. +// +// A revision identifier for the underlying source repository, +// such as a commit hash prefix, revision tag, or branch name, +// selects that specific code revision. If the revision is +// also tagged with a semantic version, the query evaluates to +// that semantic version. Otherwise the query evaluates to a +// pseudo-version for the commit. +// +// All queries prefer release versions to pre-release versions. +// For example, ">`+tg.path("pkg-config.out")) } } +func TestCgoCache(t *testing.T) { + if !canCgo { + t.Skip("no cgo") + } + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/a.go", `package main + // #ifndef VAL + // #define VAL 0 + // #endif + // int val = VAL; + import "C" + import "fmt" + func main() { fmt.Println(C.val) } + `) + tg.setenv("GOPATH", tg.path(".")) + exe := tg.path("x.exe") + tg.run("build", "-o", exe, "x") + tg.setenv("CGO_LDFLAGS", "-lnosuchlibraryexists") + tg.runFail("build", "-o", exe, "x") + tg.grepStderr(`nosuchlibraryexists`, "did not run linker with changed CGO_LDFLAGS") +} + // Issue 23982 func TestFilepathUnderCwdFormat(t *testing.T) { tg := testgo(t) @@ -6381,15 +6070,14 @@ func TestNoRelativeTmpdir(t *testing.T) { tg.setenv("GOCACHE", "off") tg.setenv("GOPATH", tg.path(".")) tg.setenv("GOTMPDIR", "tmp") - tg.runFail("build", "a") - tg.grepStderr("relative tmpdir", "wrong error") + tg.run("build", "-work", "a") + tg.grepStderr("WORK=[^t]", "work should be absolute path") - if runtime.GOOS != "windows" && runtime.GOOS != "plan9" { - tg.unsetenv("GOTMPDIR") - tg.setenv("TMPDIR", "tmp") - tg.runFail("build", "a") - tg.grepStderr("relative tmpdir", "wrong error") - } + tg.unsetenv("GOTMPDIR") + tg.setenv("TMP", "tmp") // windows + tg.setenv("TMPDIR", "tmp") // unix + tg.run("build", "-work", "a") + tg.grepStderr("WORK=[^t]", "work should be absolute path") } // Issue 24704. @@ -6473,6 +6161,16 @@ func TestCDAndGOPATHAreDifferent(t *testing.T) { } } +// Issue 26242. +func TestGoTestWithoutTests(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("test", "testnorun") + tg.grepStdout(`testnorun\t\[no test files\]`, "do not want test to run") +} + // Issue 25579. func TestGoBuildDashODevNull(t *testing.T) { tg := testgo(t) @@ -6483,3 +6181,23 @@ func TestGoBuildDashODevNull(t *testing.T) { tg.mustNotExist("hello") tg.mustNotExist("hello.exe") } + +// Issue 25093. +func TestCoverpkgTestOnly(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/a/a.go", `package a + func F(i int) int { + return i*i + }`) + tg.tempFile("src/atest/a_test.go", ` + package a_test + import ( "a"; "testing" ) + func TestF(t *testing.T) { a.F(2) } + `) + tg.setenv("GOPATH", tg.path(".")) + tg.run("test", "-coverpkg=a", "atest") + tg.grepStderrNot("no packages being tested depend on matches", "bad match message") + tg.grepStdout("coverage: 100", "no coverage") +} diff --git a/src/cmd/go/go_windows_test.go b/src/cmd/go/go_windows_test.go index f278741c8b..99af3d43dc 100644 --- a/src/cmd/go/go_windows_test.go +++ b/src/cmd/go/go_windows_test.go @@ -97,7 +97,7 @@ func TestACL(t *testing.T) { // will make all files created in TestACL/tmp have different // security attributes to the files created in TestACL. runIcacls(t, newtmpdir, - "/grant", "guest:(oi)(ci)f", // add Guest user to have full access + "/grant", "*S-1-5-32-546:(oi)(ci)f", // add Guests group to have full access ) src := filepath.Join(tmpdir, "main.go") diff --git a/src/cmd/go/help_test.go b/src/cmd/go/help_test.go new file mode 100644 index 0000000000..ec6a9d11cb --- /dev/null +++ b/src/cmd/go/help_test.go @@ -0,0 +1,28 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !nacl + +package main_test + +import ( + "bytes" + "io/ioutil" + "testing" + + "cmd/go/internal/help" +) + +func TestDocsUpToDate(t *testing.T) { + buf := new(bytes.Buffer) + // Match the command in mkalldocs.sh that generates alldocs.go. + help.Help(buf, []string{"documentation"}) + data, err := ioutil.ReadFile("alldocs.go") + if err != nil { + t.Fatalf("error reading alldocs.go: %v", err) + } + if !bytes.Equal(data, buf.Bytes()) { + t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it") + } +} diff --git a/src/cmd/go/internal/base/base.go b/src/cmd/go/internal/base/base.go index 286efbc041..e7f54c9a36 100644 --- a/src/cmd/go/internal/base/base.go +++ b/src/cmd/go/internal/base/base.go @@ -45,25 +45,43 @@ type Command struct { // CustomFlags indicates that the command will do its own // flag parsing. CustomFlags bool + + // Commands lists the available commands and help topics. + // The order here is the order in which they are printed by 'go help'. + // Note that subcommands are in general best avoided. + Commands []*Command } -// Commands lists the available commands and help topics. -// The order here is the order in which they are printed by 'go help'. -var Commands []*Command +var Go = &Command{ + UsageLine: "go", + Long: `Go is a tool for managing Go source code.`, + // Commands initialized in package main +} -// Name returns the command's name: the first word in the usage line. -func (c *Command) Name() string { +// LongName returns the command's long name: all the words in the usage line between "go" and a flag or argument, +func (c *Command) LongName() string { name := c.UsageLine - i := strings.Index(name, " ") - if i >= 0 { + if i := strings.Index(name, " ["); i >= 0 { name = name[:i] } + if name == "go" { + return "" + } + return strings.TrimPrefix(name, "go ") +} + +// Name returns the command's short name: the last word in the usage line before a flag or argument. +func (c *Command) Name() string { + name := c.LongName() + if i := strings.LastIndex(name, " "); i >= 0 { + name = name[i+1:] + } return name } func (c *Command) Usage() { fmt.Fprintf(os.Stderr, "usage: %s\n", c.UsageLine) - fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.Name()) + fmt.Fprintf(os.Stderr, "Run 'go help %s' for details.\n", c.LongName()) os.Exit(2) } diff --git a/src/cmd/go/internal/base/goflags.go b/src/cmd/go/internal/base/goflags.go new file mode 100644 index 0000000000..2f50b50bfc --- /dev/null +++ b/src/cmd/go/internal/base/goflags.go @@ -0,0 +1,152 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package base + +import ( + "flag" + "fmt" + "os" + "runtime" + "strings" + + "cmd/go/internal/cfg" +) + +var ( + goflags []string // cached $GOFLAGS list; can be -x or --x form + knownFlag = make(map[string]bool) // flags allowed to appear in $GOFLAGS; no leading dashes +) + +// AddKnownFlag adds name to the list of known flags for use in $GOFLAGS. +func AddKnownFlag(name string) { + knownFlag[name] = true +} + +// GOFLAGS returns the flags from $GOFLAGS. +// The list can be assumed to contain one string per flag, +// with each string either beginning with -name or --name. +func GOFLAGS() []string { + InitGOFLAGS() + return goflags +} + +// InitGOFLAGS initializes the goflags list from $GOFLAGS. +// If goflags is already initialized, it does nothing. +func InitGOFLAGS() { + if goflags != nil { // already initialized + return + } + + // Build list of all flags for all commands. + // If no command has that flag, then we report the problem. + // This catches typos while still letting users record flags in GOFLAGS + // that only apply to a subset of go commands. + // Commands using CustomFlags can report their flag names + // by calling AddKnownFlag instead. + var walkFlags func(*Command) + walkFlags = func(cmd *Command) { + for _, sub := range cmd.Commands { + walkFlags(sub) + } + cmd.Flag.VisitAll(func(f *flag.Flag) { + knownFlag[f.Name] = true + }) + } + walkFlags(Go) + + // Ignore bad flag in go env and go bug, because + // they are what people reach for when debugging + // a problem, and maybe they're debugging GOFLAGS. + // (Both will show the GOFLAGS setting if let succeed.) + hideErrors := cfg.CmdName == "env" || cfg.CmdName == "bug" + + goflags = strings.Fields(os.Getenv("GOFLAGS")) + if goflags == nil { + goflags = []string{} // avoid work on later InitGOFLAGS call + } + + // Each of the words returned by strings.Fields must be its own flag. + // To set flag arguments use -x=value instead of -x value. + // For boolean flags, -x is fine instead of -x=true. + for _, f := range goflags { + // Check that every flag looks like -x --x -x=value or --x=value. + if !strings.HasPrefix(f, "-") || f == "-" || f == "--" || strings.HasPrefix(f, "---") || strings.HasPrefix(f, "-=") || strings.HasPrefix(f, "--=") { + if hideErrors { + continue + } + Fatalf("go: parsing $GOFLAGS: non-flag %q", f) + } + + name := f[1:] + if name[0] == '-' { + name = name[1:] + } + if i := strings.Index(name, "="); i >= 0 { + name = name[:i] + } + if !knownFlag[name] { + if hideErrors { + continue + } + Fatalf("go: parsing $GOFLAGS: unknown flag -%s", name) + } + } +} + +// boolFlag is the optional interface for flag.Value known to the flag package. +// (It is not clear why package flag does not export this interface.) +type boolFlag interface { + flag.Value + IsBoolFlag() bool +} + +// SetFromGOFLAGS sets the flags in the given flag set using settings in $GOFLAGS. +func SetFromGOFLAGS(flags flag.FlagSet) { + InitGOFLAGS() + + // This loop is similar to flag.Parse except that it ignores + // unknown flags found in goflags, so that setting, say, GOFLAGS=-ldflags=-w + // does not break commands that don't have a -ldflags. + // It also adjusts the output to be clear that the reported problem is from $GOFLAGS. + where := "$GOFLAGS" + if runtime.GOOS == "windows" { + where = "%GOFLAGS%" + } + for _, goflag := range goflags { + name, value, hasValue := goflag, "", false + if i := strings.Index(goflag, "="); i >= 0 { + name, value, hasValue = goflag[:i], goflag[i+1:], true + } + if strings.HasPrefix(name, "--") { + name = name[1:] + } + f := flags.Lookup(name[1:]) + if f == nil { + continue + } + if fb, ok := f.Value.(boolFlag); ok && fb.IsBoolFlag() { + if hasValue { + if err := fb.Set(value); err != nil { + fmt.Fprintf(flags.Output(), "go: invalid boolean value %q for flag %s (from %s): %v\n", value, name, where, err) + flags.Usage() + } + } else { + if err := fb.Set("true"); err != nil { + fmt.Fprintf(flags.Output(), "go: invalid boolean flag %s (from %s): %v\n", name, where, err) + flags.Usage() + } + } + } else { + if !hasValue { + fmt.Fprintf(flags.Output(), "go: flag needs an argument: %s (from %s)\n", name, where) + flags.Usage() + } + if err := f.Value.Set(value); err != nil { + fmt.Fprintf(flags.Output(), "go: invalid value %q for flag %s (from %s): %v\n", value, name, where, err) + flags.Usage() + } + } + } +} diff --git a/src/cmd/go/internal/bug/bug.go b/src/cmd/go/internal/bug/bug.go index 963da94c49..e701f6eac9 100644 --- a/src/cmd/go/internal/bug/bug.go +++ b/src/cmd/go/internal/bug/bug.go @@ -25,7 +25,7 @@ import ( var CmdBug = &base.Command{ Run: runBug, - UsageLine: "bug", + UsageLine: "go bug", Short: "start a bug report", Long: ` Bug opens the default browser and starts a new bug report. @@ -38,6 +38,9 @@ func init() { } func runBug(cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go bug: bug takes no arguments") + } var buf bytes.Buffer buf.WriteString(bugHeader) inspectGoVersion(&buf) diff --git a/src/cmd/go/internal/cache/default.go b/src/cmd/go/internal/cache/default.go index 9728376225..02fc1e896f 100644 --- a/src/cmd/go/internal/cache/default.go +++ b/src/cmd/go/internal/cache/default.go @@ -35,12 +35,14 @@ See golang.org to learn more about Go. // initDefaultCache does the work of finding the default cache // the first time Default is called. func initDefaultCache() { - dir := DefaultDir() + dir, showWarnings := defaultDir() if dir == "off" { return } if err := os.MkdirAll(dir, 0777); err != nil { - fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + if showWarnings { + fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + } return } if _, err := os.Stat(filepath.Join(dir, "README")); err != nil { @@ -50,7 +52,9 @@ func initDefaultCache() { c, err := Open(dir) if err != nil { - fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + if showWarnings { + fmt.Fprintf(os.Stderr, "go: disabling cache (%s) due to initialization failure: %s\n", dir, err) + } return } defaultCache = c @@ -59,14 +63,24 @@ func initDefaultCache() { // DefaultDir returns the effective GOCACHE setting. // It returns "off" if the cache is disabled. func DefaultDir() string { + dir, _ := defaultDir() + return dir +} + +// defaultDir returns the effective GOCACHE setting. +// It returns "off" if the cache is disabled. +// The second return value reports whether warnings should +// be shown if the cache fails to initialize. +func defaultDir() (string, bool) { dir := os.Getenv("GOCACHE") if dir != "" { - return dir + return dir, true } // Compute default location. // TODO(rsc): This code belongs somewhere else, // like maybe ioutil.CacheDir or os.CacheDir. + showWarnings := true switch runtime.GOOS { case "windows": dir = os.Getenv("LocalAppData") @@ -76,20 +90,20 @@ func DefaultDir() string { dir = os.Getenv("AppData") } if dir == "" { - return "off" + return "off", true } case "darwin": dir = os.Getenv("HOME") if dir == "" { - return "off" + return "off", true } dir += "/Library/Caches" case "plan9": dir = os.Getenv("home") if dir == "" { - return "off" + return "off", true } // Plan 9 has no established per-user cache directory, // but $home/lib/xyz is the usual equivalent of $HOME/.xyz on Unix. @@ -101,10 +115,15 @@ func DefaultDir() string { if dir == "" { dir = os.Getenv("HOME") if dir == "" { - return "off" + return "off", true + } + if dir == "/" { + // probably docker run with -u flag + // https://golang.org/issue/26280 + showWarnings = false } dir += "/.cache" } } - return filepath.Join(dir, "go-build") + return filepath.Join(dir, "go-build"), showWarnings } diff --git a/src/cmd/go/internal/cache/default_unix_test.go b/src/cmd/go/internal/cache/default_unix_test.go new file mode 100644 index 0000000000..1458201f4b --- /dev/null +++ b/src/cmd/go/internal/cache/default_unix_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !windows,!darwin,!plan9 + +package cache + +import ( + "os" + "strings" + "testing" +) + +func TestDefaultDir(t *testing.T) { + goCacheDir := "/tmp/test-go-cache" + xdgCacheDir := "/tmp/test-xdg-cache" + homeDir := "/tmp/test-home" + + // undo env changes when finished + defer func(GOCACHE, XDG_CACHE_HOME, HOME string) { + os.Setenv("GOCACHE", GOCACHE) + os.Setenv("XDG_CACHE_HOME", XDG_CACHE_HOME) + os.Setenv("HOME", HOME) + }(os.Getenv("GOCACHE"), os.Getenv("XDG_CACHE_HOME"), os.Getenv("HOME")) + + os.Setenv("GOCACHE", goCacheDir) + os.Setenv("XDG_CACHE_HOME", xdgCacheDir) + os.Setenv("HOME", homeDir) + + dir, showWarnings := defaultDir() + if dir != goCacheDir { + t.Errorf("Cache DefaultDir %q should be $GOCACHE %q", dir, goCacheDir) + } + if !showWarnings { + t.Error("Warnings should be shown when $GOCACHE is set") + } + + os.Unsetenv("GOCACHE") + dir, showWarnings = defaultDir() + if !strings.HasPrefix(dir, xdgCacheDir+"/") { + t.Errorf("Cache DefaultDir %q should be under $XDG_CACHE_HOME %q when $GOCACHE is unset", dir, xdgCacheDir) + } + if !showWarnings { + t.Error("Warnings should be shown when $XDG_CACHE_HOME is set") + } + + os.Unsetenv("XDG_CACHE_HOME") + dir, showWarnings = defaultDir() + if !strings.HasPrefix(dir, homeDir+"/.cache/") { + t.Errorf("Cache DefaultDir %q should be under $HOME/.cache %q when $GOCACHE and $XDG_CACHE_HOME are unset", dir, homeDir+"/.cache") + } + if !showWarnings { + t.Error("Warnings should be shown when $HOME is not /") + } + + os.Unsetenv("HOME") + if dir, _ := defaultDir(); dir != "off" { + t.Error("Cache not disabled when $GOCACHE, $XDG_CACHE_HOME, and $HOME are unset") + } + + os.Setenv("HOME", "/") + if _, showWarnings := defaultDir(); showWarnings { + // https://golang.org/issue/26280 + t.Error("Cache initialization warnings should be squelched when $GOCACHE and $XDG_CACHE_HOME are unset and $HOME is /") + } +} diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index b7906bb1db..8dc4d1fbd2 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -20,7 +20,8 @@ import ( var ( BuildA bool // -a flag BuildBuildmode string // -buildmode flag - BuildContext = build.Default + BuildContext = defaultContext() + BuildMod string // -mod flag BuildI bool // -i flag BuildLinkshared bool // -linkshared flag BuildMSan bool // -msan flag @@ -42,6 +43,12 @@ var ( DebugActiongraph string // -debug-actiongraph flag (undocumented, unstable) ) +func defaultContext() build.Context { + ctxt := build.Default + ctxt.JoinPath = filepath.Join // back door to say "do not use go command" + return ctxt +} + func init() { BuildToolchainCompiler = func() string { return "missing-compiler" } BuildToolchainLinker = func() string { return "missing-linker" } @@ -67,6 +74,16 @@ var ( Goos = BuildContext.GOOS ExeSuffix string Gopath = filepath.SplitList(BuildContext.GOPATH) + + // ModulesEnabled specifies whether the go command is running + // in module-aware mode (as opposed to GOPATH mode). + // It is equal to modload.Enabled, but not all packages can import modload. + ModulesEnabled bool + + // GoModInGOPATH records whether we've found a go.mod in GOPATH/src + // in GO111MODULE=auto mode. In that case, we don't use modules + // but people might expect us to, so 'go get' warns. + GoModInGOPATH string ) func init() { diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go index fa5af944af..d023592eed 100644 --- a/src/cmd/go/internal/clean/clean.go +++ b/src/cmd/go/internal/clean/clean.go @@ -17,11 +17,13 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" "cmd/go/internal/work" ) var CmdClean = &base.Command{ - UsageLine: "clean [-i] [-r] [-n] [-x] [-cache] [-testcache] [build flags] [packages]", + UsageLine: "go clean [clean flags] [build flags] [packages]", Short: "remove object files and cached files", Long: ` Clean removes object files from package source directories. @@ -65,6 +67,10 @@ The -cache flag causes clean to remove the entire go build cache. The -testcache flag causes clean to expire all test results in the go build cache. +The -modcache flag causes clean to remove the entire module +download cache, including unpacked source code of versioned +dependencies. + For more about build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. @@ -75,6 +81,7 @@ var ( cleanI bool // clean -i flag cleanR bool // clean -r flag cleanCache bool // clean -cache flag + cleanModcache bool // clean -modcache flag cleanTestcache bool // clean -testcache flag ) @@ -85,6 +92,7 @@ func init() { CmdClean.Flag.BoolVar(&cleanI, "i", false, "") CmdClean.Flag.BoolVar(&cleanR, "r", false, "") CmdClean.Flag.BoolVar(&cleanCache, "cache", false, "") + CmdClean.Flag.BoolVar(&cleanModcache, "modcache", false, "") CmdClean.Flag.BoolVar(&cleanTestcache, "testcache", false, "") // -n and -x are important enough to be @@ -95,8 +103,13 @@ func init() { } func runClean(cmd *base.Command, args []string) { - for _, pkg := range load.PackagesAndErrors(args) { - clean(pkg) + if len(args) == 0 && modload.Failed() { + // Don't try to clean current directory, + // which will cause modload to base.Fatalf. + } else { + for _, pkg := range load.PackagesAndErrors(args) { + clean(pkg) + } } if cleanCache { @@ -138,6 +151,29 @@ func runClean(cmd *base.Command, args []string) { } } } + + if cleanModcache { + if modfetch.PkgMod == "" { + base.Fatalf("go clean -modcache: no module cache") + } + if err := removeAll(modfetch.PkgMod); err != nil { + base.Errorf("go clean -modcache: %v", err) + } + } +} + +func removeAll(dir string) error { + // Module cache has 0555 directories; make them writable in order to remove content. + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil // ignore errors walking in file system + } + if info.IsDir() { + os.Chmod(path, 0777) + } + return nil + }) + return os.RemoveAll(dir) } var cleaned = map[*load.Package]bool{} diff --git a/src/cmd/go/internal/cmdflag/flag.go b/src/cmd/go/internal/cmdflag/flag.go index 7ab3022127..b2a67e6f74 100644 --- a/src/cmd/go/internal/cmdflag/flag.go +++ b/src/cmd/go/internal/cmdflag/flag.go @@ -69,6 +69,14 @@ func SyntaxError(cmd, msg string) { os.Exit(2) } +// AddKnownFlags registers the flags in defns with base.AddKnownFlag. +func AddKnownFlags(cmd string, defns []*Defn) { + for _, f := range defns { + base.AddKnownFlag(f.Name) + base.AddKnownFlag(cmd + "." + f.Name) + } +} + // Parse sees if argument i is present in the definitions and if so, // returns its definition, value, and whether it consumed an extra word. // If the flag begins (cmd+".") it is ignored for the purpose of this function. @@ -121,3 +129,31 @@ func Parse(cmd string, defns []*Defn, args []string, i int) (f *Defn, value stri f = nil return } + +// FindGOFLAGS extracts and returns the flags matching defns from GOFLAGS. +// Ideally the caller would mention that the flags were from GOFLAGS +// when reporting errors, but that's too hard for now. +func FindGOFLAGS(defns []*Defn) []string { + var flags []string + for _, flag := range base.GOFLAGS() { + // Flags returned by base.GOFLAGS are well-formed, one of: + // -x + // --x + // -x=value + // --x=value + if strings.HasPrefix(flag, "--") { + flag = flag[1:] + } + name := flag[1:] + if i := strings.Index(name, "="); i >= 0 { + name = name[:i] + } + for _, f := range defns { + if name == f.Name { + flags = append(flags, flag) + break + } + } + } + return flags +} diff --git a/src/cmd/go/internal/doc/doc.go b/src/cmd/go/internal/doc/doc.go index d73dd9ad91..4e7dca082d 100644 --- a/src/cmd/go/internal/doc/doc.go +++ b/src/cmd/go/internal/doc/doc.go @@ -12,7 +12,7 @@ import ( var CmdDoc = &base.Command{ Run: runDoc, - UsageLine: "doc [-u] [-c] [package|[package.]symbol[.methodOrField]]", + UsageLine: "go doc [-u] [-c] [package|[package.]symbol[.methodOrField]]", CustomFlags: true, Short: "show documentation for package or symbol", Long: ` diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index bd66a98f21..afadbade38 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -9,6 +9,7 @@ import ( "encoding/json" "fmt" "os" + "path/filepath" "runtime" "strings" @@ -16,12 +17,12 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" - "cmd/go/internal/vgo" + "cmd/go/internal/modload" "cmd/go/internal/work" ) var CmdEnv = &base.Command{ - UsageLine: "env [-json] [var ...]", + UsageLine: "go env [-json] [var ...]", Short: "print Go environment information", Long: ` Env prints Go environment information. @@ -53,6 +54,7 @@ func MkEnv() []cfg.EnvVar { {Name: "GOBIN", Value: cfg.GOBIN}, {Name: "GOCACHE", Value: cache.DefaultDir()}, {Name: "GOEXE", Value: cfg.ExeSuffix}, + {Name: "GOFLAGS", Value: os.Getenv("GOFLAGS")}, {Name: "GOHOSTARCH", Value: runtime.GOARCH}, {Name: "GOHOSTOS", Value: runtime.GOOS}, {Name: "GOOS", Value: cfg.Goos}, @@ -62,9 +64,6 @@ func MkEnv() []cfg.EnvVar { {Name: "GOROOT", Value: cfg.GOROOT}, {Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")}, {Name: "GOTOOLDIR", Value: base.ToolDir}, - - // disable escape codes in clang errors - {Name: "TERM", Value: "dumb"}, } if work.GccgoBin != "" { @@ -115,6 +114,18 @@ func findEnv(env []cfg.EnvVar, name string) string { // ExtraEnvVars returns environment variables that should not leak into child processes. func ExtraEnvVars() []cfg.EnvVar { + gomod := "" + if modload.Init(); modload.ModRoot != "" { + gomod = filepath.Join(modload.ModRoot, "go.mod") + } + return []cfg.EnvVar{ + {Name: "GOMOD", Value: gomod}, + } +} + +// ExtraEnvVarsCostly returns environment variables that should not leak into child processes +// but are costly to evaluate. +func ExtraEnvVarsCostly() []cfg.EnvVar { var b work.Builder b.Init() cppflags, cflags, cxxflags, fflags, ldflags, err := b.CFlags(&load.Package{}) @@ -124,6 +135,7 @@ func ExtraEnvVars() []cfg.EnvVar { return nil } cmd := b.GccCmd(".", "") + return []cfg.EnvVar{ // Note: Update the switch in runEnv below when adding to this list. {Name: "CGO_CFLAGS", Value: strings.Join(cflags, " ")}, @@ -133,19 +145,19 @@ func ExtraEnvVars() []cfg.EnvVar { {Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")}, {Name: "PKG_CONFIG", Value: b.PkgconfigCmd()}, {Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")}, - {Name: "VGOMODROOT", Value: vgo.ModRoot}, } } func runEnv(cmd *base.Command, args []string) { env := cfg.CmdEnv + env = append(env, ExtraEnvVars()...) - // Do we need to call ExtraEnvVars, which is a bit expensive? + // Do we need to call ExtraEnvVarsCostly, which is a bit expensive? // Only if we're listing all environment variables ("go env") // or the variables being requested are in the extra list. - needExtra := true + needCostly := true if len(args) > 0 { - needExtra = false + needCostly = false for _, arg := range args { switch arg { case "CGO_CFLAGS", @@ -155,12 +167,12 @@ func runEnv(cmd *base.Command, args []string) { "CGO_LDFLAGS", "PKG_CONFIG", "GOGCCFLAGS": - needExtra = true + needCostly = true } } } - if needExtra { - env = append(env, ExtraEnvVars()...) + if needCostly { + env = append(env, ExtraEnvVarsCostly()...) } if len(args) > 0 { diff --git a/src/cmd/go/internal/fix/fix.go b/src/cmd/go/internal/fix/fix.go index 56f88329ab..aab164148f 100644 --- a/src/cmd/go/internal/fix/fix.go +++ b/src/cmd/go/internal/fix/fix.go @@ -9,15 +9,15 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/modload" "cmd/go/internal/str" - "cmd/go/internal/vgo" "fmt" "os" ) var CmdFix = &base.Command{ Run: runFix, - UsageLine: "fix [packages]", + UsageLine: "go fix [packages]", Short: "update packages to use new APIs", Long: ` Fix runs the Go fix command on the packages named by the import paths. @@ -34,9 +34,9 @@ See also: go fmt, go vet. func runFix(cmd *base.Command, args []string) { printed := false for _, pkg := range load.Packages(args) { - if vgo.Enabled() && !pkg.Module.Top { + if modload.Enabled() && !pkg.Module.Main { if !printed { - fmt.Fprintf(os.Stderr, "vgo: not fixing packages in dependency modules\n") + fmt.Fprintf(os.Stderr, "go: not fixing packages in dependency modules\n") printed = true } continue diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go index c3a90d069c..8e4ef37281 100644 --- a/src/cmd/go/internal/fmtcmd/fmt.go +++ b/src/cmd/go/internal/fmtcmd/fmt.go @@ -16,8 +16,8 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/modload" "cmd/go/internal/str" - "cmd/go/internal/vgo" ) func init() { @@ -26,7 +26,7 @@ func init() { var CmdFmt = &base.Command{ Run: runFmt, - UsageLine: "fmt [-n] [-x] [packages]", + UsageLine: "go fmt [-n] [-x] [packages]", Short: "gofmt (reformat) package sources", Long: ` Fmt runs the command 'gofmt -l -w' on the packages named @@ -60,9 +60,9 @@ func runFmt(cmd *base.Command, args []string) { }() } for _, pkg := range load.PackagesAndErrors(args) { - if vgo.Enabled() && !pkg.Module.Top { + if modload.Enabled() && pkg.Module != nil && !pkg.Module.Main { if !printed { - fmt.Fprintf(os.Stderr, "vgo: not formatting packages in dependency modules\n") + fmt.Fprintf(os.Stderr, "go: not formatting packages in dependency modules\n") printed = true } continue diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go index 365427d442..9482be98ae 100644 --- a/src/cmd/go/internal/generate/generate.go +++ b/src/cmd/go/internal/generate/generate.go @@ -21,13 +21,13 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" "cmd/go/internal/load" - "cmd/go/internal/vgo" + "cmd/go/internal/modload" "cmd/go/internal/work" ) var CmdGenerate = &base.Command{ Run: runGenerate, - UsageLine: "generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]", + UsageLine: "go generate [-run regexp] [-n] [-v] [-x] [build flags] [file.go... | packages]", Short: "generate Go files by processing source", Long: ` Generate runs commands described by directives within existing @@ -161,9 +161,9 @@ func runGenerate(cmd *base.Command, args []string) { // Even if the arguments are .go files, this loop suffices. printed := false for _, pkg := range load.Packages(args) { - if vgo.Enabled() && !pkg.Module.Top { + if modload.Enabled() && !pkg.Module.Main { if !printed { - fmt.Fprintf(os.Stderr, "vgo: not generating in packages in dependency modules\n") + fmt.Fprintf(os.Stderr, "go: not generating in packages in dependency modules\n") printed = true } continue diff --git a/src/cmd/go/internal/get/discovery.go b/src/cmd/go/internal/get/discovery.go index 97aa1d7e8d..6ba5c091e3 100644 --- a/src/cmd/go/internal/get/discovery.go +++ b/src/cmd/go/internal/get/discovery.go @@ -28,7 +28,7 @@ func charsetReader(charset string, input io.Reader) (io.Reader, error) { // parseMetaGoImports returns meta imports from the HTML in r. // Parsing ends at the end of the section or the beginning of the . -func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { +func parseMetaGoImports(r io.Reader, mod ModuleMode) (imports []metaImport, err error) { d := xml.NewDecoder(r) d.CharsetReader = charsetReader d.Strict = false @@ -39,13 +39,13 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { if err == io.EOF || len(imports) > 0 { err = nil } - return + break } if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { - return + break } if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { - return + break } e, ok := t.(xml.StartElement) if !ok || !strings.EqualFold(e.Name.Local, "meta") { @@ -55,13 +55,6 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { continue } if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { - // Ignore VCS type "mod", which is new Go modules. - // This code is for old go get and must ignore the new mod lines. - // Otherwise matchGoImport will complain about two - // different metaImport lines for the same Prefix. - if f[1] == "mod" { - continue - } imports = append(imports, metaImport{ Prefix: f[0], VCS: f[1], @@ -69,6 +62,27 @@ func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { }) } } + + // Extract mod entries if we are paying attention to them. + var list []metaImport + var have map[string]bool + if mod == PreferMod { + have = make(map[string]bool) + for _, m := range imports { + if m.VCS == "mod" { + have[m.Prefix] = true + list = append(list, m) + } + } + } + + // Append non-mod entries, ignoring those superseded by a mod entry. + for _, m := range imports { + if m.VCS != "mod" && !have[m.Prefix] { + list = append(list, m) + } + } + return list, nil } // attrValue returns the attribute value for the case-insensitive key diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go index 6eabc4eabb..e4148bceb0 100644 --- a/src/cmd/go/internal/get/get.go +++ b/src/cmd/go/internal/get/get.go @@ -18,13 +18,12 @@ import ( "cmd/go/internal/load" "cmd/go/internal/search" "cmd/go/internal/str" - "cmd/go/internal/vgo" "cmd/go/internal/web" "cmd/go/internal/work" ) var CmdGet = &base.Command{ - UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [-v] [build flags] [packages]", + UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [-insecure] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` Get downloads the packages named by the import paths, along with their @@ -75,25 +74,54 @@ For more about specifying packages, see 'go help packages'. For more about how 'go get' finds source code to download, see 'go help importpath'. +This text describes the behavior of get when using GOPATH +to manage source code and dependencies. +If instead the go command is running in module-aware mode, +the details of get's flags and effects change, as does 'go help get'. +See 'go help modules' and 'go help module-get'. + See also: go build, go install, go clean. `, } -var getD = CmdGet.Flag.Bool("d", false, "") -var getF = CmdGet.Flag.Bool("f", false, "") -var getT = CmdGet.Flag.Bool("t", false, "") -var getU = CmdGet.Flag.Bool("u", false, "") -var getFix = CmdGet.Flag.Bool("fix", false, "") -var getInsecure = CmdGet.Flag.Bool("insecure", false, "") +var HelpGopathGet = &base.Command{ + UsageLine: "gopath-get", + Short: "legacy GOPATH go get", + Long: ` +The 'go get' command changes behavior depending on whether the +go command is running in module-aware mode or legacy GOPATH mode. +This help text, accessible as 'go help gopath-get' even in module-aware mode, +describes 'go get' as it operates in legacy GOPATH mode. + +Usage: ` + CmdGet.UsageLine + ` +` + CmdGet.Long, +} + +var ( + getD = CmdGet.Flag.Bool("d", false, "") + getF = CmdGet.Flag.Bool("f", false, "") + getT = CmdGet.Flag.Bool("t", false, "") + getU = CmdGet.Flag.Bool("u", false, "") + getFix = CmdGet.Flag.Bool("fix", false, "") + + Insecure bool +) func init() { work.AddBuildFlags(CmdGet) CmdGet.Run = runGet // break init loop + CmdGet.Flag.BoolVar(&Insecure, "insecure", Insecure, "") } func runGet(cmd *base.Command, args []string) { - if vgo.Enabled() { - base.Fatalf("go get: vgo not implemented") + if cfg.ModulesEnabled { + // Should not happen: main.go should install the separate module-enabled get code. + base.Fatalf("go get: modules not implemented") + } + if cfg.GoModInGOPATH != "" { + // Warn about not using modules with GO111MODULE=auto when go.mod exists. + // To silence the warning, users can set GO111MODULE=off. + fmt.Fprintf(os.Stderr, "go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;\n\tignoring %s;\n\tsee 'go help modules'\n", base.ShortPath(cfg.GoModInGOPATH)) } work.BuildInit() @@ -135,9 +163,8 @@ func runGet(cmd *base.Command, args []string) { if *getT { mode |= load.GetTestDeps } - args = downloadPaths(args) - for _, arg := range args { - download(arg, nil, &stk, mode) + for _, pkg := range downloadPaths(args) { + download(pkg, nil, &stk, mode) } base.ExitIfErrors() @@ -156,8 +183,7 @@ func runGet(cmd *base.Command, args []string) { // This leads to duplicated loads of the standard packages. load.ClearCmdCache() - args = load.ImportPaths(args) - load.PackagesForBuild(args) + pkgs := load.PackagesForBuild(args) // Phase 3. Install. if *getD { @@ -167,7 +193,7 @@ func runGet(cmd *base.Command, args []string) { return } - work.InstallPackages(args, true) + work.InstallPackages(args, pkgs) } // downloadPaths prepares the list of paths to pass to download. @@ -175,28 +201,21 @@ func runGet(cmd *base.Command, args []string) { // for a particular pattern, downloadPaths leaves it in the result list, // in the hope that we can figure out the repository from the // initial ...-free prefix. -func downloadPaths(args []string) []string { - args = load.ImportPathsForGoGet(args) - var out []string - for _, a := range args { - if strings.Contains(a, "...") { - var expand []string - // Use matchPackagesInFS to avoid printing - // warnings. They will be printed by the - // eventual call to importPaths instead. - if build.IsLocalImport(a) { - expand = search.MatchPackagesInFS(a) - } else { - expand = search.MatchPackages(a) - } - if len(expand) > 0 { - out = append(out, expand...) - continue - } +func downloadPaths(patterns []string) []string { + for _, arg := range patterns { + if strings.Contains(arg, "@") { + base.Fatalf("go: cannot use path@version syntax in GOPATH mode") } - out = append(out, a) } - return out + var pkgs []string + for _, m := range search.ImportPathsQuiet(patterns) { + if len(m.Pkgs) == 0 && strings.Contains(m.Pattern, "...") { + pkgs = append(pkgs, m.Pattern) + } else { + pkgs = append(pkgs, m.Pkgs...) + } + } + return pkgs } // downloadCache records the import paths we have already @@ -221,7 +240,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) } load1 := func(path string, mode int) *load.Package { if parent == nil { - return load.LoadPackage(path, stk) + return load.LoadPackageNoFlags(path, stk) } return load.LoadImport(path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) } @@ -277,9 +296,9 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) // for p has been replaced in the package cache. if wildcardOkay && strings.Contains(arg, "...") { if build.IsLocalImport(arg) { - args = search.MatchPackagesInFS(arg) + args = search.MatchPackagesInFS(arg).Pkgs } else { - args = search.MatchPackages(arg) + args = search.MatchPackages(arg).Pkgs } isWildcard = true } @@ -310,7 +329,7 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) // The imports might have changed, so reload again. - p = load.ReloadPackage(arg, stk) + p = load.ReloadPackageNoFlags(arg, stk) if p.Error != nil { base.Errorf("%s", p.Error) return @@ -379,7 +398,7 @@ func downloadPackage(p *load.Package) error { ) security := web.Secure - if *getInsecure { + if Insecure { security = web.Insecure } @@ -402,16 +421,16 @@ func downloadPackage(p *load.Package) error { } repo = remote if !*getF && err == nil { - if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil { - repo := rr.repo + if rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security); err == nil { + repo := rr.Repo if rr.vcs.resolveRepo != nil { resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) if err == nil { repo = resolved } } - if remote != repo && rr.isCustom { - return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote) + if remote != repo && rr.IsCustom { + return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote) } } } @@ -419,13 +438,13 @@ func downloadPackage(p *load.Package) error { } else { // Analyze the import path to determine the version control system, // repository, and the import path for the root of the repository. - rr, err := repoRootForImportPath(p.ImportPath, security) + rr, err := RepoRootForImportPath(p.ImportPath, IgnoreMod, security) if err != nil { return err } - vcs, repo, rootPath = rr.vcs, rr.repo, rr.root + vcs, repo, rootPath = rr.vcs, rr.Repo, rr.Root } - if !blindRepo && !vcs.isSecure(repo) && !*getInsecure { + if !blindRepo && !vcs.isSecure(repo) && !Insecure { return fmt.Errorf("cannot download, %v uses insecure protocol", repo) } diff --git a/src/cmd/go/internal/get/pkg_test.go b/src/cmd/go/internal/get/pkg_test.go index 1179d86693..fc6a179c2e 100644 --- a/src/cmd/go/internal/get/pkg_test.go +++ b/src/cmd/go/internal/get/pkg_test.go @@ -33,15 +33,18 @@ func TestFoldDup(t *testing.T) { var parseMetaGoImportsTests = []struct { in string + mod ModuleMode out []metaImport }{ { ``, + IgnoreMod, []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, }, { ` `, + IgnoreMod, []metaImport{ {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, {"baz/quux", "git", "http://github.com/rsc/baz/quux"}, @@ -50,6 +53,7 @@ var parseMetaGoImportsTests = []struct { { ` `, + IgnoreMod, []metaImport{ {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, }, @@ -57,35 +61,65 @@ var parseMetaGoImportsTests = []struct { { ` `, + IgnoreMod, []metaImport{ {"foo/bar", "git", "https://github.com/rsc/foo/bar"}, }, }, + { + ` + `, + PreferMod, + []metaImport{ + {"foo/bar", "mod", "http://github.com/rsc/baz/quux"}, + }, + }, { ` `, + IgnoreMod, []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, }, { ` `, + IgnoreMod, []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, }, { ``, + IgnoreMod, []metaImport{{"foo/bar", "git", "https://github.com/rsc/foo/bar"}}, }, { // XML doesn't like
    . `Page Not Found
    DRAFT
    `, + IgnoreMod, []metaImport{{"chitin.io/chitin", "git", "https://github.com/chitin-io/chitin"}}, }, + { + ` + + `, + IgnoreMod, + []metaImport{{"myitcv.io", "git", "https://github.com/myitcv/x"}}, + }, + { + ` + + `, + PreferMod, + []metaImport{ + {"myitcv.io/blah2", "mod", "https://raw.githubusercontent.com/myitcv/pubx/master"}, + {"myitcv.io", "git", "https://github.com/myitcv/x"}, + }, + }, } func TestParseMetaGoImports(t *testing.T) { for i, tt := range parseMetaGoImportsTests { - out, err := parseMetaGoImports(strings.NewReader(tt.in)) + out, err := parseMetaGoImports(strings.NewReader(tt.in), tt.mod) if err != nil { t.Errorf("test#%d: %v", i, err) continue diff --git a/src/cmd/go/internal/get/vcs.go b/src/cmd/go/internal/get/vcs.go index 45fc69a7f3..0f7b623ec3 100644 --- a/src/cmd/go/internal/get/vcs.go +++ b/src/cmd/go/internal/get/vcs.go @@ -5,7 +5,6 @@ package get import ( - "bytes" "encoding/json" "errors" "fmt" @@ -428,19 +427,18 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) fmt.Printf("cd %s\n", dir) fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " ")) } - var buf bytes.Buffer - cmd.Stdout = &buf - cmd.Stderr = &buf - err = cmd.Run() - out := buf.Bytes() + out, err := cmd.Output() if err != nil { if verbose || cfg.BuildV { fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " ")) - os.Stderr.Write(out) + if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { + os.Stderr.Write(ee.Stderr) + } else { + fmt.Fprintf(os.Stderr, err.Error()) + } } - return out, err } - return out, nil + return out, err } // ping pings to determine scheme to use. @@ -624,27 +622,29 @@ func checkNestedVCS(vcs *vcsCmd, dir, srcRoot string) error { return nil } -// repoRoot represents a version control system, a repo, and a root of -// where to put it on disk. -type repoRoot struct { - vcs *vcsCmd +// RepoRoot describes the repository root for a tree of source code. +type RepoRoot struct { + Repo string // repository URL, including scheme + Root string // import path corresponding to root of repo + IsCustom bool // defined by served tags (as opposed to hard-coded pattern) + VCS string // vcs type ("mod", "git", ...) - // repo is the repository URL, including scheme - repo string - - // root is the import path corresponding to the root of the - // repository - root string - - // isCustom is true for custom import paths (those defined by HTML meta tags) - isCustom bool + vcs *vcsCmd // internal: vcs command access } var httpPrefixRE = regexp.MustCompile(`^https?:`) -// repoRootForImportPath analyzes importPath to determine the +// ModuleMode specifies whether to prefer modules when looking up code sources. +type ModuleMode int + +const ( + IgnoreMod ModuleMode = iota + PreferMod +) + +// RepoRootForImportPath analyzes importPath to determine the // version control system, and code repository to use. -func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoRoot, error) { +func RepoRootForImportPath(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) { rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths) if err == errUnknownSite { // If there are wildcards, look up the thing before the wildcard, @@ -654,7 +654,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR if i := strings.Index(lookup, "/.../"); i >= 0 { lookup = lookup[:i] } - rr, err = repoRootForImportDynamic(lookup, security) + rr, err = repoRootForImportDynamic(lookup, mod, security) if err != nil { err = fmt.Errorf("unrecognized import path %q (%v)", importPath, err) } @@ -667,7 +667,7 @@ func repoRootForImportPath(importPath string, security web.SecurityMode) (*repoR } } - if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") { + if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.Root, "...") { // Do not allow wildcards in the repo root. rr = nil err = fmt.Errorf("cannot expand ... in %q", importPath) @@ -680,7 +680,7 @@ var errUnknownSite = errors.New("dynamic lookup required to find mapping") // repoRootFromVCSPaths attempts to map importPath to a repoRoot // using the mappings defined in vcsPaths. // If scheme is non-empty, that scheme is forced. -func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*repoRoot, error) { +func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, vcsPaths []*vcsPath) (*RepoRoot, error) { // A common error is to use https://packagepath because that's what // hg and git require. Diagnose this helpfully. if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil { @@ -733,28 +733,32 @@ func repoRootFromVCSPaths(importPath, scheme string, security web.SecurityMode, if security == web.Secure && !vcs.isSecureScheme(scheme) { continue } - if vcs.ping(scheme, match["repo"]) == nil { + if vcs.pingCmd != "" && vcs.ping(scheme, match["repo"]) == nil { match["repo"] = scheme + "://" + match["repo"] - break + goto Found } } + // No scheme found. Fall back to the first one. + match["repo"] = vcs.scheme[0] + "://" + match["repo"] + Found: } } - rr := &repoRoot{ + rr := &RepoRoot{ + Repo: match["repo"], + Root: match["root"], + VCS: vcs.cmd, vcs: vcs, - repo: match["repo"], - root: match["root"], } return rr, nil } return nil, errUnknownSite } -// repoRootForImportDynamic finds a *repoRoot for a custom domain that's not +// repoRootForImportDynamic finds a *RepoRoot for a custom domain that's not // statically known by repoRootForImportPathStatic. // // This handles custom import paths like "name.tld/pkg/foo" or just "name.tld". -func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*repoRoot, error) { +func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.SecurityMode) (*RepoRoot, error) { slash := strings.Index(importPath, "/") if slash < 0 { slash = len(importPath) @@ -772,7 +776,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re return nil, fmt.Errorf(msg, err) } defer body.Close() - imports, err := parseMetaGoImports(body) + imports, err := parseMetaGoImports(body, mod) if err != nil { return nil, fmt.Errorf("parsing %s: %v", importPath, err) } @@ -799,7 +803,7 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re } urlStr0 := urlStr var imports []metaImport - urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security) + urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, mod, security) if err != nil { return nil, err } @@ -812,15 +816,18 @@ func repoRootForImportDynamic(importPath string, security web.SecurityMode) (*re if err := validateRepoRoot(mmi.RepoRoot); err != nil { return nil, fmt.Errorf("%s: invalid repo root %q: %v", urlStr, mmi.RepoRoot, err) } - rr := &repoRoot{ - vcs: vcsByCmd(mmi.VCS), - repo: mmi.RepoRoot, - root: mmi.Prefix, - isCustom: true, - } - if rr.vcs == nil { + vcs := vcsByCmd(mmi.VCS) + if vcs == nil && mmi.VCS != "mod" { return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS) } + + rr := &RepoRoot{ + Repo: mmi.RepoRoot, + Root: mmi.Prefix, + IsCustom: true, + VCS: mmi.VCS, + vcs: vcs, + } return rr, nil } @@ -851,7 +858,7 @@ var ( // It is an error if no imports are found. // urlStr will still be valid if err != nil. // The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1" -func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlStr string, imports []metaImport, err error) { +func metaImportsForPrefix(importPrefix string, mod ModuleMode, security web.SecurityMode) (urlStr string, imports []metaImport, err error) { setCache := func(res fetchResult) (fetchResult, error) { fetchCacheMu.Lock() defer fetchCacheMu.Unlock() @@ -871,7 +878,7 @@ func metaImportsForPrefix(importPrefix string, security web.SecurityMode) (urlSt if err != nil { return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)}) } - imports, err := parseMetaGoImports(body) + imports, err := parseMetaGoImports(body, mod) if err != nil { return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)}) } @@ -896,16 +903,16 @@ type metaImport struct { Prefix, VCS, RepoRoot string } -func splitPathHasPrefix(path, prefix []string) bool { - if len(path) < len(prefix) { +// pathPrefix reports whether sub is a prefix of s, +// only considering entire path components. +func pathPrefix(s, sub string) bool { + // strings.HasPrefix is necessary but not sufficient. + if !strings.HasPrefix(s, sub) { return false } - for i, p := range prefix { - if path[i] != p { - return false - } - } - return true + // The remainder after the prefix must either be empty or start with a slash. + rem := s[len(sub):] + return rem == "" || rem[0] == '/' } // A ImportMismatchError is returned where metaImport/s are present @@ -928,18 +935,21 @@ func (m ImportMismatchError) Error() string { // errNoMatch is returned if none match. func matchGoImport(imports []metaImport, importPath string) (metaImport, error) { match := -1 - imp := strings.Split(importPath, "/") errImportMismatch := ImportMismatchError{importPath: importPath} for i, im := range imports { - pre := strings.Split(im.Prefix, "/") - - if !splitPathHasPrefix(imp, pre) { + if !pathPrefix(importPath, im.Prefix) { errImportMismatch.mismatches = append(errImportMismatch.mismatches, im.Prefix) continue } - if match != -1 { + if match >= 0 { + if imports[match].VCS == "mod" && im.VCS != "mod" { + // All the mod entries precede all the non-mod entries. + // We have a mod entry and don't care about the rest, + // matching or not. + break + } return metaImport{}, fmt.Errorf("multiple meta tags match import path %q", importPath) } match = i diff --git a/src/cmd/go/internal/get/vcs_test.go b/src/cmd/go/internal/get/vcs_test.go index 1ce9b739b1..d13721bed1 100644 --- a/src/cmd/go/internal/get/vcs_test.go +++ b/src/cmd/go/internal/get/vcs_test.go @@ -16,43 +16,43 @@ import ( "cmd/go/internal/web" ) -// Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath. +// Test that RepoRootForImportPath determines the correct RepoRoot for a given importPath. // TODO(cmang): Add tests for SVN and BZR. func TestRepoRootForImportPath(t *testing.T) { testenv.MustHaveExternalNetwork(t) tests := []struct { path string - want *repoRoot + want *RepoRoot }{ { "github.com/golang/groupcache", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://github.com/golang/groupcache", + Repo: "https://github.com/golang/groupcache", }, }, // Unicode letters in directories (issue 18660). { "github.com/user/unicode/испытание", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://github.com/user/unicode", + Repo: "https://github.com/user/unicode", }, }, // IBM DevOps Services tests { "hub.jazz.net/git/user1/pkgname", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://hub.jazz.net/git/user1/pkgname", + Repo: "https://hub.jazz.net/git/user1/pkgname", }, }, { "hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://hub.jazz.net/git/user1/pkgname", + Repo: "https://hub.jazz.net/git/user1/pkgname", }, }, { @@ -91,9 +91,9 @@ func TestRepoRootForImportPath(t *testing.T) { }, { "hub.jazz.net/git/user/pkg.name", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://hub.jazz.net/git/user/pkg.name", + Repo: "https://hub.jazz.net/git/user/pkg.name", }, }, // User names cannot have uppercase letters @@ -104,9 +104,9 @@ func TestRepoRootForImportPath(t *testing.T) { // OpenStack tests { "git.openstack.org/openstack/swift", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://git.openstack.org/openstack/swift", + Repo: "https://git.openstack.org/openstack/swift", }, }, // Trailing .git is less preferred but included for @@ -114,16 +114,16 @@ func TestRepoRootForImportPath(t *testing.T) { // be compilable on both old and new go { "git.openstack.org/openstack/swift.git", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://git.openstack.org/openstack/swift.git", + Repo: "https://git.openstack.org/openstack/swift.git", }, }, { "git.openstack.org/openstack/swift/go/hummingbird", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://git.openstack.org/openstack/swift", + Repo: "https://git.openstack.org/openstack/swift", }, }, { @@ -150,23 +150,23 @@ func TestRepoRootForImportPath(t *testing.T) { }, { "git.apache.org/package-name.git", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://git.apache.org/package-name.git", + Repo: "https://git.apache.org/package-name.git", }, }, { "git.apache.org/package-name_2.x.git/path/to/lib", - &repoRoot{ + &RepoRoot{ vcs: vcsGit, - repo: "https://git.apache.org/package-name_2.x.git", + Repo: "https://git.apache.org/package-name_2.x.git", }, }, { "chiselapp.com/user/kyle/repository/fossilgg", - &repoRoot{ + &RepoRoot{ vcs: vcsFossil, - repo: "https://chiselapp.com/user/kyle/repository/fossilgg", + Repo: "https://chiselapp.com/user/kyle/repository/fossilgg", }, }, { @@ -181,21 +181,21 @@ func TestRepoRootForImportPath(t *testing.T) { } for _, test := range tests { - got, err := repoRootForImportPath(test.path, web.Secure) + got, err := RepoRootForImportPath(test.path, IgnoreMod, web.Secure) want := test.want if want == nil { if err == nil { - t.Errorf("repoRootForImportPath(%q): Error expected but not received", test.path) + t.Errorf("RepoRootForImportPath(%q): Error expected but not received", test.path) } continue } if err != nil { - t.Errorf("repoRootForImportPath(%q): %v", test.path, err) + t.Errorf("RepoRootForImportPath(%q): %v", test.path, err) continue } - if got.vcs.name != want.vcs.name || got.repo != want.repo { - t.Errorf("repoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.repo, want.vcs, want.repo) + if got.vcs.name != want.vcs.name || got.Repo != want.Repo { + t.Errorf("RepoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.vcs, got.Repo, want.vcs, want.Repo) } } } @@ -227,18 +227,18 @@ func TestFromDir(t *testing.T) { f.Close() } - want := repoRoot{ + want := RepoRoot{ vcs: vcs, - root: path.Join("example.com", vcs.name), + Root: path.Join("example.com", vcs.name), } - var got repoRoot - got.vcs, got.root, err = vcsFromDir(dir, tempDir) + var got RepoRoot + got.vcs, got.Root, err = vcsFromDir(dir, tempDir) if err != nil { t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err) continue } - if got.vcs.name != want.vcs.name || got.root != want.root { - t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.root, want.vcs, want.root) + if got.vcs.name != want.vcs.name || got.Root != want.Root { + t.Errorf("FromDir(%q, %q) = VCS(%s) Root(%s), want VCS(%s) Root(%s)", dir, tempDir, got.vcs, got.Root, want.vcs, want.Root) } } } @@ -401,6 +401,22 @@ func TestMatchGoImport(t *testing.T) { path: "different.example.com/user/foo", err: errors.New("meta tags do not match import path"), }, + { + imports: []metaImport{ + {Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"}, + {Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"}, + }, + path: "myitcv.io/blah2/foo", + mi: metaImport{Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"}, + }, + { + imports: []metaImport{ + {Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"}, + {Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"}, + }, + path: "myitcv.io/other", + mi: metaImport{Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"}, + }, } for _, test := range tests { diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go index c79bf8bebb..312a29590f 100644 --- a/src/cmd/go/internal/help/help.go +++ b/src/cmd/go/internal/help/help.go @@ -20,83 +20,96 @@ import ( ) // Help implements the 'help' command. -func Help(args []string) { - if len(args) == 0 { - PrintUsage(os.Stdout) - // not exit 2: succeeded at 'go help'. - return - } - if len(args) != 1 { - fmt.Fprintf(os.Stderr, "usage: go help command\n\nToo many arguments given.\n") - os.Exit(2) // failed at 'go help' - } - - arg := args[0] - +func Help(w io.Writer, args []string) { // 'go help documentation' generates doc.go. - if arg == "documentation" { - fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.") - fmt.Println("// Use of this source code is governed by a BSD-style") - fmt.Println("// license that can be found in the LICENSE file.") - fmt.Println() - fmt.Println("// Code generated by mkalldocs.sh; DO NOT EDIT.") - fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") - fmt.Println() + if len(args) == 1 && args[0] == "documentation" { + fmt.Fprintln(w, "// Copyright 2011 The Go Authors. All rights reserved.") + fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style") + fmt.Fprintln(w, "// license that can be found in the LICENSE file.") + fmt.Fprintln(w) + fmt.Fprintln(w, "// Code generated by mkalldocs.sh; DO NOT EDIT.") + fmt.Fprintln(w, "// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.") + fmt.Fprintln(w) buf := new(bytes.Buffer) - PrintUsage(buf) + PrintUsage(buf, base.Go) usage := &base.Command{Long: buf.String()} - tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*base.Command{usage}, base.Commands...)) - fmt.Println("package main") + cmds := []*base.Command{usage} + for _, cmd := range base.Go.Commands { + if cmd.UsageLine == "gopath-get" { + // Avoid duplication of the "get" documentation. + continue + } + cmds = append(cmds, cmd) + cmds = append(cmds, cmd.Commands...) + } + tmpl(&commentWriter{W: w}, documentationTemplate, cmds) + fmt.Fprintln(w, "package main") return } - for _, cmd := range base.Commands { - if cmd.Name() == arg { - tmpl(os.Stdout, helpTemplate, cmd) - // not exit 2: succeeded at 'go help cmd'. - return + cmd := base.Go +Args: + for i, arg := range args { + for _, sub := range cmd.Commands { + if sub.Name() == arg { + cmd = sub + continue Args + } } + + // helpSuccess is the help command using as many args as possible that would succeed. + helpSuccess := "go help" + if i > 0 { + helpSuccess = " " + strings.Join(args[:i], " ") + } + fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess) + os.Exit(2) // failed at 'go help cmd' } - fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'go help'.\n", arg) - os.Exit(2) // failed at 'go help cmd' + if len(cmd.Commands) > 0 { + PrintUsage(os.Stdout, cmd) + } else { + tmpl(os.Stdout, helpTemplate, cmd) + } + // not exit 2: succeeded at 'go help cmd'. + return } -var usageTemplate = `Go is a tool for managing Go source code. +var usageTemplate = `{{.Long | trim}} Usage: - go command [arguments] + {{.UsageLine}} [arguments] The commands are: -{{range .}}{{if .Runnable}} +{{range .Commands}}{{if or (.Runnable) .Commands}} {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} -Use "go help [command]" for more information about a command. - +Use "go help{{with .LongName}} {{.}}{{end}} " for more information about a command. +{{if eq (.UsageLine) "go"}} Additional help topics: -{{range .}}{{if not .Runnable}} +{{range .Commands}}{{if and (not .Runnable) (not .Commands)}} {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} -Use "go help [topic]" for more information about that topic. - +Use "go help{{with .LongName}} {{.}}{{end}} " for more information about that topic. +{{end}} ` -var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}} +var helpTemplate = `{{if .Runnable}}usage: {{.UsageLine}} {{end}}{{.Long | trim}} ` var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}} -{{end}}{{if .Runnable}}Usage: +{{end}}{{if .Commands}}` + usageTemplate + `{{else}}{{if .Runnable}}Usage: - go {{.UsageLine}} + {{.UsageLine}} {{end}}{{.Long | trim}} -{{end}}` +{{end}}{{end}}` // commentWriter writes a Go comment to the underlying io.Writer, // using line comment form (//). @@ -171,8 +184,8 @@ func capitalize(s string) string { return string(unicode.ToTitle(r)) + s[n:] } -func PrintUsage(w io.Writer) { +func PrintUsage(w io.Writer, cmd *base.Command) { bw := bufio.NewWriter(w) - tmpl(bw, usageTemplate, base.Commands) + tmpl(bw, usageTemplate, cmd) bw.Flush() } diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index ce19796558..aff4ce12f6 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -30,7 +30,7 @@ the C or C++ compiler, respectively, to use. var HelpPackages = &base.Command{ UsageLine: "packages", - Short: "package lists", + Short: "package lists and patterns", Long: ` Many commands apply to a set of packages: @@ -54,9 +54,11 @@ for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. -- "all" expands to all package directories found in all the GOPATH +- "all" expands to all packages found in all the GOPATH trees. For example, 'go list all' lists all the packages on the local -system. +system. When using modules, "all" expands to all packages in +the main module and their dependencies, including dependencies +needed by tests of any of those. - "std" is like all but expands to just the packages in the standard Go library. @@ -193,6 +195,7 @@ using the named version control system, and then the path inside that repository. The supported version control systems are: Bazaar .bzr + Fossil .fossil Git .git Mercurial .hg Subversion .svn @@ -236,7 +239,7 @@ The meta tag should appear as early in the file as possible. In particular, it should appear before any raw JavaScript or CSS, to avoid confusing the go command's restricted parser. -The vcs is one of "git", "hg", "svn", etc, +The vcs is one of "bzr", "fossil", "git", "hg", "svn". The repo-root is the root of the version control system containing a scheme and not containing a .vcs qualifier. @@ -258,12 +261,22 @@ the go tool will verify that https://example.org/?go-get=1 contains the same meta tag and then git clone https://code.org/r/p/exproj into GOPATH/src/example.org. -New downloaded packages are written to the first directory listed in the GOPATH -environment variable (For more details see: 'go help gopath'). +When using GOPATH, downloaded packages are written to the first directory +listed in the GOPATH environment variable. +(See 'go help gopath-get' and 'go help gopath'.) -The go command attempts to download the version of the -package appropriate for the Go release being used. -Run 'go help get' for more. +When using modules, downloaded packages are stored in the module cache. +(See 'go help modules-get' and 'go help goproxy'.) + +When using modules, an additional variant of the go-import meta tag is +recognized and is preferred over those listing version control systems. +That variant uses "mod" as the vcs in the content value, as in: + + + +This tag means to fetch modules with paths beginning with example.org +from the module proxy available at the URL https://code.org/moduleproxy. +See 'go help goproxy' for details about the proxy protocol. Import path checking @@ -286,6 +299,9 @@ Import path checking is disabled for code found within vendor trees. This makes it possible to copy code into alternate locations in vendor trees without needing to update import comments. +Import path checking is also disabled when using modules. +Import path comments are obsoleted by the go.mod file's module statement. + See https://golang.org/s/go14customimport for details. `, } @@ -358,6 +374,12 @@ in the list. See https://golang.org/doc/code.html for an example. +GOPATH and Modules + +When using modules, GOPATH is no longer used for resolving imports. +However, it is still used to store downloaded source code (in GOPATH/pkg/mod) +and compiled commands (in GOPATH/bin). + Internal Directories Code in or below a directory named "internal" is importable only @@ -464,11 +486,18 @@ General-purpose environment variables: GOCACHE The directory where the go command will store cached information for reuse in future builds. + GOFLAGS + A space-separated list of -flag=value settings to apply + to go commands by default, when the given flag is known by + the current command. Flags listed on the command-line + are applied after this list and therefore override it. GOOS The operating system for which to compile code. Examples are linux, darwin, windows, netbsd. GOPATH For more details see: 'go help gopath'. + GOPROXY + URL of Go module proxy. See 'go help goproxy'. GORACE Options for the race detector. See https://golang.org/doc/articles/race_detector.html. @@ -477,10 +506,6 @@ General-purpose environment variables: GOTMPDIR The directory where the go command will write temporary source files, packages, and binaries. - GOTOOLDIR - The directory where the go tools (compile, cover, doc, etc...) - are installed. This is printed by go env, but setting the - environment variable has no effect. Environment variables for use with cgo: @@ -549,6 +574,20 @@ Special-purpose environment variables: Defined by Git. A colon-separated list of schemes that are allowed to be used with git fetch/clone. If set, any scheme not explicitly mentioned will be considered insecure by 'go get'. + +Additional information available from 'go env' but not read from the environment: + + GOEXE + The executable file name suffix (".exe" on Windows, "" on other systems). + GOHOSTARCH + The architecture (GOARCH) of the Go toolchain binaries. + GOHOSTOS + The operating system (GOOS) of the Go toolchain binaries. + GOMOD + The absolute path to the go.mod of the main module, + or the empty string if not using modules. + GOTOOLDIR + The directory where the go tools (compile, cover, doc, etc...) are installed. `, } diff --git a/src/cmd/go/internal/imports/build.go b/src/cmd/go/internal/imports/build.go index 5597870a02..d1adf9440c 100644 --- a/src/cmd/go/internal/imports/build.go +++ b/src/cmd/go/internal/imports/build.go @@ -183,27 +183,27 @@ func MatchFile(name string, tags map[string]bool) bool { l = l[:n-1] } n := len(l) - if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] { + if n >= 2 && KnownOS[l[n-2]] && KnownArch[l[n-1]] { return tags[l[n-2]] && tags[l[n-1]] } - if n >= 1 && knownOS[l[n-1]] { + if n >= 1 && KnownOS[l[n-1]] { return tags[l[n-1]] } - if n >= 1 && knownArch[l[n-1]] { + if n >= 1 && KnownArch[l[n-1]] { return tags[l[n-1]] } return true } -var knownOS = make(map[string]bool) -var knownArch = make(map[string]bool) +var KnownOS = make(map[string]bool) +var KnownArch = make(map[string]bool) func init() { for _, v := range strings.Fields(goosList) { - knownOS[v] = true + KnownOS[v] = true } for _, v := range strings.Fields(goarchList) { - knownArch[v] = true + KnownArch[v] = true } } diff --git a/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go index 095bb64a8d..d944e95724 100644 --- a/src/cmd/go/internal/imports/scan.go +++ b/src/cmd/go/internal/imports/scan.go @@ -37,6 +37,7 @@ func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]stri imports := make(map[string]bool) testImports := make(map[string]bool) numFiles := 0 +Files: for _, name := range files { r, err := os.Open(name) if err != nil { @@ -48,6 +49,19 @@ func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]stri if err != nil { return nil, nil, fmt.Errorf("reading %s: %v", name, err) } + + // import "C" is implicit requirement of cgo tag. + // When listing files on the command line (explicitFiles=true) + // we do not apply build tag filtering but we still do apply + // cgo filtering, so no explicitFiles check here. + // Why? Because we always have, and it's not worth breaking + // that behavior now. + for _, path := range list { + if path == `"C"` && !tags["cgo"] && !tags["*"] { + continue Files + } + } + if !explicitFiles && !ShouldBuild(data, tags) { continue } diff --git a/src/cmd/go/internal/imports/tags.go b/src/cmd/go/internal/imports/tags.go index ba0ca94535..1c22a472b8 100644 --- a/src/cmd/go/internal/imports/tags.go +++ b/src/cmd/go/internal/imports/tags.go @@ -24,7 +24,6 @@ func loadTags() map[string]bool { if cfg.BuildContext.CgoEnabled { tags["cgo"] = true } - // TODO: Should read these out of GOROOT source code? for _, tag := range cfg.BuildContext.BuildTags { tags[tag] = true } diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 218999c7e8..f3cb4e47ec 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -19,14 +19,21 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/modload" + "cmd/go/internal/str" "cmd/go/internal/work" ) var CmdList = &base.Command{ - UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages]", - Short: "list packages", + // Note: -f -json -m are listed explicitly because they are the most common list flags. + // Do not send CLs removing them because they're covered by [list flags]. + UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]", + Short: "list packages or modules", Long: ` -List lists the packages named by the import paths, one per line. +List lists the named packages, one per line. +The most commonly-used flags are -f and -json, which control the form +of the output printed for each package. Other list flags, documented below, +control more specific details. The default output shows the package import path: @@ -36,43 +43,46 @@ The default output shows the package import path: golang.org/x/net/html The -f flag specifies an alternate format for the list, using the -syntax of package template. The default output is equivalent to -f -'{{.ImportPath}}'. The struct being passed to the template is: +syntax of package template. The default output is equivalent +to -f '{{.ImportPath}}'. The struct being passed to the template is: type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - ImportComment string // path in import comment on package statement - Name string // package name - Doc string // package documentation string - Target string // install path - Shlib string // the shared library that contains this package (only set when -linkshared) - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - StaleReason string // explanation for Stale==true - Root string // Go root or Go path dir containing this package - ConflictDir string // this directory shadows Dir in $GOPATH - BinaryOnly bool // binary-only package: cannot be recompiled from sources - ForTest string // package is only for use in named test - DepOnly bool // package is only a dependency, not explicitly listed - Export string // file containing export data (when using -export) + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Shlib string // the shared library that contains this package (only set when -linkshared) + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + StaleReason string // explanation for Stale==true + Root string // Go root or Go path dir containing this package + ConflictDir string // this directory shadows Dir in $GOPATH + BinaryOnly bool // binary-only package: cannot be recompiled from sources + ForTest string // package is only for use in named test + Export string // file containing export data (when using -export) + Module *Module // info about package's containing module, if any (can be nil) + Match []string // command-line patterns matching this package + DepOnly bool // package is only a dependency, not explicitly listed // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" - IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - FFiles []string // .f, .F, .for and .f90 Fortran source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive - TestGoFiles []string // _test.go files in package - XTestGoFiles []string // _test.go files outside package + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go source files that import "C" + CompiledGoFiles []string // .go files presented to compiler (when using -compiled) + IgnoredGoFiles []string // .go source files ignored due to build constraints + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + FFiles []string // .f, .F, .for and .f90 Fortran source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive + TestGoFiles []string // _test.go files in package + XTestGoFiles []string // _test.go files outside package // Cgo directives CgoCFLAGS []string // cgo: flags for C compiler @@ -83,10 +93,11 @@ syntax of package template. The default output is equivalent to -f CgoPkgConfig []string // cgo: pkg-config names // Dependency information - Imports []string // import paths used by this package - Deps []string // all (recursively) imported dependencies - TestImports []string // imports from TestGoFiles - XTestImports []string // imports from XTestGoFiles + Imports []string // import paths used by this package + ImportMap map[string]string // map from source import to ImportPath (identity entries omitted) + Deps []string // all (recursively) imported dependencies + TestImports []string // imports from TestGoFiles + XTestImports []string // imports from XTestGoFiles // Error information Incomplete bool // this package or a dependency has an error @@ -98,7 +109,7 @@ Packages stored in vendor directories report an ImportPath that includes the path to the vendor directory (for example, "d/vendor/p" instead of "p"), so that the ImportPath uniquely identifies a given copy of a package. The Imports, Deps, TestImports, and XTestImports lists also contain these -expanded imports paths. See golang.org/s/go15vendor for more about vendoring. +expanded import paths. See golang.org/s/go15vendor for more about vendoring. The error information, if any, is @@ -108,22 +119,25 @@ The error information, if any, is Err string // the error itself } +The module information is a Module struct, defined in the discussion +of list -m below. + The template function "join" calls strings.Join. The template function "context" returns the build context, defined as: - type Context struct { - GOARCH string // target architecture - GOOS string // target operating system - GOROOT string // Go root - GOPATH string // Go path - CgoEnabled bool // whether cgo can be used - UseAllFiles bool // use files regardless of +build lines, file names - Compiler string // compiler to assume when computing target paths - BuildTags []string // build constraints to match in +build lines - ReleaseTags []string // releases the current release is compatible with - InstallSuffix string // suffix to use in the name of the install dir - } + type Context struct { + GOARCH string // target architecture + GOOS string // target operating system + GOROOT string // Go root + GOPATH string // Go path + CgoEnabled bool // whether cgo can be used + UseAllFiles bool // use files regardless of +build lines, file names + Compiler string // compiler to assume when computing target paths + BuildTags []string // build constraints to match in +build lines + ReleaseTags []string // releases the current release is compatible with + InstallSuffix string // suffix to use in the name of the install dir + } For more information about the meaning of these fields see the documentation for the go/build package's Context type. @@ -131,9 +145,11 @@ for the go/build package's Context type. The -json flag causes the package data to be printed in JSON format instead of using the template format. -The -cgo flag causes list to set CgoFiles not to the original *.go files -importing "C" but instead to the translated files generated by the cgo -command. +The -compiled flag causes list to set CompiledGoFiles to the Go source +files presented to the compiler. Typically this means that it repeats +the files listed in GoFiles and then also adds the Go code generated +by processing CgoFiles and SwigFiles. The Imports list contains the +union of all imports from both GoFiles and CompiledGoFiles. The -deps flag causes list to iterate over not just the named packages but also all their dependencies. It visits them in a depth-first post-order @@ -154,6 +170,9 @@ a non-nil Error field; other information may or may not be missing The -export flag causes list to set the Export field to the name of a file containing up-to-date export information for the given package. +The -find flag causes list to identify the named packages but not +resolve their dependencies: the Imports and Deps lists will be empty. + The -test flag causes list to report not only the named packages but also their test binaries (for packages with tests), to convey to source code analysis tools exactly how test binaries are constructed. @@ -173,13 +192,95 @@ are all absolute paths. By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir (that is, paths relative to Dir, not absolute paths). -The extra entries added by the -cgo and -test flags are absolute paths -referring to cached copies of generated Go source files. +The generated files added when using the -compiled and -test flags +are absolute paths referring to cached copies of generated Go source files. Although they are Go source files, the paths may not end in ".go". +The -m flag causes list to list modules instead of packages. + +When listing modules, the -f flag still specifies a format template +applied to a Go struct, but now a Module struct: + + type Module struct { + Path string // module path + Version string // module version + Versions []string // available module versions (with -versions) + Replace *Module // replaced by this module + Time *time.Time // time version was created + Update *Module // available update, if any (with -u) + Main bool // is this the main module? + Indirect bool // is this module only an indirect dependency of main module? + Dir string // directory holding files for this module, if any + GoMod string // path to go.mod file for this module, if any + Error *ModuleError // error loading module + } + + type ModuleError struct { + Err string // the error itself + } + +The default output is to print the module path and then +information about the version and replacement if any. +For example, 'go list -m all' might print: + + my/main/module + golang.org/x/text v0.3.0 => /tmp/text + rsc.io/pdf v0.1.1 + +The Module struct has a String method that formats this +line of output, so that the default format is equivalent +to -f '{{.String}}'. + +Note that when a module has been replaced, its Replace field +describes the replacement module, and its Dir field is set to +the replacement's source code, if present. (That is, if Replace +is non-nil, then Dir is set to Replace.Dir, with no access to +the replaced source code.) + +The -u flag adds information about available upgrades. +When the latest version of a given module is newer than +the current one, list -u sets the Module's Update field +to information about the newer module. +The Module's String method indicates an available upgrade by +formatting the newer version in brackets after the current version. +For example, 'go list -m -u all' might print: + + my/main/module + golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text + rsc.io/pdf v0.1.1 [v0.1.2] + +(For tools, 'go list -m -u -json all' may be more convenient to parse.) + +The -versions flag causes list to set the Module's Versions field +to a list of all known versions of that module, ordered according +to semantic versioning, earliest to latest. The flag also changes +the default output format to display the module path followed by the +space-separated version list. + +The arguments to list -m are interpreted as a list of modules, not packages. +The main module is the module containing the current directory. +The active modules are the main module and its dependencies. +With no arguments, list -m shows the main module. +With arguments, list -m shows the modules specified by the arguments. +Any of the active modules can be specified by its module path. +The special pattern "all" specifies all the active modules, first the main +module and then dependencies sorted by module path. +A pattern containing "..." specifies the active modules whose +module paths match the pattern. +A query of the form path@version specifies the result of that query, +which is not limited to active modules. +See 'go help modules' for more about module queries. + +The template function "module" takes a single string argument +that must be a module path or query and returns the specified +module as a Module struct. If an error occurs, the result will +be a Module struct with a non-nil Error field. + For more about build flags, see 'go help build'. For more about specifying packages, see 'go help packages'. + +For more about modules, see 'go help modules'. `, } @@ -188,24 +289,43 @@ func init() { work.AddBuildFlags(CmdList) } -var listCgo = CmdList.Flag.Bool("cgo", false, "") -var listDeps = CmdList.Flag.Bool("deps", false, "") -var listE = CmdList.Flag.Bool("e", false, "") -var listExport = CmdList.Flag.Bool("export", false, "") -var listFmt = CmdList.Flag.String("f", "{{.ImportPath}}", "") -var listJson = CmdList.Flag.Bool("json", false, "") -var listTest = CmdList.Flag.Bool("test", false, "") +var ( + listCompiled = CmdList.Flag.Bool("compiled", false, "") + listDeps = CmdList.Flag.Bool("deps", false, "") + listE = CmdList.Flag.Bool("e", false, "") + listExport = CmdList.Flag.Bool("export", false, "") + listFmt = CmdList.Flag.String("f", "", "") + listFind = CmdList.Flag.Bool("find", false, "") + listJson = CmdList.Flag.Bool("json", false, "") + listM = CmdList.Flag.Bool("m", false, "") + listU = CmdList.Flag.Bool("u", false, "") + listTest = CmdList.Flag.Bool("test", false, "") + listVersions = CmdList.Flag.Bool("versions", false, "") +) + var nl = []byte{'\n'} func runList(cmd *base.Command, args []string) { + modload.LoadTests = *listTest work.BuildInit() out := newTrackingWriter(os.Stdout) defer out.w.Flush() - var do func(*load.PackagePublic) + if *listFmt == "" { + if *listM { + *listFmt = "{{.String}}" + if *listVersions { + *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}` + } + } else { + *listFmt = "{{.ImportPath}}" + } + } + + var do func(interface{}) if *listJson { - do = func(p *load.PackagePublic) { - b, err := json.MarshalIndent(p, "", "\t") + do = func(x interface{}) { + b, err := json.MarshalIndent(x, "", "\t") if err != nil { out.Flush() base.Fatalf("%s", err) @@ -224,13 +344,14 @@ func runList(cmd *base.Command, args []string) { fm := template.FuncMap{ "join": strings.Join, "context": context, + "module": modload.ModuleInfo, } tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) if err != nil { base.Fatalf("%s", err) } - do = func(p *load.PackagePublic) { - if err := tmpl.Execute(out, p); err != nil { + do = func(x interface{}) { + if err := tmpl.Execute(out, x); err != nil { out.Flush() base.Fatalf("%s", err) } @@ -240,6 +361,62 @@ func runList(cmd *base.Command, args []string) { } } + if *listM { + // Module mode. + if *listCompiled { + base.Fatalf("go list -compiled cannot be used with -m") + } + if *listDeps { + // TODO(rsc): Could make this mean something with -m. + base.Fatalf("go list -deps cannot be used with -m") + } + if *listExport { + base.Fatalf("go list -export cannot be used with -m") + } + if *listFind { + base.Fatalf("go list -find cannot be used with -m") + } + if *listTest { + base.Fatalf("go list -test cannot be used with -m") + } + + if modload.Init(); !modload.Enabled() { + base.Fatalf("go list -m: not using modules") + } + modload.LoadBuildList() + + mods := modload.ListModules(args, *listU, *listVersions) + if !*listE { + for _, m := range mods { + if m.Error != nil { + base.Errorf("go list -m %s: %v", m.Path, m.Error.Err) + } + } + base.ExitIfErrors() + } + for _, m := range mods { + do(m) + } + return + } + + // Package mode (not -m). + if *listU { + base.Fatalf("go list -u can only be used with -m") + } + if *listVersions { + base.Fatalf("go list -versions can only be used with -m") + } + + // These pairings make no sense. + if *listFind && *listDeps { + base.Fatalf("go list -deps cannot be used with -find") + } + if *listFind && *listTest { + base.Fatalf("go list -test cannot be used with -find") + } + + load.IgnoreImports = *listFind var pkgs []*load.Package if *listE { pkgs = load.PackagesAndErrors(args) @@ -250,8 +427,8 @@ func runList(cmd *base.Command, args []string) { if cache.Default() == nil { // These flags return file names pointing into the build cache, // so the build cache must exist. - if *listCgo { - base.Fatalf("go list -cgo requires build cache") + if *listCompiled { + base.Fatalf("go list -compiled requires build cache") } if *listExport { base.Fatalf("go list -export requires build cache") @@ -269,20 +446,27 @@ func runList(cmd *base.Command, args []string) { continue } if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { - pmain, _, _, err := load.TestPackagesFor(p, nil) + pmain, ptest, pxtest, err := load.TestPackagesFor(p, nil) if err != nil { - if !*listE { - base.Errorf("can't load test package: %s", err) + if *listE { + pkgs = append(pkgs, &load.Package{ + PackagePublic: load.PackagePublic{ + ImportPath: p.ImportPath + ".test", + Error: &load.PackageError{Err: err.Error()}, + }, + }) continue } - pmain = &load.Package{ - PackagePublic: load.PackagePublic{ - ImportPath: p.ImportPath + ".test", - Error: &load.PackageError{Err: err.Error()}, - }, - } + base.Errorf("can't load test package: %s", err) + continue } pkgs = append(pkgs, pmain) + if ptest != nil { + pkgs = append(pkgs, ptest) + } + if pxtest != nil { + pkgs = append(pkgs, pxtest) + } data := *pmain.Internal.TestmainGo h := cache.NewHash("testmain") @@ -317,16 +501,18 @@ func runList(cmd *base.Command, args []string) { // Do we need to run a build to gather information? needStale := *listJson || strings.Contains(*listFmt, ".Stale") - if needStale || *listExport || *listCgo { + if needStale || *listExport || *listCompiled { var b work.Builder b.Init() b.IsCmdList = true b.NeedExport = *listExport - b.NeedCgoFiles = *listCgo + b.NeedCompiledGoFiles = *listCompiled a := &work.Action{} // TODO: Use pkgsFilter? for _, p := range pkgs { - a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) + if len(p.GoFiles)+len(p.CgoFiles) > 0 { + a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) + } } b.Do(a) } @@ -336,6 +522,10 @@ func runList(cmd *base.Command, args []string) { p.TestImports = p.Resolve(p.TestImports) p.XTestImports = p.Resolve(p.XTestImports) p.DepOnly = !cmdline[p] + + if *listCompiled { + p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports) + } } if *listTest { @@ -348,22 +538,30 @@ func runList(cmd *base.Command, args []string) { // This must happen only once the build code is done // looking at import paths, because it will get very confused // if it sees these. + old := make(map[string]string) for _, p := range all { if p.ForTest != "" { - p.ImportPath += " [" + p.ForTest + ".test]" + new := p.ImportPath + " [" + p.ForTest + ".test]" + old[new] = p.ImportPath + p.ImportPath = new } p.DepOnly = !cmdline[p] } // Update import path lists to use new strings. + m := make(map[string]string) for _, p := range all { - j := 0 - for i := range p.Imports { - // Internal skips "C" - if p.Imports[i] == "C" { - continue + for _, p1 := range p.Internal.Imports { + if p1.ForTest != "" { + m[old[p1.ImportPath]] = p1.ImportPath } - p.Imports[i] = p.Internal.Imports[j].ImportPath - j++ + } + for i, old := range p.Imports { + if new := m[old]; new != "" { + p.Imports[i] = new + } + } + for old := range m { + delete(m, old) } } // Recompute deps lists using new strings, from the leaves up. @@ -383,6 +581,19 @@ func runList(cmd *base.Command, args []string) { } } + // Record non-identity import mappings in p.ImportMap. + for _, p := range pkgs { + for i, srcPath := range p.Internal.RawImports { + path := p.Imports[i] + if path != srcPath { + if p.ImportMap == nil { + p.ImportMap = make(map[string]string) + } + p.ImportMap[srcPath] = path + } + } + } + for _, p := range pkgs { do(&p.PackagePublic) } diff --git a/src/cmd/go/internal/load/flag.go b/src/cmd/go/internal/load/flag.go index 7ad4208ccc..7534e65f54 100644 --- a/src/cmd/go/internal/load/flag.go +++ b/src/cmd/go/internal/load/flag.go @@ -91,31 +91,3 @@ func (f *PerPackageFlag) For(p *Package) []string { } return flags } - -var cmdlineMatchers []func(*Package) bool - -// SetCmdlinePatterns records the set of patterns given on the command line, -// for use by the PerPackageFlags. -func SetCmdlinePatterns(args []string) { - setCmdlinePatterns(args, base.Cwd) -} - -func setCmdlinePatterns(args []string, cwd string) { - if len(args) == 0 { - args = []string{"."} - } - cmdlineMatchers = nil // allow reset for testing - for _, arg := range args { - cmdlineMatchers = append(cmdlineMatchers, MatchPackage(arg, cwd)) - } -} - -// isCmdlinePkg reports whether p is a package listed on the command line. -func isCmdlinePkg(p *Package) bool { - for _, m := range cmdlineMatchers { - if m(p) { - return true - } - } - return false -} diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 28d3f9f847..d9696783a9 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -25,7 +25,21 @@ import ( "cmd/go/internal/modinfo" "cmd/go/internal/search" "cmd/go/internal/str" - "cmd/go/internal/vgo" +) + +var ( + // module initialization hook; never nil, no-op if module use is disabled + ModInit func() + + // module hooks; nil if module use is disabled + ModBinDir func() string // return effective bin directory + ModLookup func(path string) (dir, realPath string, err error) // lookup effective meaning of import + ModPackageModuleInfo func(path string) *modinfo.ModulePublic // return module info for Package struct + ModImportPaths func(args []string) []*search.Match // expand import paths + ModPackageBuildInfo func(main string, deps []string) string // return module info to embed in binary + ModInfoProg func(info string) []byte // wrap module info in .go code for binary + ModImportFromFiles func([]string) // update go.mod to add modules for imports in these files + ModDirImportPath func(string) string // return effective import path for directory ) var IgnoreImports bool // control whether we ignore imports in packages @@ -40,21 +54,24 @@ type PackagePublic struct { // Note: These fields are part of the go command's public API. // See list.go. It is okay to add fields, but not to change or // remove existing ones. Keep in sync with list.go - Dir string `json:",omitempty"` // directory containing package sources - ImportPath string `json:",omitempty"` // import path of package in dir - ImportComment string `json:",omitempty"` // path in import comment on package statement - Name string `json:",omitempty"` // package name - Doc string `json:",omitempty"` // package documentation string - Target string `json:",omitempty"` // installed target for this package (may be executable) - Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared) - Goroot bool `json:",omitempty"` // is this package found in the Go root? - Standard bool `json:",omitempty"` // is this package part of the standard Go library? - Root string `json:",omitempty"` // Go root or Go path dir containing this package - ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory - BinaryOnly bool `json:",omitempty"` // package cannot be recompiled - ForTest string `json:",omitempty"` // package is only for use in named test - DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed - Export string `json:",omitempty"` // file containing export data (set by go list -export) + Dir string `json:",omitempty"` // directory containing package sources + ImportPath string `json:",omitempty"` // import path of package in dir + ImportComment string `json:",omitempty"` // path in import comment on package statement + Name string `json:",omitempty"` // package name + Doc string `json:",omitempty"` // package documentation string + Target string `json:",omitempty"` // installed target for this package (may be executable) + Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared) + Root string `json:",omitempty"` // Go root or Go path dir containing this package + ConflictDir string `json:",omitempty"` // Dir is hidden by this other directory + ForTest string `json:",omitempty"` // package is only for use in named test + Export string `json:",omitempty"` // file containing export data (set by go list -export) + Module *modinfo.ModulePublic `json:",omitempty"` // info about package's module, if any + Match []string `json:",omitempty"` // command-line patterns matching this package + Goroot bool `json:",omitempty"` // is this package found in the Go root? + Standard bool `json:",omitempty"` // is this package part of the standard Go library? + DepOnly bool `json:",omitempty"` // package is only as a dependency, not explicitly listed + BinaryOnly bool `json:",omitempty"` // package cannot be recompiled + Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies? // Stale and StaleReason remain here *only* for the list command. // They are only initialized in preparation for list execution. @@ -65,18 +82,19 @@ type PackagePublic struct { // Source files // If you add to this list you MUST add to p.AllFiles (below) too. // Otherwise file name security lists will not apply to any new additions. - GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string `json:",omitempty"` // .go sources files that import "C" - IgnoredGoFiles []string `json:",omitempty"` // .go sources ignored due to build constraints - CFiles []string `json:",omitempty"` // .c source files - CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files - MFiles []string `json:",omitempty"` // .m source files - HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files - FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files - SFiles []string `json:",omitempty"` // .s source files - SwigFiles []string `json:",omitempty"` // .swig files - SwigCXXFiles []string `json:",omitempty"` // .swigcxx files - SysoFiles []string `json:",omitempty"` // .syso system object files added to package + GoFiles []string `json:",omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string `json:",omitempty"` // .go source files that import "C" + CompiledGoFiles []string `json:",omitempty"` // .go output from running cgo on CgoFiles + IgnoredGoFiles []string `json:",omitempty"` // .go source files ignored due to build constraints + CFiles []string `json:",omitempty"` // .c source files + CXXFiles []string `json:",omitempty"` // .cc, .cpp and .cxx source files + MFiles []string `json:",omitempty"` // .m source files + HFiles []string `json:",omitempty"` // .h, .hh, .hpp and .hxx source files + FFiles []string `json:",omitempty"` // .f, .F, .for and .f90 Fortran source files + SFiles []string `json:",omitempty"` // .s source files + SwigFiles []string `json:",omitempty"` // .swig files + SwigCXXFiles []string `json:",omitempty"` // .swigcxx files + SysoFiles []string `json:",omitempty"` // .syso system object files added to package // Cgo directives CgoCFLAGS []string `json:",omitempty"` // cgo: flags for C compiler @@ -87,11 +105,12 @@ type PackagePublic struct { CgoPkgConfig []string `json:",omitempty"` // cgo: pkg-config names // Dependency information - Imports []string `json:",omitempty"` // import paths used by this package - Deps []string `json:",omitempty"` // all (recursively) imported dependencies + Imports []string `json:",omitempty"` // import paths used by this package + ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted) + Deps []string `json:",omitempty"` // all (recursively) imported dependencies // Error information - Incomplete bool `json:",omitempty"` // was there an error loading this package or dependencies? + // Incomplete is above, packed into the other bools Error *PackageError `json:",omitempty"` // error loading this package (not dependencies) DepsErrors []*PackageError `json:",omitempty"` // errors loading dependencies @@ -102,8 +121,6 @@ type PackagePublic struct { TestImports []string `json:",omitempty"` // imports from TestGoFiles XTestGoFiles []string `json:",omitempty"` // _test.go files outside package XTestImports []string `json:",omitempty"` // imports from XTestGoFiles - - Module *modinfo.ModulePublic `json:",omitempty"` // info about package module } // AllFiles returns the names of all the files considered for the package. @@ -115,6 +132,7 @@ func (p *Package) AllFiles() []string { return str.StringList( p.GoFiles, p.CgoFiles, + // no p.CompiledGoFiles, because they are from GoFiles or generated by us p.IgnoredGoFiles, p.CFiles, p.CXXFiles, @@ -140,21 +158,23 @@ func (p *Package) Desc() string { type PackageInternal struct { // Unexported fields are not part of the public API. - Build *build.Package - Imports []*Package // this package's direct imports - RawImports []string // this package's original imports as they appear in the text of the program - ForceLibrary bool // this package is a library (even if named "main") - CmdlineFiles bool // package built from files listed on command line - CmdlinePkg bool // package listed on command line - Local bool // imported via local path (./ or ../) - LocalPrefix string // interpret ./ and ../ imports relative to this prefix - ExeName string // desired name for temporary executable - CoverMode string // preprocess Go source files with the coverage tool in this mode - CoverVars map[string]*CoverVar // variables created by coverage analysis - OmitDebug bool // tell linker not to write debug information - GobinSubdir bool // install target would be subdir of GOBIN - BuildInfo string // add this info to package main - TestmainGo *[]byte // content for _testmain.go + Build *build.Package + Imports []*Package // this package's direct imports + CompiledImports []string // additional Imports necessary when using CompiledGoFiles (all from standard library) + RawImports []string // this package's original imports as they appear in the text of the program + ForceLibrary bool // this package is a library (even if named "main") + CmdlineFiles bool // package built from files listed on command line + CmdlinePkg bool // package listed on command line + CmdlinePkgLiteral bool // package listed as literal on command line (not via wildcard) + Local bool // imported via local path (./ or ../) + LocalPrefix string // interpret ./ and ../ imports relative to this prefix + ExeName string // desired name for temporary executable + CoverMode string // preprocess Go source files with the coverage tool in this mode + CoverVars map[string]*CoverVar // variables created by coverage analysis + OmitDebug bool // tell linker not to write debug information + GobinSubdir bool // install target would be subdir of GOBIN + BuildInfo string // add this info to package main + TestmainGo *[]byte // content for _testmain.go Asmflags []string // -asmflags for this package Gcflags []string // -gcflags for this package @@ -277,6 +297,7 @@ func (p *Package) copyBuild(pp *build.Package) { p.XTestImports = pp.XTestImports if IgnoreImports { p.Imports = nil + p.Internal.RawImports = nil p.TestImports = nil p.XTestImports = nil } @@ -307,7 +328,9 @@ func (p *PackageError) Error() string { return "package " + strings.Join(p.ImportStack, "\n\timports ") + ": " + p.Err } -// An ImportStack is a stack of import paths. +// An ImportStack is a stack of import paths, possibly with the suffix " (test)" appended. +// The import path of a test package is the import path of the corresponding +// non-test package with the suffix "_test" added. type ImportStack []string func (s *ImportStack) Push(p string) { @@ -360,15 +383,17 @@ func ClearPackageCachePartial(args []string) { } } -// reloadPackage is like loadPackage but makes sure +// ReloadPackageNoFlags is like LoadPackageNoFlags but makes sure // not to use the package cache. -func ReloadPackage(arg string, stk *ImportStack) *Package { +// It is only for use by GOPATH-based "go get". +// TODO(rsc): When GOPATH-based "go get" is removed, delete this function. +func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package { p := packageCache[arg] if p != nil { delete(packageCache, p.Dir) delete(packageCache, p.ImportPath) } - return LoadPackage(arg, stk) + return LoadPackageNoFlags(arg, stk) } // dirToImportPath returns the pseudo-import path we use for a package @@ -417,10 +442,53 @@ const ( // but possibly a local import path (an absolute file system path or one beginning // with ./ or ../). A local relative path is interpreted relative to srcDir. // It returns a *Package describing the package found in that directory. +// LoadImport does not set tool flags and should only be used by +// this package, as part of a bigger load operation, and by GOPATH-based "go get". +// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function. func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) *Package { stk.Push(path) defer stk.Pop() + if strings.HasPrefix(path, "mod/") { + // Paths beginning with "mod/" might accidentally + // look in the module cache directory tree in $GOPATH/pkg/mod/. + // This prefix is owned by the Go core for possible use in the + // standard library (since it does not begin with a domain name), + // so it's OK to disallow entirely. + return &Package{ + PackagePublic: PackagePublic{ + ImportPath: path, + Error: &PackageError{ + ImportStack: stk.Copy(), + Err: fmt.Sprintf("disallowed import path %q", path), + }, + }, + } + } + + if strings.Contains(path, "@") { + var text string + if cfg.ModulesEnabled { + text = "can only use path@version syntax with 'go get'" + } else { + text = "cannot use path@version syntax in GOPATH mode" + } + return &Package{ + PackagePublic: PackagePublic{ + ImportPath: path, + Error: &PackageError{ + ImportStack: stk.Copy(), + Err: text, + }, + }, + } + } + + parentPath := "" + if parent != nil { + parentPath = parent.ImportPath + } + // Determine canonical identifier for this package. // For a local import the identifier is the pseudo-import path // we create from the full directory to the package. @@ -429,18 +497,14 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo importPath := path origPath := path isLocal := build.IsLocalImport(path) - var vgoDir string - var vgoErr error + var modDir string + var modErr error if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) - } else if vgo.Enabled() { - parentPath := "" - if parent != nil { - parentPath = parent.ImportPath - } + } else if cfg.ModulesEnabled { var p string - vgoDir, p, vgoErr = vgo.Lookup(parentPath, path) - if vgoErr == nil { + modDir, p, modErr = ModLookup(path) + if modErr == nil { importPath = p } } else if mode&ResolveImport != 0 { @@ -469,11 +533,14 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo // in order to return partial information. var bp *build.Package var err error - if vgoDir != "" { - bp, err = cfg.BuildContext.ImportDir(vgoDir, 0) - } else if vgoErr != nil { + if modDir != "" { + bp, err = cfg.BuildContext.ImportDir(modDir, 0) + } else if modErr != nil { bp = new(build.Package) - err = fmt.Errorf("unknown import path %q: %v", importPath, vgoErr) + err = fmt.Errorf("unknown import path %q: %v", importPath, modErr) + } else if cfg.ModulesEnabled && path != "unsafe" { + bp = new(build.Package) + err = fmt.Errorf("unknown import path %q: internal error: module loader did not resolve import", importPath) } else { buildMode := build.ImportComment if mode&ResolveImport == 0 || path != origPath { @@ -485,10 +552,10 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo bp.ImportPath = importPath if cfg.GOBIN != "" { bp.BinDir = cfg.GOBIN - } else if vgo.Enabled() { - bp.BinDir = vgo.BinDir() + } else if cfg.ModulesEnabled { + bp.BinDir = ModBinDir() } - if vgoDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && + if modDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && !strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") { err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } @@ -497,7 +564,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo p = setErrorPos(p, importPos) } - if vgoDir == "" && origPath != cleanImport(origPath) { + if modDir == "" && origPath != cleanImport(origPath) { p.Error = &PackageError{ ImportStack: stk.Copy(), Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)), @@ -507,11 +574,11 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo } // Checked on every import because the rules depend on the code doing the importing. - if perr := disallowInternal(srcDir, p, stk); perr != p { + if perr := disallowInternal(srcDir, parent, parentPath, p, stk); perr != p { return setErrorPos(perr, importPos) } if mode&ResolveImport != 0 { - if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { + if perr := disallowVendor(srcDir, parent, parentPath, origPath, p, stk); perr != p { return setErrorPos(perr, importPos) } } @@ -573,14 +640,10 @@ func isDir(path string) bool { // There are two different resolutions applied. // First, there is Go 1.5 vendoring (golang.org/s/go15vendor). // If vendor expansion doesn't trigger, then the path is also subject to -// Go 1.11 vgo legacy conversion (golang.org/issue/25069). +// Go 1.11 module legacy conversion (golang.org/issue/25069). func ResolveImportPath(parent *Package, path string) (found string) { - if vgo.Enabled() { - parentPath := "" - if parent != nil { - parentPath = parent.ImportPath - } - if _, p, e := vgo.Lookup(parentPath, path); e == nil { + if cfg.ModulesEnabled { + if _, p, e := ModLookup(path); e == nil { return p } return path @@ -872,10 +935,11 @@ func reusePackage(p *Package, stk *ImportStack) *Package { return p } -// disallowInternal checks that srcDir is allowed to import p. +// disallowInternal checks that srcDir (containing package importerPath, if non-empty) +// is allowed to import p. // If the import is allowed, disallowInternal returns the original package p. // If not, it returns a new package containing just an appropriate error. -func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package { +func disallowInternal(srcDir string, importer *Package, importerPath string, p *Package, stk *ImportStack) *Package { // golang.org/s/go14internal: // An import of a path containing the element “internal” // is disallowed if the importing code is outside the tree @@ -918,16 +982,33 @@ func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package { if i > 0 { i-- // rewind over slash in ".../internal" } - parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)] - if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { - return p - } - // Look for symlinks before reporting error. - srcDir = expandPath(srcDir) - parent = expandPath(parent) - if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { - return p + if p.Module == nil { + parent := p.Dir[:i+len(p.Dir)-len(p.ImportPath)] + + if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { + return p + } + + // Look for symlinks before reporting error. + srcDir = expandPath(srcDir) + parent = expandPath(parent) + if str.HasFilePathPrefix(filepath.Clean(srcDir), filepath.Clean(parent)) { + return p + } + } else { + // p is in a module, so make it available based on the importer's import path instead + // of the file path (https://golang.org/issue/23970). + if importerPath == "." { + // The importer is a list of command-line files. + // Pretend that the import path is the import path of the + // directory containing them. + importerPath = ModDirImportPath(importer.Dir) + } + parentOfInternal := p.ImportPath[:i] + if str.HasPathPrefix(importerPath, parentOfInternal) { + return p + } } // Internal is present, and srcDir is outside parent's tree. Not allowed. @@ -959,10 +1040,11 @@ func findInternal(path string) (index int, ok bool) { return 0, false } -// disallowVendor checks that srcDir is allowed to import p as path. +// disallowVendor checks that srcDir (containing package importerPath, if non-empty) +// is allowed to import p as path. // If the import is allowed, disallowVendor returns the original package p. // If not, it returns a new package containing just an appropriate error. -func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package { +func disallowVendor(srcDir string, importer *Package, importerPath, path string, p *Package, stk *ImportStack) *Package { // The stack includes p.ImportPath. // If that's the only thing on the stack, we started // with a name given on the command line, not an @@ -971,6 +1053,20 @@ func disallowVendor(srcDir, path string, p *Package, stk *ImportStack) *Package return p } + // Modules must not import vendor packages in the standard library, + // but the usual vendor visibility check will not catch them + // because the module loader presents them with an ImportPath starting + // with "golang_org/" instead of "vendor/". + if p.Standard && !importer.Standard && strings.HasPrefix(p.ImportPath, "golang_org") { + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.Copy(), + Err: "use of vendored package " + path + " not allowed", + } + perr.Incomplete = true + return &perr + } + if perr := disallowVendorVisibility(srcDir, p, stk); perr != p { return perr } @@ -1101,26 +1197,6 @@ var foldPath = make(map[string]string) func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { p.copyBuild(bp) - // Decide whether p was listed on the command line. - // Given that load is called while processing the command line, - // you might think we could simply pass a flag down into load - // saying whether we are loading something named on the command - // line or something to satisfy an import. But the first load of a - // package named on the command line may be as a dependency - // of an earlier package named on the command line, not when we - // get to that package during command line processing. - // For example "go test fmt reflect" will load reflect as a dependency - // of fmt before it attempts to load as a command-line argument. - // Because loads are cached, the later load will be a no-op, - // so it is important that the first load can fill in CmdlinePkg correctly. - // Hence the call to an explicit matching check here. - p.Internal.CmdlinePkg = isCmdlinePkg(p) - - p.Internal.Asmflags = BuildAsmflags.For(p) - p.Internal.Gcflags = BuildGcflags.For(p) - p.Internal.Ldflags = BuildLdflags.For(p) - p.Internal.Gccgoflags = BuildGccgoflags.For(p) - // The localPrefix is the path we interpret ./ imports relative to. // Synthesized main packages sometimes override this. if p.Internal.Local { @@ -1157,13 +1233,44 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { return } _, elem := filepath.Split(p.Dir) + if cfg.ModulesEnabled { + // NOTE(rsc): Using p.ImportPath instead of p.Dir + // makes sure we install a package in the root of a + // cached module directory as that package name + // not name@v1.2.3. + // Using p.ImportPath instead of p.Dir + // is probably correct all the time, + // even for non-module-enabled code, + // but I'm not brave enough to change the + // non-module behavior this late in the + // release cycle. Maybe for Go 1.12. + // See golang.org/issue/26869. + _, elem = pathpkg.Split(p.ImportPath) + + // If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2. + // See golang.org/issue/24667. + isVersion := func(v string) bool { + if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] { + return false + } + for i := 2; i < len(v); i++ { + if c := v[i]; c < '0' || '9' < c { + return false + } + } + return true + } + if isVersion(elem) { + _, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath)) + } + } full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH { // Install cross-compiled binaries to subdirectories of bin. elem = full } - if p.Internal.Build.BinDir == "" && vgo.Enabled() { - p.Internal.Build.BinDir = vgo.BinDir() + if p.Internal.Build.BinDir == "" && cfg.ModulesEnabled { + p.Internal.Build.BinDir = ModBinDir() } if p.Internal.Build.BinDir != "" { // Install to GOBIN or bin of GOPATH entry. @@ -1212,31 +1319,37 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // Build augmented import list to add implicit dependencies. // Be careful not to add imports twice, just to avoid confusion. importPaths := p.Imports - addImport := func(path string) { + addImport := func(path string, forCompiler bool) { for _, p := range importPaths { if path == p { return } } importPaths = append(importPaths, path) + if forCompiler { + p.Internal.CompiledImports = append(p.Internal.CompiledImports, path) + } } - // Cgo translation adds imports of "runtime/cgo" and "syscall", + // Cgo translation adds imports of "unsafe", "runtime/cgo" and "syscall", // except for certain packages, to avoid circular dependencies. + if p.UsesCgo() { + addImport("unsafe", true) + } if p.UsesCgo() && (!p.Standard || !cgoExclude[p.ImportPath]) && cfg.BuildContext.Compiler != "gccgo" { - addImport("runtime/cgo") + addImport("runtime/cgo", true) } if p.UsesCgo() && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { - addImport("syscall") + addImport("syscall", true) } // SWIG adds imports of some standard packages. if p.UsesSwig() { if cfg.BuildContext.Compiler != "gccgo" { - addImport("runtime/cgo") + addImport("runtime/cgo", true) } - addImport("syscall") - addImport("sync") + addImport("syscall", true) + addImport("sync", true) // TODO: The .swig and .swigcxx files can use // %go_import directives to import other packages. @@ -1245,7 +1358,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { // The linker loads implicit dependencies. if p.Name == "main" && !p.Internal.ForceLibrary { for _, dep := range LinkerDeps(p) { - addImport(dep) + addImport(dep, false) } } @@ -1416,10 +1529,10 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { return } - if vgo.Enabled() { - p.Module = vgo.PackageModuleInfo(p.ImportPath) + if cfg.ModulesEnabled { + p.Module = ModPackageModuleInfo(p.ImportPath) if p.Name == "main" { - p.Internal.BuildInfo = vgo.PackageBuildInfo(p.ImportPath, p.Deps) + p.Internal.BuildInfo = ModPackageBuildInfo(p.ImportPath, p.Deps) } } } @@ -1552,7 +1665,7 @@ func (p *Package) UsesCgo() bool { return len(p.CgoFiles) > 0 } -// packageList returns the list of packages in the dag rooted at roots +// PackageList returns the list of packages in the dag rooted at roots // as visited in a depth-first post-order traversal. func PackageList(roots []*Package) []*Package { seen := map[*Package]bool{} @@ -1574,6 +1687,42 @@ func PackageList(roots []*Package) []*Package { return all } +// TestPackageList returns the list of packages in the dag rooted at roots +// as visited in a depth-first post-order traversal, including the test +// imports of the roots. This ignores errors in test packages. +func TestPackageList(roots []*Package) []*Package { + seen := map[*Package]bool{} + all := []*Package{} + var walk func(*Package) + walk = func(p *Package) { + if seen[p] { + return + } + seen[p] = true + for _, p1 := range p.Internal.Imports { + walk(p1) + } + all = append(all, p) + } + walkTest := func(root *Package, path string) { + var stk ImportStack + p1 := LoadImport(path, root.Dir, root, &stk, root.Internal.Build.TestImportPos[path], ResolveImport) + if p1.Error == nil { + walk(p1) + } + } + for _, root := range roots { + walk(root) + for _, path := range root.TestImports { + walkTest(root, path) + } + for _, path := range root.XTestImports { + walkTest(root, path) + } + } + return all +} + var cmdCache = map[string]*Package{} func ClearCmdCache() { @@ -1582,11 +1731,31 @@ func ClearCmdCache() { } } +// LoadPackage loads the package named by arg. +func LoadPackage(arg string, stk *ImportStack) *Package { + p := loadPackage(arg, stk) + setToolFlags(p) + return p +} + +// LoadPackageNoFlags is like LoadPackage +// but does not guarantee that the build tool flags are set in the result. +// It is only for use by GOPATH-based "go get" +// and is only appropriate for preliminary loading of packages. +// A real load using LoadPackage or (more likely) +// Packages, PackageAndErrors, or PackagesForBuild +// must be done before passing the package to any build +// steps, so that the tool flags can be set properly. +// TODO(rsc): When GOPATH-based "go get" is removed, delete this function. +func LoadPackageNoFlags(arg string, stk *ImportStack) *Package { + return loadPackage(arg, stk) +} + // loadPackage is like loadImport but is used for command-line arguments, // not for paths found in import statements. In addition to ordinary import paths, // loadPackage accepts pseudo-paths beginning with cmd/ to denote commands // in the Go command directory, as well as paths to those directories. -func LoadPackage(arg string, stk *ImportStack) *Package { +func loadPackage(arg string, stk *ImportStack) *Package { if build.IsLocalImport(arg) { dir := arg if !filepath.IsAbs(dir) { @@ -1633,8 +1802,12 @@ func LoadPackage(arg string, stk *ImportStack) *Package { // This lets you run go test ./ioutil in package io and be // referring to io/ioutil rather than a hypothetical import of // "./ioutil". - if build.IsLocalImport(arg) { - bp, _ := cfg.BuildContext.ImportDir(filepath.Join(base.Cwd, arg), build.FindOnly) + if build.IsLocalImport(arg) || filepath.IsAbs(arg) { + dir := arg + if !filepath.IsAbs(arg) { + dir = filepath.Join(base.Cwd, arg) + } + bp, _ := cfg.BuildContext.ImportDir(dir, build.FindOnly) if bp.ImportPath != "" && bp.ImportPath != "." { arg = bp.ImportPath } @@ -1643,7 +1816,7 @@ func LoadPackage(arg string, stk *ImportStack) *Package { return LoadImport(arg, base.Cwd, nil, stk, nil, 0) } -// packages returns the packages named by the +// Packages returns the packages named by the // command line arguments 'args'. If a named package // cannot be loaded at all (for example, if the directory does not exist), // then packages prints an error and does not include that @@ -1663,55 +1836,68 @@ func Packages(args []string) []*Package { return pkgs } -// packagesAndErrors is like 'packages' but returns a +// PackagesAndErrors is like 'packages' but returns a // *Package for every argument, even the ones that // cannot be loaded at all. // The packages that fail to load will have p.Error != nil. -func PackagesAndErrors(args []string) []*Package { - if len(args) > 0 && strings.HasSuffix(args[0], ".go") { - return []*Package{GoFilesPackage(args)} +func PackagesAndErrors(patterns []string) []*Package { + if len(patterns) > 0 && strings.HasSuffix(patterns[0], ".go") { + return []*Package{GoFilesPackage(patterns)} } - args = ImportPaths(args) + matches := ImportPaths(patterns) var ( pkgs []*Package stk ImportStack - seenArg = make(map[string]bool) seenPkg = make(map[*Package]bool) ) - for _, arg := range args { - if seenArg[arg] { - continue + for _, m := range matches { + for _, pkg := range m.Pkgs { + p := loadPackage(pkg, &stk) + p.Match = append(p.Match, m.Pattern) + p.Internal.CmdlinePkg = true + if m.Literal { + // Note: do not set = m.Literal unconditionally + // because maybe we'll see p matching both + // a literal and also a non-literal pattern. + p.Internal.CmdlinePkgLiteral = true + } + if seenPkg[p] { + continue + } + seenPkg[p] = true + pkgs = append(pkgs, p) } - seenArg[arg] = true - pkg := LoadPackage(arg, &stk) - if seenPkg[pkg] { - continue - } - seenPkg[pkg] = true - pkgs = append(pkgs, pkg) } + // Now that CmdlinePkg is set correctly, + // compute the effective flags for all loaded packages + // (not just the ones matching the patterns but also + // their dependencies). + setToolFlags(pkgs...) + return pkgs } -func ImportPaths(args []string) []string { - if cmdlineMatchers == nil { - SetCmdlinePatterns(search.CleanImportPaths(args)) +func setToolFlags(pkgs ...*Package) { + for _, p := range PackageList(pkgs) { + p.Internal.Asmflags = BuildAsmflags.For(p) + p.Internal.Gcflags = BuildGcflags.For(p) + p.Internal.Ldflags = BuildLdflags.For(p) + p.Internal.Gccgoflags = BuildGccgoflags.For(p) } - return vgo.ImportPaths(args) } -func ImportPathsForGoGet(args []string) []string { - if cmdlineMatchers == nil { - SetCmdlinePatterns(search.CleanImportPaths(args)) +func ImportPaths(args []string) []*search.Match { + if ModInit(); cfg.ModulesEnabled { + return ModImportPaths(args) } - return search.ImportPathsNoDotExpansion(args) + return search.ImportPaths(args) } -// packagesForBuild is like 'packages' but fails if any of -// the packages or their dependencies have errors +// PackagesForBuild is like Packages but exits +// if any of the packages or their dependencies have errors // (cannot be built). func PackagesForBuild(args []string) []*Package { pkgs := PackagesAndErrors(args) @@ -1757,7 +1943,8 @@ func PackagesForBuild(args []string) []*Package { // (typically named on the command line). The target is named p.a for // package p or named after the first Go file for package main. func GoFilesPackage(gofiles []string) *Package { - // TODO: Remove this restriction. + ModInit() + for _, f := range gofiles { if !strings.HasSuffix(f, ".go") { base.Fatalf("named files must be .go files") @@ -1795,7 +1982,9 @@ func GoFilesPackage(gofiles []string) *Package { } ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil } - vgo.AddImports(gofiles) + if cfg.ModulesEnabled { + ModImportFromFiles(gofiles) + } var err error if dir == "" { @@ -1807,6 +1996,11 @@ func GoFilesPackage(gofiles []string) *Package { } bp, err := ctxt.ImportDir(dir, 0) + if ModDirImportPath != nil { + // Use the effective import path of the directory + // for deciding visibility during pkg.load. + bp.ImportPath = ModDirImportPath(dir) + } pkg := new(Package) pkg.Internal.Local = true pkg.Internal.CmdlineFiles = true @@ -1816,6 +2010,7 @@ func GoFilesPackage(gofiles []string) *Package { pkg.Internal.LocalPrefix = dirToImportPath(dir) pkg.ImportPath = "command-line-arguments" pkg.Target = "" + pkg.Match = gofiles if pkg.Name == "main" { _, elem := filepath.Split(gofiles[0]) @@ -1825,10 +2020,12 @@ func GoFilesPackage(gofiles []string) *Package { } if cfg.GOBIN != "" { pkg.Target = filepath.Join(cfg.GOBIN, exe) - } else if vgo.Enabled() { - pkg.Target = filepath.Join(vgo.BinDir(), exe) + } else if cfg.ModulesEnabled { + pkg.Target = filepath.Join(ModBinDir(), exe) } } + setToolFlags(pkg) + return pkg } diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go index 49433984a8..cf09c7b0a8 100644 --- a/src/cmd/go/internal/load/search.go +++ b/src/cmd/go/internal/load/search.go @@ -6,7 +6,6 @@ package load import ( "path/filepath" - "runtime" "strings" "cmd/go/internal/search" @@ -15,7 +14,7 @@ import ( // MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd. func MatchPackage(pattern, cwd string) func(*Package) bool { switch { - case strings.HasPrefix(pattern, "./") || strings.HasPrefix(pattern, "../") || pattern == "." || pattern == "..": + case search.IsRelativePath(pattern): // Split pattern into leading pattern-free directory path // (including all . and .. elements) and the final pattern. var dir string @@ -28,13 +27,7 @@ func MatchPackage(pattern, cwd string) func(*Package) bool { } dir = filepath.Join(cwd, dir) if pattern == "" { - return func(p *Package) bool { - // TODO(rsc): This is wrong. See golang.org/issue/25878. - if runtime.GOOS != "windows" { - return p.Dir == dir - } - return strings.EqualFold(p.Dir, dir) - } + return func(p *Package) bool { return p.Dir == dir } } matchPath := search.MatchPattern(pattern) return func(p *Package) bool { diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index 0a13dfc1b7..bb9568d07e 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -36,7 +36,7 @@ type TestCover struct { Pkgs []*Package Paths []string Vars []coverInfo - DeclVars func(string, ...string) map[string]*CoverVar + DeclVars func(*Package, ...string) map[string]*CoverVar } // TestPackagesFor returns three packages: @@ -49,6 +49,9 @@ type TestCover struct { // (for example, if there are no "package p" test files and // package p need not be instrumented for coverage or any other reason), // then the returned ptest == p. +// +// The caller is expected to have checked that len(p.TestGoFiles)+len(p.XTestGoFiles) > 0, +// or else there's no point in any of this. func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Package, err error) { var imports, ximports []*Package var stk ImportStack @@ -111,16 +114,17 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag ptest.GoFiles = append(ptest.GoFiles, p.TestGoFiles...) ptest.Target = "" // Note: The preparation of the vet config requires that common - // indexes in ptest.Imports, ptest.Internal.Imports, and ptest.Internal.RawImports + // indexes in ptest.Imports and ptest.Internal.RawImports // all line up (but RawImports can be shorter than the others). // That is, for 0 ≤ i < len(RawImports), - // RawImports[i] is the import string in the program text, - // Imports[i] is the expanded import string (vendoring applied or relative path expanded away), - // and Internal.Imports[i] is the corresponding *Package. + // RawImports[i] is the import string in the program text, and + // Imports[i] is the expanded import string (vendoring applied or relative path expanded away). // Any implicitly added imports appear in Imports and Internal.Imports // but not RawImports (because they were not in the source code). // We insert TestImports, imports, and rawTestImports at the start of // these lists to preserve the alignment. + // Note that p.Internal.Imports may not be aligned with p.Imports/p.Internal.RawImports, + // but we insert at the beginning there too just for consistency. ptest.Imports = str.StringList(p.TestImports, p.Imports) ptest.Internal.Imports = append(imports, p.Internal.Imports...) ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports) @@ -178,6 +182,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag GoFiles: []string{"_testmain.go"}, ImportPath: p.ImportPath + ".test", Root: p.Root, + Imports: str.StringList(TestMainDeps), }, Internal: PackageInternal{ Build: &build.Package{Name: "main"}, @@ -233,13 +238,28 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag t.Cover = cover if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { pmain.Internal.Imports = append(pmain.Internal.Imports, ptest) + pmain.Imports = append(pmain.Imports, ptest.ImportPath) t.ImportTest = true } if pxtest != nil { pmain.Internal.Imports = append(pmain.Internal.Imports, pxtest) + pmain.Imports = append(pmain.Imports, pxtest.ImportPath) t.ImportXtest = true } + // Sort and dedup pmain.Imports. + // Only matters for go list -test output. + sort.Strings(pmain.Imports) + w := 0 + for _, path := range pmain.Imports { + if w == 0 || path != pmain.Imports[w-1] { + pmain.Imports[w] = path + w++ + } + } + pmain.Imports = pmain.Imports[:w] + pmain.Internal.RawImports = str.StringList(pmain.Imports) + if ptest != p { // We have made modifications to the package p being tested // and are rebuilding p (as ptest). @@ -261,7 +281,7 @@ func TestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Packag var coverFiles []string coverFiles = append(coverFiles, ptest.GoFiles...) coverFiles = append(coverFiles, ptest.CgoFiles...) - ptest.Internal.CoverVars = cover.DeclVars(ptest.ImportPath, coverFiles...) + ptest.Internal.CoverVars = cover.DeclVars(ptest, coverFiles...) } for _, cp := range pmain.Internal.Imports { @@ -322,6 +342,8 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) { p1.ForTest = preal.ImportPath p1.Internal.Imports = make([]*Package, len(p.Internal.Imports)) copy(p1.Internal.Imports, p.Internal.Imports) + p1.Imports = make([]string, len(p.Imports)) + copy(p1.Imports, p.Imports) p = p1 p.Target = "" } diff --git a/src/cmd/go/internal/modcmd/download.go b/src/cmd/go/internal/modcmd/download.go new file mode 100644 index 0000000000..8678caea51 --- /dev/null +++ b/src/cmd/go/internal/modcmd/download.go @@ -0,0 +1,133 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modcmd + +import ( + "cmd/go/internal/base" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + "cmd/go/internal/module" + "cmd/go/internal/par" + "encoding/json" + "os" +) + +var cmdDownload = &base.Command{ + UsageLine: "go mod download [-json] [modules]", + Short: "download modules to local cache", + Long: ` +Download downloads the named modules, which can be module patterns selecting +dependencies of the main module or module queries of the form path@version. +With no arguments, download applies to all dependencies of the main module. + +The go command will automatically download modules as needed during ordinary +execution. The "go mod download" command is useful mainly for pre-filling +the local cache or to compute the answers for a Go module proxy. + +By default, download reports errors to standard error but is otherwise silent. +The -json flag causes download to print a sequence of JSON objects +to standard output, describing each downloaded module (or failure), +corresponding to this Go struct: + + type Module struct { + Path string // module path + Version string // module version + Error string // error loading module + Info string // absolute path to cached .info file + GoMod string // absolute path to cached .mod file + Zip string // absolute path to cached .zip file + Dir string // absolute path to cached source root directory + Sum string // checksum for path, version (as in go.sum) + GoModSum string // checksum for go.mod (as in go.sum) + } + +See 'go help modules' for more about module queries. + `, +} + +var downloadJSON = cmdDownload.Flag.Bool("json", false, "") + +func init() { + cmdDownload.Run = runDownload // break init cycle +} + +type moduleJSON struct { + Path string `json:",omitempty"` + Version string `json:",omitempty"` + Error string `json:",omitempty"` + Info string `json:",omitempty"` + GoMod string `json:",omitempty"` + Zip string `json:",omitempty"` + Dir string `json:",omitempty"` + Sum string `json:",omitempty"` + GoModSum string `json:",omitempty"` +} + +func runDownload(cmd *base.Command, args []string) { + if len(args) == 0 { + args = []string{"all"} + } + + var mods []*moduleJSON + var work par.Work + listU := false + listVersions := false + for _, info := range modload.ListModules(args, listU, listVersions) { + if info.Replace != nil { + info = info.Replace + } + if info.Version == "" { + continue + } + m := &moduleJSON{ + Path: info.Path, + Version: info.Version, + } + mods = append(mods, m) + work.Add(m) + } + + work.Do(10, func(item interface{}) { + m := item.(*moduleJSON) + var err error + m.Info, err = modfetch.InfoFile(m.Path, m.Version) + if err != nil { + m.Error = err.Error() + return + } + m.GoMod, err = modfetch.GoModFile(m.Path, m.Version) + if err != nil { + m.Error = err.Error() + return + } + m.GoModSum, err = modfetch.GoModSum(m.Path, m.Version) + if err != nil { + m.Error = err.Error() + return + } + mod := module.Version{Path: m.Path, Version: m.Version} + m.Zip, err = modfetch.DownloadZip(mod) + if err != nil { + m.Error = err.Error() + return + } + m.Sum = modfetch.Sum(mod) + m.Dir, err = modfetch.Download(mod) + if err != nil { + m.Error = err.Error() + return + } + }) + + if *downloadJSON { + for _, m := range mods { + b, err := json.MarshalIndent(m, "", "\t") + if err != nil { + base.Fatalf("%v", err) + } + os.Stdout.Write(append(b, '\n')) + } + } +} diff --git a/src/cmd/go/internal/modcmd/edit.go b/src/cmd/go/internal/modcmd/edit.go new file mode 100644 index 0000000000..5fea3e48e0 --- /dev/null +++ b/src/cmd/go/internal/modcmd/edit.go @@ -0,0 +1,382 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go mod edit + +package modcmd + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/modfile" + "cmd/go/internal/modload" + "cmd/go/internal/module" +) + +var cmdEdit = &base.Command{ + UsageLine: "go mod edit [editing flags] [go.mod]", + Short: "edit go.mod from tools or scripts", + Long: ` +Edit provides a command-line interface for editing go.mod, +for use primarily by tools or scripts. It reads only go.mod; +it does not look up information about the modules involved. +By default, edit reads and writes the go.mod file of the main module, +but a different target file can be specified after the editing flags. + +The editing flags specify a sequence of editing operations. + +The -fmt flag reformats the go.mod file without making other changes. +This reformatting is also implied by any other modifications that use or +rewrite the go.mod file. The only time this flag is needed is if no other +flags are specified, as in 'go mod edit -fmt'. + +The -module flag changes the module's path (the go.mod file's module line). + +The -require=path@version and -droprequire=path flags +add and drop a requirement on the given module path and version. +Note that -require overrides any existing requirements on path. +These flags are mainly for tools that understand the module graph. +Users should prefer 'go get path@version' or 'go get path@none', +which make other go.mod adjustments as needed to satisfy +constraints imposed by other modules. + +The -exclude=path@version and -dropexclude=path@version flags +add and drop an exclusion for the given module path and version. +Note that -exclude=path@version is a no-op if that exclusion already exists. + +The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags +add and drop a replacement of the given module path and version pair. +If the @v in old@v is omitted, the replacement applies to all versions +with the old module path. If the @v in new@v is omitted, the new path +should be a local module root directory, not a module path. +Note that -replace overrides any existing replacements for old[@v]. + +The -require, -droprequire, -exclude, -dropexclude, -replace, +and -dropreplace editing flags may be repeated, and the changes +are applied in the order given. + +The -print flag prints the final go.mod in its text format instead of +writing it back to go.mod. + +The -json flag prints the final go.mod file in JSON format instead of +writing it back to go.mod. The JSON output corresponds to these Go types: + + type Module struct { + Path string + Version string + } + + type GoMod struct { + Module Module + Require []Require + Exclude []Module + Replace []Replace + } + + type Require struct { + Path string + Version string + Indirect bool + } + + type Replace struct { + Old Module + New Module + } + +Note that this only describes the go.mod file itself, not other modules +referred to indirectly. For the full set of modules available to a build, +use 'go list -m -json all'. + +For example, a tool can obtain the go.mod as a data structure by +parsing the output of 'go mod edit -json' and can then make changes +by invoking 'go mod edit' with -require, -exclude, and so on. + `, +} + +var ( + editFmt = cmdEdit.Flag.Bool("fmt", false, "") + // editGo = cmdEdit.Flag.String("go", "", "") + editJSON = cmdEdit.Flag.Bool("json", false, "") + editPrint = cmdEdit.Flag.Bool("print", false, "") + editModule = cmdEdit.Flag.String("module", "", "") + edits []func(*modfile.File) // edits specified in flags +) + +type flagFunc func(string) + +func (f flagFunc) String() string { return "" } +func (f flagFunc) Set(s string) error { f(s); return nil } + +func init() { + cmdEdit.Run = runEdit // break init cycle + + cmdEdit.Flag.Var(flagFunc(flagRequire), "require", "") + cmdEdit.Flag.Var(flagFunc(flagDropRequire), "droprequire", "") + cmdEdit.Flag.Var(flagFunc(flagExclude), "exclude", "") + cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "") + cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "") + cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "") + + base.AddBuildFlagsNX(&cmdEdit.Flag) +} + +func runEdit(cmd *base.Command, args []string) { + anyFlags := + *editModule != "" || + *editJSON || + *editPrint || + *editFmt || + len(edits) > 0 + + if !anyFlags { + base.Fatalf("go mod edit: no flags specified (see 'go help mod edit').") + } + + if *editJSON && *editPrint { + base.Fatalf("go mod edit: cannot use both -json and -print") + } + + if len(args) > 1 { + base.Fatalf("go mod edit: too many arguments") + } + var gomod string + if len(args) == 1 { + gomod = args[0] + } else { + modload.MustInit() + gomod = filepath.Join(modload.ModRoot, "go.mod") + } + + if *editModule != "" { + if err := module.CheckPath(*editModule); err != nil { + base.Fatalf("go mod: invalid -module: %v", err) + } + } + + // TODO(rsc): Implement -go= once we start advertising it. + + data, err := ioutil.ReadFile(gomod) + if err != nil { + base.Fatalf("go: %v", err) + } + + modFile, err := modfile.Parse(gomod, data, nil) + if err != nil { + base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gomod), err) + } + + if *editModule != "" { + modFile.AddModuleStmt(modload.CmdModModule) + } + + if len(edits) > 0 { + for _, edit := range edits { + edit(modFile) + } + } + modFile.SortBlocks() + modFile.Cleanup() // clean file after edits + + if *editJSON { + editPrintJSON(modFile) + return + } + + data, err = modFile.Format() + if err != nil { + base.Fatalf("go: %v", err) + } + + if *editPrint { + os.Stdout.Write(data) + return + } + + if err := ioutil.WriteFile(gomod, data, 0666); err != nil { + base.Fatalf("go: %v", err) + } +} + +// parsePathVersion parses -flag=arg expecting arg to be path@version. +func parsePathVersion(flag, arg string) (path, version string) { + i := strings.Index(arg, "@") + if i < 0 { + base.Fatalf("go mod: -%s=%s: need path@version", flag, arg) + } + path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:]) + if err := module.CheckPath(path); err != nil { + base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err) + } + + // We don't call modfile.CheckPathVersion, because that insists + // on versions being in semver form, but here we want to allow + // versions like "master" or "1234abcdef", which the go command will resolve + // the next time it runs (or during -fix). + // Even so, we need to make sure the version is a valid token. + if modfile.MustQuote(version) { + base.Fatalf("go mod: -%s=%s: invalid version %q", flag, arg, version) + } + + return path, version +} + +// parsePath parses -flag=arg expecting arg to be path (not path@version). +func parsePath(flag, arg string) (path string) { + if strings.Contains(arg, "@") { + base.Fatalf("go mod: -%s=%s: need just path, not path@version", flag, arg) + } + path = arg + if err := module.CheckPath(path); err != nil { + base.Fatalf("go mod: -%s=%s: invalid path: %v", flag, arg, err) + } + return path +} + +// parsePathVersionOptional parses path[@version], using adj to +// describe any errors. +func parsePathVersionOptional(adj, arg string, allowDirPath bool) (path, version string, err error) { + if i := strings.Index(arg, "@"); i < 0 { + path = arg + } else { + path, version = strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:]) + } + if err := module.CheckPath(path); err != nil { + if !allowDirPath || !modfile.IsDirectoryPath(path) { + return path, version, fmt.Errorf("invalid %s path: %v", adj, err) + } + } + if path != arg && modfile.MustQuote(version) { + return path, version, fmt.Errorf("invalid %s version: %q", adj, version) + } + return path, version, nil +} + +// flagRequire implements the -require flag. +func flagRequire(arg string) { + path, version := parsePathVersion("require", arg) + edits = append(edits, func(f *modfile.File) { + if err := f.AddRequire(path, version); err != nil { + base.Fatalf("go mod: -require=%s: %v", arg, err) + } + }) +} + +// flagDropRequire implements the -droprequire flag. +func flagDropRequire(arg string) { + path := parsePath("droprequire", arg) + edits = append(edits, func(f *modfile.File) { + if err := f.DropRequire(path); err != nil { + base.Fatalf("go mod: -droprequire=%s: %v", arg, err) + } + }) +} + +// flagExclude implements the -exclude flag. +func flagExclude(arg string) { + path, version := parsePathVersion("exclude", arg) + edits = append(edits, func(f *modfile.File) { + if err := f.AddExclude(path, version); err != nil { + base.Fatalf("go mod: -exclude=%s: %v", arg, err) + } + }) +} + +// flagDropExclude implements the -dropexclude flag. +func flagDropExclude(arg string) { + path, version := parsePathVersion("dropexclude", arg) + edits = append(edits, func(f *modfile.File) { + if err := f.DropExclude(path, version); err != nil { + base.Fatalf("go mod: -dropexclude=%s: %v", arg, err) + } + }) +} + +// flagReplace implements the -replace flag. +func flagReplace(arg string) { + var i int + if i = strings.Index(arg, "="); i < 0 { + base.Fatalf("go mod: -replace=%s: need old[@v]=new[@w] (missing =)", arg) + } + old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:]) + if strings.HasPrefix(new, ">") { + base.Fatalf("go mod: -replace=%s: separator between old and new is =, not =>", arg) + } + oldPath, oldVersion, err := parsePathVersionOptional("old", old, false) + if err != nil { + base.Fatalf("go mod: -replace=%s: %v", arg, err) + } + newPath, newVersion, err := parsePathVersionOptional("new", new, true) + if err != nil { + base.Fatalf("go mod: -replace=%s: %v", arg, err) + } + if newPath == new && !modfile.IsDirectoryPath(new) { + base.Fatalf("go mod: -replace=%s: unversioned new path must be local directory", arg) + } + + edits = append(edits, func(f *modfile.File) { + if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil { + base.Fatalf("go mod: -replace=%s: %v", arg, err) + } + }) +} + +// flagDropReplace implements the -dropreplace flag. +func flagDropReplace(arg string) { + path, version, err := parsePathVersionOptional("old", arg, true) + if err != nil { + base.Fatalf("go mod: -dropreplace=%s: %v", arg, err) + } + edits = append(edits, func(f *modfile.File) { + if err := f.DropReplace(path, version); err != nil { + base.Fatalf("go mod: -dropreplace=%s: %v", arg, err) + } + }) +} + +// fileJSON is the -json output data structure. +type fileJSON struct { + Module module.Version + Require []requireJSON + Exclude []module.Version + Replace []replaceJSON +} + +type requireJSON struct { + Path string + Version string `json:",omitempty"` + Indirect bool `json:",omitempty"` +} + +type replaceJSON struct { + Old module.Version + New module.Version +} + +// editPrintJSON prints the -json output. +func editPrintJSON(modFile *modfile.File) { + var f fileJSON + f.Module = modFile.Module.Mod + for _, r := range modFile.Require { + f.Require = append(f.Require, requireJSON{Path: r.Mod.Path, Version: r.Mod.Version, Indirect: r.Indirect}) + } + for _, x := range modFile.Exclude { + f.Exclude = append(f.Exclude, x.Mod) + } + for _, r := range modFile.Replace { + f.Replace = append(f.Replace, replaceJSON{r.Old, r.New}) + } + data, err := json.MarshalIndent(&f, "", "\t") + if err != nil { + base.Fatalf("go: internal error: %v", err) + } + data = append(data, '\n') + os.Stdout.Write(data) +} diff --git a/src/cmd/go/internal/modcmd/graph.go b/src/cmd/go/internal/modcmd/graph.go new file mode 100644 index 0000000000..5825c6d8ca --- /dev/null +++ b/src/cmd/go/internal/modcmd/graph.go @@ -0,0 +1,73 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go mod graph + +package modcmd + +import ( + "bufio" + "os" + "sort" + + "cmd/go/internal/base" + "cmd/go/internal/modload" + "cmd/go/internal/module" + "cmd/go/internal/par" +) + +var cmdGraph = &base.Command{ + UsageLine: "go mod graph", + Short: "print module requirement graph", + Long: ` +Graph prints the module requirement graph (with replacements applied) +in text form. Each line in the output has two space-separated fields: a module +and one of its requirements. Each module is identified as a string of the form +path@version, except for the main module, which has no @version suffix. + `, + Run: runGraph, +} + +func runGraph(cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go mod graph: graph takes no arguments") + } + modload.LoadBuildList() + + reqs := modload.MinReqs() + format := func(m module.Version) string { + if m.Version == "" { + return m.Path + } + return m.Path + "@" + m.Version + } + + // Note: using par.Work only to manage work queue. + // No parallelism here, so no locking. + var out []string + var deps int // index in out where deps start + var work par.Work + work.Add(modload.Target) + work.Do(1, func(item interface{}) { + m := item.(module.Version) + list, _ := reqs.Required(m) + for _, r := range list { + work.Add(r) + out = append(out, format(m)+" "+format(r)+"\n") + } + if m == modload.Target { + deps = len(out) + } + }) + + sort.Slice(out[deps:], func(i, j int) bool { + return out[deps+i][0] < out[deps+j][0] + }) + + w := bufio.NewWriter(os.Stdout) + for _, line := range out { + w.WriteString(line) + } + w.Flush() +} diff --git a/src/cmd/go/internal/modcmd/init.go b/src/cmd/go/internal/modcmd/init.go new file mode 100644 index 0000000000..f510a46262 --- /dev/null +++ b/src/cmd/go/internal/modcmd/init.go @@ -0,0 +1,41 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go mod init + +package modcmd + +import ( + "cmd/go/internal/base" + "cmd/go/internal/modload" + "os" +) + +var cmdInit = &base.Command{ + UsageLine: "go mod init [module]", + Short: "initialize new module in current directory", + Long: ` +Init initializes and writes a new go.mod to the current directory, +in effect creating a new module rooted at the current directory. +The file go.mod must not already exist. +If possible, init will guess the module path from import comments +(see 'go help importpath') or from version control configuration. +To override this guess, supply the module path as an argument. + `, + Run: runInit, +} + +func runInit(cmd *base.Command, args []string) { + modload.CmdModInit = true + if len(args) > 1 { + base.Fatalf("go mod init: too many arguments") + } + if len(args) == 1 { + modload.CmdModModule = args[0] + } + if _, err := os.Stat("go.mod"); err == nil { + base.Fatalf("go mod init: go.mod already exists") + } + modload.InitMod() // does all the hard work +} diff --git a/src/cmd/go/internal/modcmd/mod.go b/src/cmd/go/internal/modcmd/mod.go new file mode 100644 index 0000000000..f150cc9728 --- /dev/null +++ b/src/cmd/go/internal/modcmd/mod.go @@ -0,0 +1,31 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package modcmd implements the ``go mod'' command. +package modcmd + +import "cmd/go/internal/base" + +var CmdMod = &base.Command{ + UsageLine: "go mod", + Short: "module maintenance", + Long: `Go mod provides access to operations on modules. + +Note that support for modules is built into all the go commands, +not just 'go mod'. For example, day-to-day adding, removing, upgrading, +and downgrading of dependencies should be done using 'go get'. +See 'go help modules' for an overview of module functionality. + `, + + Commands: []*base.Command{ + cmdDownload, + cmdEdit, + cmdGraph, + cmdInit, + cmdTidy, + cmdVendor, + cmdVerify, + cmdWhy, + }, +} diff --git a/src/cmd/go/internal/modcmd/tidy.go b/src/cmd/go/internal/modcmd/tidy.go new file mode 100644 index 0000000000..f2063a9ea6 --- /dev/null +++ b/src/cmd/go/internal/modcmd/tidy.go @@ -0,0 +1,90 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// go mod tidy + +package modcmd + +import ( + "fmt" + "os" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + "cmd/go/internal/module" +) + +var cmdTidy = &base.Command{ + UsageLine: "go mod tidy [-v]", + Short: "add missing and remove unused modules", + Long: ` +Tidy makes sure go.mod matches the source code in the module. +It adds any missing modules necessary to build the current module's +packages and dependencies, and it removes unused modules that +don't provide any relevant packages. It also adds any missing entries +to go.sum and removes any unnecessary ones. + +The -v flag causes tidy to print information about removed modules +to standard error. + `, +} + +func init() { + cmdTidy.Run = runTidy // break init cycle + cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "") +} + +func runTidy(cmd *base.Command, args []string) { + if len(args) > 0 { + base.Fatalf("go mod tidy: no arguments allowed") + } + + // LoadALL adds missing modules. + // Remove unused modules. + used := make(map[module.Version]bool) + for _, pkg := range modload.LoadALL() { + used[modload.PackageModule(pkg)] = true + } + used[modload.Target] = true // note: LoadALL initializes Target + + inGoMod := make(map[string]bool) + for _, r := range modload.ModFile().Require { + inGoMod[r.Mod.Path] = true + } + + var keep []module.Version + for _, m := range modload.BuildList() { + if used[m] { + keep = append(keep, m) + } else if cfg.BuildV && inGoMod[m.Path] { + fmt.Fprintf(os.Stderr, "unused %s\n", m.Path) + } + } + modload.SetBuildList(keep) + modTidyGoSum() // updates memory copy; WriteGoMod on next line flushes it out + modload.WriteGoMod() +} + +// modTidyGoSum resets the go.sum file content +// to be exactly what's needed for the current go.mod. +func modTidyGoSum() { + // Assuming go.sum already has at least enough from the successful load, + // we only have to tell modfetch what needs keeping. + reqs := modload.Reqs() + keep := make(map[module.Version]bool) + var walk func(module.Version) + walk = func(m module.Version) { + keep[m] = true + list, _ := reqs.Required(m) + for _, r := range list { + if !keep[r] { + walk(r) + } + } + } + walk(modload.Target) + modfetch.TrimGoSum(keep) +} diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go new file mode 100644 index 0000000000..62e7458535 --- /dev/null +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -0,0 +1,200 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modcmd + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modload" + "cmd/go/internal/module" +) + +var cmdVendor = &base.Command{ + UsageLine: "go mod vendor [-v]", + Short: "make vendored copy of dependencies", + Long: ` +Vendor resets the main module's vendor directory to include all packages +needed to build and test all the main module's packages. +It does not include test code for vendored packages. + +The -v flag causes vendor to print the names of vendored +modules and packages to standard error. + `, + Run: runVendor, +} + +func init() { + cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "") +} + +func runVendor(cmd *base.Command, args []string) { + if len(args) != 0 { + base.Fatalf("go mod vendor: vendor takes no arguments") + } + pkgs := modload.LoadVendor() + + vdir := filepath.Join(modload.ModRoot, "vendor") + if err := os.RemoveAll(vdir); err != nil { + base.Fatalf("go vendor: %v", err) + } + + modpkgs := make(map[module.Version][]string) + for _, pkg := range pkgs { + m := modload.PackageModule(pkg) + if m == modload.Target { + continue + } + modpkgs[m] = append(modpkgs[m], pkg) + } + + var buf bytes.Buffer + for _, m := range modload.BuildList()[1:] { + if pkgs := modpkgs[m]; len(pkgs) > 0 { + repl := "" + if r := modload.Replacement(m); r.Path != "" { + repl = " => " + r.Path + if r.Version != "" { + repl += " " + r.Version + } + } + fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl) + if cfg.BuildV { + fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl) + } + for _, pkg := range pkgs { + fmt.Fprintf(&buf, "%s\n", pkg) + if cfg.BuildV { + fmt.Fprintf(os.Stderr, "%s\n", pkg) + } + vendorPkg(vdir, pkg) + } + } + } + if buf.Len() == 0 { + fmt.Fprintf(os.Stderr, "go: no dependencies to vendor\n") + return + } + if err := ioutil.WriteFile(filepath.Join(vdir, "modules.txt"), buf.Bytes(), 0666); err != nil { + base.Fatalf("go vendor: %v", err) + } +} + +func vendorPkg(vdir, pkg string) { + realPath := modload.ImportMap(pkg) + if realPath != pkg && modload.ImportMap(realPath) != "" { + fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg) + } + + dst := filepath.Join(vdir, pkg) + src := modload.PackageDir(realPath) + if src == "" { + fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath) + } + copyDir(dst, src, matchNonTest) + if m := modload.PackageModule(realPath); m.Path != "" { + copyMetadata(m.Path, realPath, dst, src) + } +} + +type metakey struct { + modPath string + dst string +} + +var copiedMetadata = make(map[metakey]bool) + +// copyMetadata copies metadata files from parents of src to parents of dst, +// stopping after processing the src parent for modPath. +func copyMetadata(modPath, pkg, dst, src string) { + for parent := 0; ; parent++ { + if copiedMetadata[metakey{modPath, dst}] { + break + } + copiedMetadata[metakey{modPath, dst}] = true + if parent > 0 { + copyDir(dst, src, matchMetadata) + } + if modPath == pkg { + break + } + pkg = filepath.Dir(pkg) + dst = filepath.Dir(dst) + src = filepath.Dir(src) + } +} + +// metaPrefixes is the list of metadata file prefixes. +// Vendoring copies metadata files from parents of copied directories. +// Note that this list could be arbitrarily extended, and it is longer +// in other tools (such as godep or dep). By using this limited set of +// prefixes and also insisting on capitalized file names, we are trying +// to nudge people toward more agreement on the naming +// and also trying to avoid false positives. +var metaPrefixes = []string{ + "AUTHORS", + "CONTRIBUTORS", + "COPYLEFT", + "COPYING", + "COPYRIGHT", + "LEGAL", + "LICENSE", + "NOTICE", + "PATENTS", +} + +// matchMetadata reports whether info is a metadata file. +func matchMetadata(info os.FileInfo) bool { + name := info.Name() + for _, p := range metaPrefixes { + if strings.HasPrefix(name, p) { + return true + } + } + return false +} + +// matchNonTest reports whether info is any non-test file (including non-Go files). +func matchNonTest(info os.FileInfo) bool { + return !strings.HasSuffix(info.Name(), "_test.go") +} + +// copyDir copies all regular files satisfying match(info) from src to dst. +func copyDir(dst, src string, match func(os.FileInfo) bool) { + files, err := ioutil.ReadDir(src) + if err != nil { + base.Fatalf("go vendor: %v", err) + } + if err := os.MkdirAll(dst, 0777); err != nil { + base.Fatalf("go vendor: %v", err) + } + for _, file := range files { + if file.IsDir() || !file.Mode().IsRegular() || !match(file) { + continue + } + r, err := os.Open(filepath.Join(src, file.Name())) + if err != nil { + base.Fatalf("go vendor: %v", err) + } + w, err := os.Create(filepath.Join(dst, file.Name())) + if err != nil { + base.Fatalf("go vendor: %v", err) + } + if _, err := io.Copy(w, r); err != nil { + base.Fatalf("go vendor: %v", err) + } + r.Close() + if err := w.Close(); err != nil { + base.Fatalf("go vendor: %v", err) + } + } +} diff --git a/src/cmd/go/internal/vgo/verify.go b/src/cmd/go/internal/modcmd/verify.go similarity index 62% rename from src/cmd/go/internal/vgo/verify.go rename to src/cmd/go/internal/modcmd/verify.go index d21c9d7673..381c18d58f 100644 --- a/src/cmd/go/internal/vgo/verify.go +++ b/src/cmd/go/internal/modcmd/verify.go @@ -2,54 +2,42 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package vgo +package modcmd import ( "bytes" "fmt" "io/ioutil" "os" - "path/filepath" "cmd/go/internal/base" "cmd/go/internal/dirhash" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" "cmd/go/internal/module" ) -var CmdVerify = &base.Command{ - UsageLine: "verify", - Run: runVerify, - Short: "verify downloaded modules against expected hashes", +var cmdVerify = &base.Command{ + UsageLine: "go mod verify", + Short: "verify dependencies have expected content", Long: ` Verify checks that the dependencies of the current module, -which are stored in a local downloaded source cache, -have not been modified since being downloaded. - -If all the modules are unmodified, verify prints - - all modules verified - -and exits successfully (status 0). Otherwise, verify reports -which modules have been changed and exits with a non-zero status. +which are stored in a local downloaded source cache, have not been +modified since being downloaded. If all the modules are unmodified, +verify prints "all modules verified." Otherwise it reports which +modules have been changed and causes 'go mod' to exit with a +non-zero status. `, + Run: runVerify, } func runVerify(cmd *base.Command, args []string) { - if Init(); !Enabled() { - base.Fatalf("vgo verify: cannot use outside module") - } if len(args) != 0 { - // TODO: take arguments - base.Fatalf("vgo verify: verify takes no arguments") + // NOTE(rsc): Could take a module pattern. + base.Fatalf("go mod verify: verify takes no arguments") } - - // Make go.mod consistent but don't load any packages. - InitMod() - iterate(func(*loader) {}) - writeGoMod() - ok := true - for _, mod := range buildList[1:] { + for _, mod := range modload.LoadBuildList()[1:] { ok = verifyMod(mod) && ok } if ok { @@ -59,10 +47,14 @@ func runVerify(cmd *base.Command, args []string) { func verifyMod(mod module.Version) bool { ok := true - zip := filepath.Join(srcV, "cache", mod.Path, "/@v/", mod.Version+".zip") - _, zipErr := os.Stat(zip) - dir := filepath.Join(srcV, mod.Path+"@"+mod.Version) - _, dirErr := os.Stat(dir) + zip, zipErr := modfetch.CachePath(mod, "zip") + if zipErr == nil { + _, zipErr = os.Stat(zip) + } + dir, dirErr := modfetch.DownloadDir(mod) + if dirErr == nil { + _, dirErr = os.Stat(dir) + } data, err := ioutil.ReadFile(zip + "hash") if err != nil { if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) { diff --git a/src/cmd/go/internal/modcmd/why.go b/src/cmd/go/internal/modcmd/why.go new file mode 100644 index 0000000000..03e0a039bc --- /dev/null +++ b/src/cmd/go/internal/modcmd/why.go @@ -0,0 +1,121 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modcmd + +import ( + "cmd/go/internal/base" + "cmd/go/internal/modload" + "cmd/go/internal/module" + "fmt" + "strings" +) + +var cmdWhy = &base.Command{ + UsageLine: "go mod why [-m] [-vendor] packages...", + Short: "explain why packages or modules are needed", + Long: ` +Why shows a shortest path in the import graph from the main module to +each of the listed packages. If the -m flag is given, why treats the +arguments as a list of modules and finds a path to any package in each +of the modules. + +By default, why queries the graph of packages matched by "go list all", +which includes tests for reachable packages. The -vendor flag causes why +to exclude tests of dependencies. + +The output is a sequence of stanzas, one for each package or module +name on the command line, separated by blank lines. Each stanza begins +with a comment line "# package" or "# module" giving the target +package or module. Subsequent lines give a path through the import +graph, one package per line. If the package or module is not +referenced from the main module, the stanza will display a single +parenthesized note indicating that fact. + +For example: + + $ go mod why golang.org/x/text/language golang.org/x/text/encoding + # golang.org/x/text/language + rsc.io/quote + rsc.io/sampler + golang.org/x/text/language + + # golang.org/x/text/encoding + (main module does not need package golang.org/x/text/encoding) + $ + `, +} + +var ( + whyM = cmdWhy.Flag.Bool("m", false, "") + whyVendor = cmdWhy.Flag.Bool("vendor", false, "") +) + +func init() { + cmdWhy.Run = runWhy // break init cycle +} + +func runWhy(cmd *base.Command, args []string) { + loadALL := modload.LoadALL + if *whyVendor { + loadALL = modload.LoadVendor + } + if *whyM { + listU := false + listVersions := false + for _, arg := range args { + if strings.Contains(arg, "@") { + base.Fatalf("go mod why: module query not allowed") + } + } + mods := modload.ListModules(args, listU, listVersions) + byModule := make(map[module.Version][]string) + for _, path := range loadALL() { + m := modload.PackageModule(path) + if m.Path != "" { + byModule[m] = append(byModule[m], path) + } + } + sep := "" + for _, m := range mods { + best := "" + bestDepth := 1000000000 + for _, path := range byModule[module.Version{Path: m.Path, Version: m.Version}] { + d := modload.WhyDepth(path) + if d > 0 && d < bestDepth { + best = path + bestDepth = d + } + } + why := modload.Why(best) + if why == "" { + vendoring := "" + if *whyVendor { + vendoring = " to vendor" + } + why = "(main module does not need" + vendoring + " module " + m.Path + ")\n" + } + fmt.Printf("%s# %s\n%s", sep, m.Path, why) + sep = "\n" + } + } else { + matches := modload.ImportPaths(args) // resolve to packages + loadALL() // rebuild graph, from main module (not from named packages) + sep := "" + for _, m := range matches { + for _, path := range m.Pkgs { + why := modload.Why(path) + if why == "" { + vendoring := "" + if *whyVendor { + vendoring = " to vendor" + } + why = "(main module does not need" + vendoring + " package " + path + ")\n" + } + fmt.Printf("%s# %s\n%s", sep, path, why) + sep = "\n" + } + } + } +} diff --git a/src/cmd/go/internal/modfetch/convert.go b/src/cmd/go/internal/modconv/convert.go similarity index 51% rename from src/cmd/go/internal/modfetch/convert.go rename to src/cmd/go/internal/modconv/convert.go index 5c482be003..6fc6718e47 100644 --- a/src/cmd/go/internal/modfetch/convert.go +++ b/src/cmd/go/internal/modconv/convert.go @@ -2,16 +2,20 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package modfetch +package modconv import ( "fmt" "os" "sort" "strings" + "sync" - "cmd/go/internal/modconv" + "cmd/go/internal/base" + "cmd/go/internal/modfetch" "cmd/go/internal/modfile" + "cmd/go/internal/module" + "cmd/go/internal/par" "cmd/go/internal/semver" ) @@ -23,56 +27,64 @@ func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error { if i >= 0 { j = strings.LastIndex(file[:i], "/") } - convert := modconv.Converters[file[i+1:]] + convert := Converters[file[i+1:]] if convert == nil && j != -2 { - convert = modconv.Converters[file[j+1:]] + convert = Converters[file[j+1:]] } if convert == nil { return fmt.Errorf("unknown legacy config file %s", file) } - require, err := convert(file, data) + mf, err := convert(file, data) if err != nil { return fmt.Errorf("parsing %s: %v", file, err) } // Convert requirements block, which may use raw SHA1 hashes as versions, // to valid semver requirement list, respecting major versions. - need := make(map[string]string) - for _, r := range require { - if r.Path == "" { + var work par.Work + for _, r := range mf.Require { + m := r.Mod + if m.Path == "" { continue } - - // TODO: Something better here. - if strings.HasPrefix(r.Path, "github.com/") || strings.HasPrefix(r.Path, "golang.org/x/") { - f := strings.Split(r.Path, "/") - if len(f) > 3 { - r.Path = strings.Join(f[:3], "/") - } - } - - repo, err := Lookup(r.Path) - if err != nil { - fmt.Fprintf(os.Stderr, "vgo: lookup %s: %v\n", r.Path, err) - continue - } - info, err := repo.Stat(r.Version) - if err != nil { - fmt.Fprintf(os.Stderr, "vgo: stat %s@%s: %v\n", r.Path, r.Version, err) - continue - } - path := repo.ModulePath() - need[path] = semver.Max(need[path], info.Version) + work.Add(r.Mod) } + var ( + mu sync.Mutex + need = make(map[string]string) + ) + work.Do(10, func(item interface{}) { + r := item.(module.Version) + repo, info, err := modfetch.ImportRepoRev(r.Path, r.Version) + if err != nil { + fmt.Fprintf(os.Stderr, "go: converting %s: stat %s@%s: %v\n", base.ShortPath(file), r.Path, r.Version, err) + return + } + mu.Lock() + path := repo.ModulePath() + // Don't use semver.Max here; need to preserve +incompatible suffix. + if v, ok := need[path]; !ok || semver.Compare(v, info.Version) < 0 { + need[path] = info.Version + } + mu.Unlock() + }) + var paths []string for path := range need { paths = append(paths, path) } sort.Strings(paths) for _, path := range paths { - f.AddRequire(path, need[path]) + f.AddNewRequire(path, need[path], false) } + for _, r := range mf.Replace { + err := f.AddReplace(r.Old.Path, r.Old.Version, r.New.Path, r.New.Version) + if err != nil { + return fmt.Errorf("add replace: %v", err) + } + } + f.Cleanup() return nil } diff --git a/src/cmd/go/internal/modfetch/convert_test.go b/src/cmd/go/internal/modconv/convert_test.go similarity index 55% rename from src/cmd/go/internal/modfetch/convert_test.go rename to src/cmd/go/internal/modconv/convert_test.go index 03ae1569f0..ad27abb8ef 100644 --- a/src/cmd/go/internal/modfetch/convert_test.go +++ b/src/cmd/go/internal/modconv/convert_test.go @@ -2,19 +2,49 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package modfetch +package modconv import ( "bytes" + "fmt" "internal/testenv" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" "strings" "testing" "cmd/go/internal/cfg" - "cmd/go/internal/modconv" + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" "cmd/go/internal/modfile" + "cmd/go/internal/module" ) +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + if _, err := exec.LookPath("git"); err != nil { + fmt.Fprintln(os.Stderr, "skipping because git binary not found") + fmt.Println("PASS") + return 0 + } + + dir, err := ioutil.TempDir("", "modconv-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + modfetch.PkgMod = filepath.Join(dir, "pkg/mod") + codehost.WorkRoot = filepath.Join(dir, "codework") + + return m.Run() +} + func TestConvertLegacyConfig(t *testing.T) { testenv.MustHaveExternalNetwork(t) @@ -31,28 +61,36 @@ func TestConvertLegacyConfig(t *testing.T) { vers string gomod string }{ - { - // Gopkg.lock parsing. - "github.com/golang/dep", "v0.4.0", - `module github.com/golang/dep + /* + Different versions of git seem to find or not find + github.com/Masterminds/semver's a93e51b5a57e, + which is an unmerged pull request. + We'd rather not provide access to unmerged pull requests, + so the line is removed from the golden file here, + but some git commands still find it somehow. - require ( - github.com/Masterminds/semver v0.0.0-20170726230514-a93e51b5a57e - github.com/Masterminds/vcs v1.11.1 - github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7 - github.com/boltdb/bolt v1.3.1 - github.com/go-yaml/yaml v0.0.0-20170407172122-cd8b52f8269e - github.com/golang/protobuf v0.0.0-20170901042739-5afd06f9d81a - github.com/jmank88/nuts v0.3.0 - github.com/nightlyone/lockfile v0.0.0-20170707060451-e83dc5e7bba0 - github.com/pelletier/go-toml v0.0.0-20171218135716-b8b5e7696574 - github.com/pkg/errors v0.8.0 - github.com/sdboyer/constext v0.0.0-20170321163424-836a14457353 - golang.org/x/net v0.0.0-20170828231752-66aacef3dd8a - golang.org/x/sync v0.0.0-20170517211232-f52d1811a629 - golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea - )`, - }, + { + // Gopkg.lock parsing. + "github.com/golang/dep", "v0.4.0", + `module github.com/golang/dep + + require ( + github.com/Masterminds/vcs v1.11.1 + github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7 + github.com/boltdb/bolt v1.3.1 + github.com/go-yaml/yaml v0.0.0-20170407172122-cd8b52f8269e + github.com/golang/protobuf v0.0.0-20170901042739-5afd06f9d81a + github.com/jmank88/nuts v0.3.0 + github.com/nightlyone/lockfile v0.0.0-20170707060451-e83dc5e7bba0 + github.com/pelletier/go-toml v0.0.0-20171218135716-b8b5e7696574 + github.com/pkg/errors v0.8.0 + github.com/sdboyer/constext v0.0.0-20170321163424-836a14457353 + golang.org/x/net v0.0.0-20170828231752-66aacef3dd8a + golang.org/x/sync v0.0.0-20170517211232-f52d1811a629 + golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea + )`, + }, + */ // TODO: https://github.com/docker/distribution uses vendor.conf @@ -65,7 +103,7 @@ func TestConvertLegacyConfig(t *testing.T) { require ( github.com/AdRoll/goamz v0.0.0-20150130162828-d3664b76d905 github.com/MSOpenTech/azure-sdk-for-go v0.0.0-20150323223030-d90753bcad2e - github.com/Sirupsen/logrus v0.0.0-20150409230825-55eb11d21d2a + github.com/Sirupsen/logrus v0.7.3 github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b github.com/bugsnag/panicwrap v0.0.0-20141110184334-e5f9854865b9 @@ -95,7 +133,7 @@ func TestConvertLegacyConfig(t *testing.T) { cloud.google.com/go v0.18.0 github.com/fishy/fsdb v0.0.0-20180217030800-5527ded01371 github.com/golang/protobuf v1.0.0 - github.com/googleapis/gax-go v0.0.0-20170915024731-317e0006254c + github.com/googleapis/gax-go v2.0.0+incompatible golang.org/x/net v0.0.0-20180216171745-136a25c244d3 golang.org/x/oauth2 v0.0.0-20180207181906-543e37812f10 golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54 @@ -117,23 +155,32 @@ func TestConvertLegacyConfig(t *testing.T) { if err != nil { t.Fatal(err) } - repo, err := Lookup(tt.path) + + dir, err := modfetch.Download(module.Version{Path: tt.path, Version: tt.vers}) if err != nil { t.Fatal(err) } - out, err := repo.GoMod(tt.vers) - if err != nil { - t.Fatal(err) - } - prefix := modconv.Prefix + "\n" - if !bytes.HasPrefix(out, []byte(prefix)) { - t.Fatalf("go.mod missing prefix %q:\n%s", prefix, out) - } - out = out[len(prefix):] - if !bytes.Equal(out, want) { - t.Fatalf("final go.mod:\n%s\n\nwant:\n%s", out, want) + for name := range Converters { + file := filepath.Join(dir, name) + data, err := ioutil.ReadFile(file) + if err == nil { + f := new(modfile.File) + f.AddModuleStmt(tt.path) + if err := ConvertLegacyConfig(f, filepath.ToSlash(file), data); err != nil { + t.Fatal(err) + } + out, err := f.Format() + if err != nil { + t.Fatalf("format after conversion: %v", err) + } + if !bytes.Equal(out, want) { + t.Fatalf("final go.mod:\n%s\n\nwant:\n%s", out, want) + } + return + } } + t.Fatalf("no converter found for %s@%s", tt.path, tt.vers) }) } } diff --git a/src/cmd/go/internal/modconv/dep.go b/src/cmd/go/internal/modconv/dep.go index 28dd28a3c2..690c206a13 100644 --- a/src/cmd/go/internal/modconv/dep.go +++ b/src/cmd/go/internal/modconv/dep.go @@ -9,11 +9,13 @@ import ( "strconv" "strings" + "cmd/go/internal/modfile" "cmd/go/internal/module" "cmd/go/internal/semver" ) -func ParseGopkgLock(file string, data []byte) ([]module.Version, error) { +func ParseGopkgLock(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) var list []module.Version var r *module.Version for lineno, line := range strings.Split(string(data), "\n") { @@ -66,6 +68,7 @@ func ParseGopkgLock(file string, data []byte) ([]module.Version, error) { if r.Path == "" || r.Version == "" { return nil, fmt.Errorf("%s: empty [[projects]] stanza (%s)", file, r.Path) } + mf.Require = append(mf.Require, &modfile.Require{Mod: r}) } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/glide.go b/src/cmd/go/internal/modconv/glide.go index abe88c4fc2..3bc675fcc0 100644 --- a/src/cmd/go/internal/modconv/glide.go +++ b/src/cmd/go/internal/modconv/glide.go @@ -5,12 +5,14 @@ package modconv import ( - "cmd/go/internal/module" "strings" + + "cmd/go/internal/modfile" + "cmd/go/internal/module" ) -func ParseGlideLock(file string, data []byte) ([]module.Version, error) { - var list []module.Version +func ParseGlideLock(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) imports := false name := "" for lineno, line := range strings.Split(string(data), "\n") { @@ -32,9 +34,9 @@ func ParseGlideLock(file string, data []byte) ([]module.Version, error) { if strings.HasPrefix(line, " version:") { version := strings.TrimSpace(line[len(" version:"):]) if name != "" && version != "" { - list = append(list, module.Version{Path: name, Version: version}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: name, Version: version}}) } } } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/glock.go b/src/cmd/go/internal/modconv/glock.go index 57eb66ebf9..1b786a939c 100644 --- a/src/cmd/go/internal/modconv/glock.go +++ b/src/cmd/go/internal/modconv/glock.go @@ -7,17 +7,18 @@ package modconv import ( "strings" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseGLOCKFILE(file string, data []byte) ([]module.Version, error) { - var list []module.Version +func ParseGLOCKFILE(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) for lineno, line := range strings.Split(string(data), "\n") { lineno++ f := strings.Fields(line) if len(f) >= 2 && f[0] != "cmd" { - list = append(list, module.Version{Path: f[0], Version: f[1]}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}}) } } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/godeps.go b/src/cmd/go/internal/modconv/godeps.go index 904fd70ea2..6398dbe7cd 100644 --- a/src/cmd/go/internal/modconv/godeps.go +++ b/src/cmd/go/internal/modconv/godeps.go @@ -7,10 +7,11 @@ package modconv import ( "encoding/json" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseGodepsJSON(file string, data []byte) ([]module.Version, error) { +func ParseGodepsJSON(file string, data []byte) (*modfile.File, error) { var cfg struct { ImportPath string Deps []struct { @@ -21,9 +22,9 @@ func ParseGodepsJSON(file string, data []byte) ([]module.Version, error) { if err := json.Unmarshal(data, &cfg); err != nil { return nil, err } - var list []module.Version + mf := new(modfile.File) for _, d := range cfg.Deps { - list = append(list, module.Version{Path: d.ImportPath, Version: d.Rev}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Rev}}) } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/modconv.go b/src/cmd/go/internal/modconv/modconv.go index b689b52dee..a58673382e 100644 --- a/src/cmd/go/internal/modconv/modconv.go +++ b/src/cmd/go/internal/modconv/modconv.go @@ -4,9 +4,9 @@ package modconv -import "cmd/go/internal/module" +import "cmd/go/internal/modfile" -var Converters = map[string]func(string, []byte) ([]module.Version, error){ +var Converters = map[string]func(string, []byte) (*modfile.File, error){ "GLOCKFILE": ParseGLOCKFILE, "Godeps/Godeps.json": ParseGodepsJSON, "Gopkg.lock": ParseGopkgLock, @@ -17,9 +17,3 @@ var Converters = map[string]func(string, []byte) ([]module.Version, error){ "vendor/manifest": ParseVendorManifest, "vendor/vendor.json": ParseVendorJSON, } - -// Prefix is a line we write at the top of auto-converted go.mod files -// for dependencies before caching them. -// In case of bugs in the converter, if we bump this version number, -// then all the cached copies will be ignored. -const Prefix = "//vgo 0.0.4\n" diff --git a/src/cmd/go/internal/modconv/modconv_test.go b/src/cmd/go/internal/modconv/modconv_test.go index 04a1db3f84..353161bc5a 100644 --- a/src/cmd/go/internal/modconv/modconv_test.go +++ b/src/cmd/go/internal/modconv/modconv_test.go @@ -7,7 +7,6 @@ package modconv import ( "bytes" "fmt" - "internal/testenv" "io/ioutil" "path/filepath" "testing" @@ -26,8 +25,6 @@ var extMap = map[string]string{ } func Test(t *testing.T) { - testenv.MustHaveExternalNetwork(t) - tests, _ := filepath.Glob("testdata/*") if len(tests) == 0 { t.Fatalf("no tests found") @@ -58,8 +55,8 @@ func Test(t *testing.T) { t.Error(err) } var buf bytes.Buffer - for _, r := range out { - fmt.Fprintf(&buf, "%s %s\n", r.Path, r.Version) + for _, r := range out.Require { + fmt.Fprintf(&buf, "%s %s\n", r.Mod.Path, r.Mod.Version) } if !bytes.Equal(buf.Bytes(), want) { t.Errorf("have:\n%s\nwant:\n%s", buf.Bytes(), want) diff --git a/src/cmd/go/internal/modconv/tsv.go b/src/cmd/go/internal/modconv/tsv.go index fd3364934f..feba181e05 100644 --- a/src/cmd/go/internal/modconv/tsv.go +++ b/src/cmd/go/internal/modconv/tsv.go @@ -7,17 +7,18 @@ package modconv import ( "strings" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseDependenciesTSV(file string, data []byte) ([]module.Version, error) { - var list []module.Version +func ParseDependenciesTSV(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) for lineno, line := range strings.Split(string(data), "\n") { lineno++ f := strings.Split(line, "\t") if len(f) >= 3 { - list = append(list, module.Version{Path: f[0], Version: f[2]}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[2]}}) } } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/vconf.go b/src/cmd/go/internal/modconv/vconf.go index 5d3cd3c917..a9a8e62518 100644 --- a/src/cmd/go/internal/modconv/vconf.go +++ b/src/cmd/go/internal/modconv/vconf.go @@ -7,11 +7,12 @@ package modconv import ( "strings" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseVendorConf(file string, data []byte) ([]module.Version, error) { - var list []module.Version +func ParseVendorConf(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) for lineno, line := range strings.Split(string(data), "\n") { lineno++ if i := strings.Index(line, "#"); i >= 0 { @@ -19,8 +20,8 @@ func ParseVendorConf(file string, data []byte) ([]module.Version, error) { } f := strings.Fields(line) if len(f) >= 2 { - list = append(list, module.Version{Path: f[0], Version: f[1]}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: f[0], Version: f[1]}}) } } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/vjson.go b/src/cmd/go/internal/modconv/vjson.go index 38b0a685ad..eec86b7339 100644 --- a/src/cmd/go/internal/modconv/vjson.go +++ b/src/cmd/go/internal/modconv/vjson.go @@ -7,10 +7,11 @@ package modconv import ( "encoding/json" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseVendorJSON(file string, data []byte) ([]module.Version, error) { +func ParseVendorJSON(file string, data []byte) (*modfile.File, error) { var cfg struct { Package []struct { Path string @@ -20,9 +21,9 @@ func ParseVendorJSON(file string, data []byte) ([]module.Version, error) { if err := json.Unmarshal(data, &cfg); err != nil { return nil, err } - var list []module.Version + mf := new(modfile.File) for _, d := range cfg.Package { - list = append(list, module.Version{Path: d.Path, Version: d.Revision}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.Path, Version: d.Revision}}) } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/vmanifest.go b/src/cmd/go/internal/modconv/vmanifest.go index f2cf0f58f2..c0ef2a9862 100644 --- a/src/cmd/go/internal/modconv/vmanifest.go +++ b/src/cmd/go/internal/modconv/vmanifest.go @@ -7,10 +7,11 @@ package modconv import ( "encoding/json" + "cmd/go/internal/modfile" "cmd/go/internal/module" ) -func ParseVendorManifest(file string, data []byte) ([]module.Version, error) { +func ParseVendorManifest(file string, data []byte) (*modfile.File, error) { var cfg struct { Dependencies []struct { ImportPath string @@ -20,9 +21,9 @@ func ParseVendorManifest(file string, data []byte) ([]module.Version, error) { if err := json.Unmarshal(data, &cfg); err != nil { return nil, err } - var list []module.Version + mf := new(modfile.File) for _, d := range cfg.Dependencies { - list = append(list, module.Version{Path: d.ImportPath, Version: d.Revision}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: d.ImportPath, Version: d.Revision}}) } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modconv/vyml.go b/src/cmd/go/internal/modconv/vyml.go index e2ea9e3e9c..0f017a3c7a 100644 --- a/src/cmd/go/internal/modconv/vyml.go +++ b/src/cmd/go/internal/modconv/vyml.go @@ -5,12 +5,14 @@ package modconv import ( - "cmd/go/internal/module" "strings" + + "cmd/go/internal/modfile" + "cmd/go/internal/module" ) -func ParseVendorYML(file string, data []byte) ([]module.Version, error) { - var list []module.Version +func ParseVendorYML(file string, data []byte) (*modfile.File, error) { + mf := new(modfile.File) vendors := false path := "" for lineno, line := range strings.Split(string(data), "\n") { @@ -32,9 +34,9 @@ func ParseVendorYML(file string, data []byte) ([]module.Version, error) { if strings.HasPrefix(line, " rev:") { rev := strings.TrimSpace(line[len(" rev:"):]) if path != "" && rev != "" { - list = append(list, module.Version{Path: path, Version: rev}) + mf.Require = append(mf.Require, &modfile.Require{Mod: module.Version{Path: path, Version: rev}}) } } } - return list, nil + return mf, nil } diff --git a/src/cmd/go/internal/modfetch/bitbucket/fetch.go b/src/cmd/go/internal/modfetch/bitbucket/fetch.go deleted file mode 100644 index c077a3eb74..0000000000 --- a/src/cmd/go/internal/modfetch/bitbucket/fetch.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package bitbucket - -import ( - "fmt" - "strings" - - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/gitrepo" -) - -func Lookup(path string) (codehost.Repo, error) { - f := strings.Split(path, "/") - if len(f) < 3 || f[0] != "bitbucket.org" { - return nil, fmt.Errorf("bitbucket repo must be bitbucket.org/org/project") - } - path = f[0] + "/" + f[1] + "/" + f[2] - return gitrepo.Repo("https://"+path, path) -} diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go new file mode 100644 index 0000000000..1f9cc96c3e --- /dev/null +++ b/src/cmd/go/internal/modfetch/cache.go @@ -0,0 +1,522 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modfetch + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" + "cmd/go/internal/par" + "cmd/go/internal/semver" +) + +var QuietLookup bool // do not print about lookups + +var PkgMod string // $GOPATH/pkg/mod; set by package modload + +func cacheDir(path string) (string, error) { + if PkgMod == "" { + return "", fmt.Errorf("internal error: modfetch.PkgMod not set") + } + enc, err := module.EncodePath(path) + if err != nil { + return "", err + } + return filepath.Join(PkgMod, "cache/download", enc, "/@v"), nil +} + +func CachePath(m module.Version, suffix string) (string, error) { + dir, err := cacheDir(m.Path) + if err != nil { + return "", err + } + if !semver.IsValid(m.Version) { + return "", fmt.Errorf("non-semver module version %q", m.Version) + } + if module.CanonicalVersion(m.Version) != m.Version { + return "", fmt.Errorf("non-canonical module version %q", m.Version) + } + encVer, err := module.EncodeVersion(m.Version) + if err != nil { + return "", err + } + return filepath.Join(dir, encVer+"."+suffix), nil +} + +func DownloadDir(m module.Version) (string, error) { + if PkgMod == "" { + return "", fmt.Errorf("internal error: modfetch.PkgMod not set") + } + enc, err := module.EncodePath(m.Path) + if err != nil { + return "", err + } + if !semver.IsValid(m.Version) { + return "", fmt.Errorf("non-semver module version %q", m.Version) + } + if module.CanonicalVersion(m.Version) != m.Version { + return "", fmt.Errorf("non-canonical module version %q", m.Version) + } + encVer, err := module.EncodeVersion(m.Version) + if err != nil { + return "", err + } + return filepath.Join(PkgMod, enc+"@"+encVer), nil +} + +// A cachingRepo is a cache around an underlying Repo, +// avoiding redundant calls to ModulePath, Versions, Stat, Latest, and GoMod (but not Zip). +// It is also safe for simultaneous use by multiple goroutines +// (so that it can be returned from Lookup multiple times). +// It serializes calls to the underlying Repo. +type cachingRepo struct { + path string + cache par.Cache // cache for all operations + r Repo +} + +func newCachingRepo(r Repo) *cachingRepo { + return &cachingRepo{ + r: r, + path: r.ModulePath(), + } +} + +func (r *cachingRepo) ModulePath() string { + return r.path +} + +func (r *cachingRepo) Versions(prefix string) ([]string, error) { + type cached struct { + list []string + err error + } + c := r.cache.Do("versions:"+prefix, func() interface{} { + list, err := r.r.Versions(prefix) + return cached{list, err} + }).(cached) + + if c.err != nil { + return nil, c.err + } + return append([]string(nil), c.list...), nil +} + +type cachedInfo struct { + info *RevInfo + err error +} + +func (r *cachingRepo) Stat(rev string) (*RevInfo, error) { + c := r.cache.Do("stat:"+rev, func() interface{} { + file, info, err := readDiskStat(r.path, rev) + if err == nil { + return cachedInfo{info, nil} + } + + if !QuietLookup { + fmt.Fprintf(os.Stderr, "go: finding %s %s\n", r.path, rev) + } + info, err = r.r.Stat(rev) + if err == nil { + if err := writeDiskStat(file, info); err != nil { + fmt.Fprintf(os.Stderr, "go: writing stat cache: %v\n", err) + } + // If we resolved, say, 1234abcde to v0.0.0-20180604122334-1234abcdef78, + // then save the information under the proper version, for future use. + if info.Version != rev { + r.cache.Do("stat:"+info.Version, func() interface{} { + return cachedInfo{info, err} + }) + } + } + return cachedInfo{info, err} + }).(cachedInfo) + + if c.err != nil { + return nil, c.err + } + info := *c.info + return &info, nil +} + +func (r *cachingRepo) Latest() (*RevInfo, error) { + c := r.cache.Do("latest:", func() interface{} { + if !QuietLookup { + fmt.Fprintf(os.Stderr, "go: finding %s latest\n", r.path) + } + info, err := r.r.Latest() + + // Save info for likely future Stat call. + if err == nil { + r.cache.Do("stat:"+info.Version, func() interface{} { + return cachedInfo{info, err} + }) + if file, _, err := readDiskStat(r.path, info.Version); err != nil { + writeDiskStat(file, info) + } + } + + return cachedInfo{info, err} + }).(cachedInfo) + + if c.err != nil { + return nil, c.err + } + info := *c.info + return &info, nil +} + +func (r *cachingRepo) GoMod(rev string) ([]byte, error) { + type cached struct { + text []byte + err error + } + c := r.cache.Do("gomod:"+rev, func() interface{} { + file, text, err := readDiskGoMod(r.path, rev) + if err == nil { + // Note: readDiskGoMod already called checkGoMod. + return cached{text, nil} + } + + // Convert rev to canonical version + // so that we use the right identifier in the go.sum check. + info, err := r.Stat(rev) + if err != nil { + return cached{nil, err} + } + rev = info.Version + + text, err = r.r.GoMod(rev) + if err == nil { + checkGoMod(r.path, rev, text) + if err := writeDiskGoMod(file, text); err != nil { + fmt.Fprintf(os.Stderr, "go: writing go.mod cache: %v\n", err) + } + } + return cached{text, err} + }).(cached) + + if c.err != nil { + return nil, c.err + } + return append([]byte(nil), c.text...), nil +} + +func (r *cachingRepo) Zip(version, tmpdir string) (string, error) { + return r.r.Zip(version, tmpdir) +} + +// Stat is like Lookup(path).Stat(rev) but avoids the +// repository path resolution in Lookup if the result is +// already cached on local disk. +func Stat(path, rev string) (*RevInfo, error) { + _, info, err := readDiskStat(path, rev) + if err == nil { + return info, nil + } + repo, err := Lookup(path) + if err != nil { + return nil, err + } + return repo.Stat(rev) +} + +// InfoFile is like Stat but returns the name of the file containing +// the cached information. +func InfoFile(path, version string) (string, error) { + if !semver.IsValid(version) { + return "", fmt.Errorf("invalid version %q", version) + } + if _, err := Stat(path, version); err != nil { + return "", err + } + // Stat should have populated the disk cache for us. + file, _, err := readDiskStat(path, version) + if err != nil { + return "", err + } + return file, nil +} + +// GoMod is like Lookup(path).GoMod(rev) but avoids the +// repository path resolution in Lookup if the result is +// already cached on local disk. +func GoMod(path, rev string) ([]byte, error) { + // Convert commit hash to pseudo-version + // to increase cache hit rate. + if !semver.IsValid(rev) { + info, err := Stat(path, rev) + if err != nil { + return nil, err + } + rev = info.Version + } + _, data, err := readDiskGoMod(path, rev) + if err == nil { + return data, nil + } + repo, err := Lookup(path) + if err != nil { + return nil, err + } + return repo.GoMod(rev) +} + +// GoModFile is like GoMod but returns the name of the file containing +// the cached information. +func GoModFile(path, version string) (string, error) { + if !semver.IsValid(version) { + return "", fmt.Errorf("invalid version %q", version) + } + if _, err := GoMod(path, version); err != nil { + return "", err + } + // GoMod should have populated the disk cache for us. + file, _, err := readDiskGoMod(path, version) + if err != nil { + return "", err + } + return file, nil +} + +// GoModSum returns the go.sum entry for the module version's go.mod file. +// (That is, it returns the entry listed in go.sum as "path version/go.mod".) +func GoModSum(path, version string) (string, error) { + if !semver.IsValid(version) { + return "", fmt.Errorf("invalid version %q", version) + } + data, err := GoMod(path, version) + if err != nil { + return "", err + } + sum, err := goModSum(data) + if err != nil { + return "", err + } + return sum, nil +} + +var errNotCached = fmt.Errorf("not in cache") + +// readDiskStat reads a cached stat result from disk, +// returning the name of the cache file and the result. +// If the read fails, the caller can use +// writeDiskStat(file, info) to write a new cache entry. +func readDiskStat(path, rev string) (file string, info *RevInfo, err error) { + file, data, err := readDiskCache(path, rev, "info") + if err != nil { + if file, info, err := readDiskStatByHash(path, rev); err == nil { + return file, info, nil + } + return file, nil, err + } + info = new(RevInfo) + if err := json.Unmarshal(data, info); err != nil { + return file, nil, errNotCached + } + // The disk might have stale .info files that have Name and Short fields set. + // We want to canonicalize to .info files with those fields omitted. + // Remarshal and update the cache file if needed. + data2, err := json.Marshal(info) + if err == nil && !bytes.Equal(data2, data) { + writeDiskCache(file, data) + } + return file, info, nil +} + +// readDiskStatByHash is a fallback for readDiskStat for the case +// where rev is a commit hash instead of a proper semantic version. +// In that case, we look for a cached pseudo-version that matches +// the commit hash. If we find one, we use it. +// This matters most for converting legacy package management +// configs, when we are often looking up commits by full hash. +// Without this check we'd be doing network I/O to the remote repo +// just to find out about a commit we already know about +// (and have cached under its pseudo-version). +func readDiskStatByHash(path, rev string) (file string, info *RevInfo, err error) { + if PkgMod == "" { + // Do not download to current directory. + return "", nil, errNotCached + } + + if !codehost.AllHex(rev) || len(rev) < 12 { + return "", nil, errNotCached + } + rev = rev[:12] + cdir, err := cacheDir(path) + if err != nil { + return "", nil, errNotCached + } + dir, err := os.Open(cdir) + if err != nil { + return "", nil, errNotCached + } + names, err := dir.Readdirnames(-1) + dir.Close() + if err != nil { + return "", nil, errNotCached + } + suffix := "-" + rev + ".info" + for _, name := range names { + if strings.HasSuffix(name, suffix) && IsPseudoVersion(strings.TrimSuffix(name, ".info")) { + return readDiskStat(path, strings.TrimSuffix(name, ".info")) + } + } + return "", nil, errNotCached +} + +// oldVgoPrefix is the prefix in the old auto-generated cached go.mod files. +// We stopped trying to auto-generate the go.mod files. Now we use a trivial +// go.mod with only a module line, and we've dropped the version prefix +// entirely. If we see a version prefix, that means we're looking at an old copy +// and should ignore it. +var oldVgoPrefix = []byte("//vgo 0.0.") + +// readDiskGoMod reads a cached stat result from disk, +// returning the name of the cache file and the result. +// If the read fails, the caller can use +// writeDiskGoMod(file, data) to write a new cache entry. +func readDiskGoMod(path, rev string) (file string, data []byte, err error) { + file, data, err = readDiskCache(path, rev, "mod") + + // If the file has an old auto-conversion prefix, pretend it's not there. + if bytes.HasPrefix(data, oldVgoPrefix) { + err = errNotCached + data = nil + } + + if err == nil { + checkGoMod(path, rev, data) + } + + return file, data, err +} + +// readDiskCache is the generic "read from a cache file" implementation. +// It takes the revision and an identifying suffix for the kind of data being cached. +// It returns the name of the cache file and the content of the file. +// If the read fails, the caller can use +// writeDiskCache(file, data) to write a new cache entry. +func readDiskCache(path, rev, suffix string) (file string, data []byte, err error) { + file, err = CachePath(module.Version{Path: path, Version: rev}, suffix) + if err != nil { + return "", nil, errNotCached + } + data, err = ioutil.ReadFile(file) + if err != nil { + return file, nil, errNotCached + } + return file, data, nil +} + +// writeDiskStat writes a stat result cache entry. +// The file name must have been returned by a previous call to readDiskStat. +func writeDiskStat(file string, info *RevInfo) error { + if file == "" { + return nil + } + js, err := json.Marshal(info) + if err != nil { + return err + } + return writeDiskCache(file, js) +} + +// writeDiskGoMod writes a go.mod cache entry. +// The file name must have been returned by a previous call to readDiskGoMod. +func writeDiskGoMod(file string, text []byte) error { + return writeDiskCache(file, text) +} + +// writeDiskCache is the generic "write to a cache file" implementation. +// The file must have been returned by a previous call to readDiskCache. +func writeDiskCache(file string, data []byte) error { + if file == "" { + return nil + } + // Make sure directory for file exists. + if err := os.MkdirAll(filepath.Dir(file), 0777); err != nil { + return err + } + // Write data to temp file next to target file. + f, err := ioutil.TempFile(filepath.Dir(file), filepath.Base(file)+".tmp-") + if err != nil { + return err + } + defer os.Remove(f.Name()) + defer f.Close() + if _, err := f.Write(data); err != nil { + return err + } + if err := f.Close(); err != nil { + return err + } + // Rename temp file onto cache file, + // so that the cache file is always a complete file. + if err := os.Rename(f.Name(), file); err != nil { + return err + } + + if strings.HasSuffix(file, ".mod") { + rewriteVersionList(filepath.Dir(file)) + } + return nil +} + +// rewriteVersionList rewrites the version list in dir +// after a new *.mod file has been written. +func rewriteVersionList(dir string) { + if filepath.Base(dir) != "@v" { + base.Fatalf("go: internal error: misuse of rewriteVersionList") + } + + // TODO(rsc): We should do some kind of directory locking here, + // to avoid lost updates. + + infos, err := ioutil.ReadDir(dir) + if err != nil { + return + } + var list []string + for _, info := range infos { + // We look for *.mod files on the theory that if we can't supply + // the .mod file then there's no point in listing that version, + // since it's unusable. (We can have *.info without *.mod.) + // We don't require *.zip files on the theory that for code only + // involved in module graph construction, many *.zip files + // will never be requested. + name := info.Name() + if strings.HasSuffix(name, ".mod") { + v := strings.TrimSuffix(name, ".mod") + if v != "" && module.CanonicalVersion(v) == v { + list = append(list, v) + } + } + } + SortVersions(list) + + var buf bytes.Buffer + for _, v := range list { + buf.WriteString(v) + buf.WriteString("\n") + } + listFile := filepath.Join(dir, "list") + old, _ := ioutil.ReadFile(listFile) + if bytes.Equal(buf.Bytes(), old) { + return + } + // TODO: Use rename to install file, + // so that readers never see an incomplete file. + ioutil.WriteFile(listFile, buf.Bytes(), 0666) +} diff --git a/src/cmd/go/internal/modfetch/cache_test.go b/src/cmd/go/internal/modfetch/cache_test.go new file mode 100644 index 0000000000..241c800e69 --- /dev/null +++ b/src/cmd/go/internal/modfetch/cache_test.go @@ -0,0 +1,25 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modfetch + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestWriteDiskCache(t *testing.T) { + tmpdir, err := ioutil.TempDir("", "go-writeCache-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmpdir) + + err = writeDiskCache(filepath.Join(tmpdir, "file"), []byte("data")) + if err != nil { + t.Fatal(err) + } +} diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index 0e3bb7d7c3..4103ddc717 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -16,6 +16,7 @@ import ( "os/exec" "path/filepath" "strings" + "sync" "time" "cmd/go/internal/cfg" @@ -32,10 +33,8 @@ const ( // A Repo represents a code hosting source. // Typical implementations include local version control repositories, // remote version control servers, and code hosting sites. +// A Repo must be safe for simultaneous use by multiple goroutines. type Repo interface { - // Root returns the import path of the root directory of the repository. - Root() string - // List lists all tags with the given prefix. Tags(prefix string) (tags []string, err error) @@ -50,8 +49,26 @@ type Repo interface { // ReadFile reads the given file in the file tree corresponding to revision rev. // It should refuse to read more than maxSize bytes. + // + // If the requested file does not exist it should return an error for which + // os.IsNotExist(err) returns true. ReadFile(rev, file string, maxSize int64) (data []byte, err error) + // ReadFileRevs reads a single file at multiple versions. + // It should refuse to read more than maxSize bytes. + // The result is a map from each requested rev strings + // to the associated FileRev. The map must have a non-nil + // entry for every requested rev (unless ReadFileRevs returned an error). + // A file simply being missing or even corrupted in revs[i] + // should be reported only in files[revs[i]].Err, not in the error result + // from ReadFileRevs. + // The overall call should return an error (and no map) only + // in the case of a problem with obtaining the data, such as + // a network failure. + // Implementations may assume that revs only contain tags, + // not direct commit hashes. + ReadFileRevs(revs []string, file string, maxSize int64) (files map[string]*FileRev, err error) + // ReadZip downloads a zip file for the subdir subdirectory // of the given revision to a new file in a given temporary directory. // It should refuse to read more than maxSize bytes. @@ -60,14 +77,31 @@ type Repo interface { // contained in the zip file. All files in the zip file are expected to be // nested in a single top-level directory, whose name is not specified. ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) + + // RecentTag returns the most recent tag at or before the given rev + // with the given prefix. It should make a best-effort attempt to + // find a tag that is a valid semantic version (following the prefix), + // or else the result is not useful to the caller, but it need not + // incur great expense in doing so. For example, the git implementation + // of RecentTag limits git's search to tags matching the glob expression + // "v[0-9]*.[0-9]*.[0-9]*" (after the prefix). + RecentTag(rev, prefix string) (tag string, err error) } // A Rev describes a single revision in a source code repository. type RevInfo struct { Name string // complete ID in underlying repository Short string // shortened ID, for use in pseudo-version - Version string // TODO what is this? + Version string // version used in lookup Time time.Time // commit time + Tags []string // known tags for commit +} + +// A FileRev describes the result of reading a file at a given revision. +type FileRev struct { + Rev string // requested revision + Data []byte // file data + Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev } // AllHex reports whether the revision rev is entirely lower-case hexadecimal digits. @@ -92,7 +126,7 @@ func ShortenSHA1(rev string) string { } // WorkRoot is the root of the cached work directory. -// It is set by cmd/go/internal/vgo.InitMod. +// It is set by cmd/go/internal/modload.InitMod. var WorkRoot string // WorkDir returns the name of the cached work directory to use for the @@ -113,21 +147,20 @@ func WorkDir(typ, name string) (string, error) { key := typ + ":" + name dir := filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key)))) data, err := ioutil.ReadFile(dir + ".info") - if err == nil { + info, err2 := os.Stat(dir) + if err == nil && err2 == nil && info.IsDir() { + // Info file and directory both already exist: reuse. have := strings.TrimSuffix(string(data), "\n") if have != key { return "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key) } - _, err := os.Stat(dir) - if err != nil { - return "", fmt.Errorf("%s exists but %s does not", dir+".info", dir) - } if cfg.BuildX { fmt.Fprintf(os.Stderr, "# %s for %s %s\n", dir, typ, name) } return dir, nil } + // Info file or directory missing. Start from scratch. if cfg.BuildX { fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", dir, typ, name) } @@ -157,19 +190,64 @@ func (e *RunError) Error() string { return text } +var dirLock sync.Map + // Run runs the command line in the given directory // (an empty dir means the current directory). // It returns the standard output and, for a non-zero exit, // a *RunError indicating the command, exit status, and standard error. // Standard error is unavailable for commands that exit successfully. func Run(dir string, cmdline ...interface{}) ([]byte, error) { + return RunWithStdin(dir, nil, cmdline...) +} + +// bashQuoter escapes characters that have special meaning in double-quoted strings in the bash shell. +// See https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html. +var bashQuoter = strings.NewReplacer(`"`, `\"`, `$`, `\$`, "`", "\\`", `\`, `\\`) + +func RunWithStdin(dir string, stdin io.Reader, cmdline ...interface{}) ([]byte, error) { + if dir != "" { + muIface, ok := dirLock.Load(dir) + if !ok { + muIface, _ = dirLock.LoadOrStore(dir, new(sync.Mutex)) + } + mu := muIface.(*sync.Mutex) + mu.Lock() + defer mu.Unlock() + } + cmd := str.StringList(cmdline...) if cfg.BuildX { - var cd string + text := new(strings.Builder) if dir != "" { - cd = "cd " + dir + "; " + text.WriteString("cd ") + text.WriteString(dir) + text.WriteString("; ") } - fmt.Fprintf(os.Stderr, "%s%s\n", cd, strings.Join(cmd, " ")) + for i, arg := range cmd { + if i > 0 { + text.WriteByte(' ') + } + switch { + case strings.ContainsAny(arg, "'"): + // Quote args that could be mistaken for quoted args. + text.WriteByte('"') + text.WriteString(bashQuoter.Replace(arg)) + text.WriteByte('"') + case strings.ContainsAny(arg, "$`\\*?[\"\t\n\v\f\r \u0085\u00a0"): + // Quote args that contain special characters, glob patterns, or spaces. + text.WriteByte('\'') + text.WriteString(arg) + text.WriteByte('\'') + default: + text.WriteString(arg) + } + } + fmt.Fprintf(os.Stderr, "%s\n", text) + start := time.Now() + defer func() { + fmt.Fprintf(os.Stderr, "%.3fs # %s\n", time.Since(start).Seconds(), text) + }() } // TODO: Impose limits on command output size. // TODO: Set environment to get English error messages. @@ -177,6 +255,7 @@ func Run(dir string, cmdline ...interface{}) ([]byte, error) { var stdout bytes.Buffer c := exec.Command(cmd[0], cmd[1:]...) c.Dir = dir + c.Stdin = stdin c.Stderr = &stderr c.Stdout = &stdout err := c.Run() diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go new file mode 100644 index 0000000000..87940a8f02 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -0,0 +1,711 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codehost + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/par" +) + +// GitRepo returns the code repository at the given Git remote reference. +func GitRepo(remote string) (Repo, error) { + return newGitRepoCached(remote, false) +} + +// LocalGitRepo is like Repo but accepts both Git remote references +// and paths to repositories on the local file system. +func LocalGitRepo(remote string) (Repo, error) { + return newGitRepoCached(remote, true) +} + +const gitWorkDirType = "git2" + +var gitRepoCache par.Cache + +func newGitRepoCached(remote string, localOK bool) (Repo, error) { + type key struct { + remote string + localOK bool + } + type cached struct { + repo Repo + err error + } + + c := gitRepoCache.Do(key{remote, localOK}, func() interface{} { + repo, err := newGitRepo(remote, localOK) + return cached{repo, err} + }).(cached) + + return c.repo, c.err +} + +func newGitRepo(remote string, localOK bool) (Repo, error) { + r := &gitRepo{remote: remote} + if strings.Contains(remote, "://") { + // This is a remote path. + dir, err := WorkDir(gitWorkDirType, r.remote) + if err != nil { + return nil, err + } + r.dir = dir + if _, err := os.Stat(filepath.Join(dir, "objects")); err != nil { + if _, err := Run(dir, "git", "init", "--bare"); err != nil { + os.RemoveAll(dir) + return nil, err + } + // We could just say git fetch https://whatever later, + // but this lets us say git fetch origin instead, which + // is a little nicer. More importantly, using a named remote + // avoids a problem with Git LFS. See golang.org/issue/25605. + if _, err := Run(dir, "git", "remote", "add", "origin", r.remote); err != nil { + os.RemoveAll(dir) + return nil, err + } + r.remote = "origin" + } + } else { + // Local path. + // Disallow colon (not in ://) because sometimes + // that's rcp-style host:path syntax and sometimes it's not (c:\work). + // The go command has always insisted on URL syntax for ssh. + if strings.Contains(remote, ":") { + return nil, fmt.Errorf("git remote cannot use host:path syntax") + } + if !localOK { + return nil, fmt.Errorf("git remote must not be local directory") + } + r.local = true + info, err := os.Stat(remote) + if err != nil { + return nil, err + } + if !info.IsDir() { + return nil, fmt.Errorf("%s exists but is not a directory", remote) + } + r.dir = remote + } + return r, nil +} + +type gitRepo struct { + remote string + local bool + dir string + + mu sync.Mutex // protects fetchLevel, some git repo state + fetchLevel int + + statCache par.Cache + + refsOnce sync.Once + refs map[string]string + refsErr error + + localTagsOnce sync.Once + localTags map[string]bool +} + +const ( + // How much have we fetched into the git repo (in this process)? + fetchNone = iota // nothing yet + fetchSome // shallow fetches of individual hashes + fetchAll // "fetch -t origin": get all remote branches and tags +) + +// loadLocalTags loads tag references from the local git cache +// into the map r.localTags. +// Should only be called as r.localTagsOnce.Do(r.loadLocalTags). +func (r *gitRepo) loadLocalTags() { + // The git protocol sends all known refs and ls-remote filters them on the client side, + // so we might as well record both heads and tags in one shot. + // Most of the time we only care about tags but sometimes we care about heads too. + out, err := Run(r.dir, "git", "tag", "-l") + if err != nil { + return + } + + r.localTags = make(map[string]bool) + for _, line := range strings.Split(string(out), "\n") { + if line != "" { + r.localTags[line] = true + } + } +} + +// loadRefs loads heads and tags references from the remote into the map r.refs. +// Should only be called as r.refsOnce.Do(r.loadRefs). +func (r *gitRepo) loadRefs() { + // The git protocol sends all known refs and ls-remote filters them on the client side, + // so we might as well record both heads and tags in one shot. + // Most of the time we only care about tags but sometimes we care about heads too. + out, err := Run(r.dir, "git", "ls-remote", "-q", r.remote) + if err != nil { + r.refsErr = err + return + } + + r.refs = make(map[string]string) + for _, line := range strings.Split(string(out), "\n") { + f := strings.Fields(line) + if len(f) != 2 { + continue + } + if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") { + r.refs[f[1]] = f[0] + } + } + for ref, hash := range r.refs { + if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag + r.refs[strings.TrimSuffix(ref, "^{}")] = hash + delete(r.refs, ref) + } + } +} + +func (r *gitRepo) Tags(prefix string) ([]string, error) { + r.refsOnce.Do(r.loadRefs) + if r.refsErr != nil { + return nil, r.refsErr + } + + tags := []string{} + for ref := range r.refs { + if !strings.HasPrefix(ref, "refs/tags/") { + continue + } + tag := ref[len("refs/tags/"):] + if !strings.HasPrefix(tag, prefix) { + continue + } + tags = append(tags, tag) + } + sort.Strings(tags) + return tags, nil +} + +func (r *gitRepo) Latest() (*RevInfo, error) { + r.refsOnce.Do(r.loadRefs) + if r.refsErr != nil { + return nil, r.refsErr + } + if r.refs["HEAD"] == "" { + return nil, fmt.Errorf("no commits") + } + return r.Stat(r.refs["HEAD"]) +} + +// findRef finds some ref name for the given hash, +// for use when the server requires giving a ref instead of a hash. +// There may be multiple ref names for a given hash, +// in which case this returns some name - it doesn't matter which. +func (r *gitRepo) findRef(hash string) (ref string, ok bool) { + r.refsOnce.Do(r.loadRefs) + for ref, h := range r.refs { + if h == hash { + return ref, true + } + } + return "", false +} + +func unshallow(gitDir string) []string { + if _, err := os.Stat(filepath.Join(gitDir, "shallow")); err == nil { + return []string{"--unshallow"} + } + return []string{} +} + +// minHashDigits is the minimum number of digits to require +// before accepting a hex digit sequence as potentially identifying +// a specific commit in a git repo. (Of course, users can always +// specify more digits, and many will paste in all 40 digits, +// but many of git's commands default to printing short hashes +// as 7 digits.) +const minHashDigits = 7 + +// stat stats the given rev in the local repository, +// or else it fetches more info from the remote repository and tries again. +func (r *gitRepo) stat(rev string) (*RevInfo, error) { + if r.local { + return r.statLocal(rev, rev) + } + + // Fast path: maybe rev is a hash we already have locally. + didStatLocal := false + if len(rev) >= minHashDigits && len(rev) <= 40 && AllHex(rev) { + if info, err := r.statLocal(rev, rev); err == nil { + return info, nil + } + didStatLocal = true + } + + // Maybe rev is a tag we already have locally. + // (Note that we're excluding branches, which can be stale.) + r.localTagsOnce.Do(r.loadLocalTags) + if r.localTags[rev] { + return r.statLocal(rev, "refs/tags/"+rev) + } + + // Maybe rev is the name of a tag or branch on the remote server. + // Or maybe it's the prefix of a hash of a named ref. + // Try to resolve to both a ref (git name) and full (40-hex-digit) commit hash. + r.refsOnce.Do(r.loadRefs) + var ref, hash string + if r.refs["refs/tags/"+rev] != "" { + ref = "refs/tags/" + rev + hash = r.refs[ref] + // Keep rev as is: tags are assumed not to change meaning. + } else if r.refs["refs/heads/"+rev] != "" { + ref = "refs/heads/" + rev + hash = r.refs[ref] + rev = hash // Replace rev, because meaning of refs/heads/foo can change. + } else if rev == "HEAD" && r.refs["HEAD"] != "" { + ref = "HEAD" + hash = r.refs[ref] + rev = hash // Replace rev, because meaning of HEAD can change. + } else if len(rev) >= minHashDigits && len(rev) <= 40 && AllHex(rev) { + // At the least, we have a hash prefix we can look up after the fetch below. + // Maybe we can map it to a full hash using the known refs. + prefix := rev + // Check whether rev is prefix of known ref hash. + for k, h := range r.refs { + if strings.HasPrefix(h, prefix) { + if hash != "" && hash != h { + // Hash is an ambiguous hash prefix. + // More information will not change that. + return nil, fmt.Errorf("ambiguous revision %s", rev) + } + if ref == "" || ref > k { // Break ties deterministically when multiple refs point at same hash. + ref = k + } + rev = h + hash = h + } + } + if hash == "" && len(rev) == 40 { // Didn't find a ref, but rev is a full hash. + hash = rev + } + } else { + return nil, fmt.Errorf("unknown revision %s", rev) + } + + // Protect r.fetchLevel and the "fetch more and more" sequence. + // TODO(rsc): Add LockDir and use it for protecting that + // sequence, so that multiple processes don't collide in their + // git commands. + r.mu.Lock() + defer r.mu.Unlock() + + // Perhaps r.localTags did not have the ref when we loaded local tags, + // but we've since done fetches that pulled down the hash we need + // (or already have the hash we need, just without its tag). + // Either way, try a local stat before falling back to network I/O. + if !didStatLocal { + if info, err := r.statLocal(rev, hash); err == nil { + if strings.HasPrefix(ref, "refs/tags/") { + // Make sure tag exists, so it will be in localTags next time the go command is run. + Run(r.dir, "git", "tag", strings.TrimPrefix(ref, "refs/tags/"), hash) + } + return info, nil + } + } + + // If we know a specific commit we need, fetch it. + if r.fetchLevel <= fetchSome && hash != "" && !r.local { + r.fetchLevel = fetchSome + var refspec string + if ref != "" && ref != "HEAD" { + // If we do know the ref name, save the mapping locally + // so that (if it is a tag) it can show up in localTags + // on a future call. Also, some servers refuse to allow + // full hashes in ref specs, so prefer a ref name if known. + refspec = ref + ":" + ref + } else { + // Fetch the hash but give it a local name (refs/dummy), + // because that triggers the fetch behavior of creating any + // other known remote tags for the hash. We never use + // refs/dummy (it's not refs/tags/dummy) and it will be + // overwritten in the next command, and that's fine. + ref = hash + refspec = hash + ":refs/dummy" + } + _, err := Run(r.dir, "git", "fetch", "-f", "--depth=1", r.remote, refspec) + if err == nil { + return r.statLocal(rev, ref) + } + // Don't try to be smart about parsing the error. + // It's too complex and varies too much by git version. + // No matter what went wrong, fall back to a complete fetch. + } + + // Last resort. + // Fetch all heads and tags and hope the hash we want is in the history. + if r.fetchLevel < fetchAll { + // TODO(bcmills): should we wait to upgrade fetchLevel until after we check + // err? If there is a temporary server error, we want subsequent fetches to + // try again instead of proceeding with an incomplete repo. + r.fetchLevel = fetchAll + if err := r.fetchUnshallow("refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { + return nil, err + } + } + + return r.statLocal(rev, rev) +} + +func (r *gitRepo) fetchUnshallow(refSpecs ...string) error { + // To work around a protocol version 2 bug that breaks --unshallow, + // add -c protocol.version=0. + // TODO(rsc): The bug is believed to be server-side, meaning only + // on Google's Git servers. Once the servers are fixed, drop the + // protocol.version=0. See Google-internal bug b/110495752. + var protoFlag []string + unshallowFlag := unshallow(r.dir) + if len(unshallowFlag) > 0 { + protoFlag = []string{"-c", "protocol.version=0"} + } + _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refSpecs) + return err +} + +// statLocal returns a RevInfo describing rev in the local git repository. +// It uses version as info.Version. +func (r *gitRepo) statLocal(version, rev string) (*RevInfo, error) { + out, err := Run(r.dir, "git", "-c", "log.showsignature=false", "log", "-n1", "--format=format:%H %ct %D", rev) + if err != nil { + return nil, fmt.Errorf("unknown revision %s", rev) + } + f := strings.Fields(string(out)) + if len(f) < 2 { + return nil, fmt.Errorf("unexpected response from git log: %q", out) + } + hash := f[0] + if strings.HasPrefix(hash, version) { + version = hash // extend to full hash + } + t, err := strconv.ParseInt(f[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid time from git log: %q", out) + } + + info := &RevInfo{ + Name: hash, + Short: ShortenSHA1(hash), + Time: time.Unix(t, 0).UTC(), + Version: hash, + } + + // Add tags. Output looks like: + // ede458df7cd0fdca520df19a33158086a8a68e81 1523994202 HEAD -> master, tag: v1.2.4-annotated, tag: v1.2.3, origin/master, origin/HEAD + for i := 2; i < len(f); i++ { + if f[i] == "tag:" { + i++ + if i < len(f) { + info.Tags = append(info.Tags, strings.TrimSuffix(f[i], ",")) + } + } + } + sort.Strings(info.Tags) + + // Used hash as info.Version above. + // Use caller's suggested version if it appears in the tag list + // (filters out branch names, HEAD). + for _, tag := range info.Tags { + if version == tag { + info.Version = version + } + } + + return info, nil +} + +func (r *gitRepo) Stat(rev string) (*RevInfo, error) { + if rev == "latest" { + return r.Latest() + } + type cached struct { + info *RevInfo + err error + } + c := r.statCache.Do(rev, func() interface{} { + info, err := r.stat(rev) + return cached{info, err} + }).(cached) + return c.info, c.err +} + +func (r *gitRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) { + // TODO: Could use git cat-file --batch. + info, err := r.Stat(rev) // download rev into local git repo + if err != nil { + return nil, err + } + out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file) + if err != nil { + return nil, os.ErrNotExist + } + return out, nil +} + +func (r *gitRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) { + // Create space to hold results. + files := make(map[string]*FileRev) + for _, rev := range revs { + f := &FileRev{Rev: rev} + files[rev] = f + } + + // Collect locally-known revs. + need, err := r.readFileRevs(revs, file, files) + if err != nil { + return nil, err + } + if len(need) == 0 { + return files, nil + } + + // Build list of known remote refs that might help. + var redo []string + r.refsOnce.Do(r.loadRefs) + if r.refsErr != nil { + return nil, r.refsErr + } + for _, tag := range need { + if r.refs["refs/tags/"+tag] != "" { + redo = append(redo, tag) + } + } + if len(redo) == 0 { + return files, nil + } + + // Protect r.fetchLevel and the "fetch more and more" sequence. + // See stat method above. + r.mu.Lock() + defer r.mu.Unlock() + + var refs []string + var protoFlag []string + var unshallowFlag []string + for _, tag := range redo { + refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag) + } + if len(refs) > 1 { + unshallowFlag = unshallow(r.dir) + if len(unshallowFlag) > 0 { + // To work around a protocol version 2 bug that breaks --unshallow, + // add -c protocol.version=0. + // TODO(rsc): The bug is believed to be server-side, meaning only + // on Google's Git servers. Once the servers are fixed, drop the + // protocol.version=0. See Google-internal bug b/110495752. + protoFlag = []string{"-c", "protocol.version=0"} + } + } + if _, err := Run(r.dir, "git", protoFlag, "fetch", unshallowFlag, "-f", r.remote, refs); err != nil { + return nil, err + } + + // TODO(bcmills): after the 1.11 freeze, replace the block above with: + // if r.fetchLevel <= fetchSome { + // r.fetchLevel = fetchSome + // var refs []string + // for _, tag := range redo { + // refs = append(refs, "refs/tags/"+tag+":refs/tags/"+tag) + // } + // if _, err := Run(r.dir, "git", "fetch", "--update-shallow", "-f", r.remote, refs); err != nil { + // return nil, err + // } + // } + + if _, err := r.readFileRevs(redo, file, files); err != nil { + return nil, err + } + + return files, nil +} + +func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*FileRev) (missing []string, err error) { + var stdin bytes.Buffer + for _, tag := range tags { + fmt.Fprintf(&stdin, "refs/tags/%s\n", tag) + fmt.Fprintf(&stdin, "refs/tags/%s:%s\n", tag, file) + } + + data, err := RunWithStdin(r.dir, &stdin, "git", "cat-file", "--batch") + if err != nil { + return nil, err + } + + next := func() (typ string, body []byte, ok bool) { + var line string + i := bytes.IndexByte(data, '\n') + if i < 0 { + return "", nil, false + } + line, data = string(bytes.TrimSpace(data[:i])), data[i+1:] + if strings.HasSuffix(line, " missing") { + return "missing", nil, true + } + f := strings.Fields(line) + if len(f) != 3 { + return "", nil, false + } + n, err := strconv.Atoi(f[2]) + if err != nil || n > len(data) { + return "", nil, false + } + body, data = data[:n], data[n:] + if len(data) > 0 && data[0] == '\r' { + data = data[1:] + } + if len(data) > 0 && data[0] == '\n' { + data = data[1:] + } + return f[1], body, true + } + + badGit := func() ([]string, error) { + return nil, fmt.Errorf("malformed output from git cat-file --batch") + } + + for _, tag := range tags { + commitType, _, ok := next() + if !ok { + return badGit() + } + fileType, fileData, ok := next() + if !ok { + return badGit() + } + f := fileMap[tag] + f.Data = nil + f.Err = nil + switch commitType { + default: + f.Err = fmt.Errorf("unexpected non-commit type %q for rev %s", commitType, tag) + + case "missing": + // Note: f.Err must not satisfy os.IsNotExist. That's reserved for the file not existing in a valid commit. + f.Err = fmt.Errorf("no such rev %s", tag) + missing = append(missing, tag) + + case "tag", "commit": + switch fileType { + default: + f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)} + case "missing": + f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: os.ErrNotExist} + case "blob": + f.Data = fileData + } + } + } + if len(bytes.TrimSpace(data)) != 0 { + return badGit() + } + + return missing, nil +} + +func (r *gitRepo) RecentTag(rev, prefix string) (tag string, err error) { + info, err := r.Stat(rev) + if err != nil { + return "", err + } + rev = info.Name // expand hash prefixes + + // describe sets tag and err using 'git describe' and reports whether the + // result is definitive. + describe := func() (definitive bool) { + var out []byte + out, err = Run(r.dir, "git", "describe", "--first-parent", "--always", "--abbrev=0", "--match", prefix+"v[0-9]*.[0-9]*.[0-9]*", "--tags", rev) + if err != nil { + return true // Because we use "--always", describe should never fail. + } + + tag = string(bytes.TrimSpace(out)) + return tag != "" && !AllHex(tag) + } + + if describe() { + return tag, err + } + + // Git didn't find a version tag preceding the requested rev. + // See whether any plausible tag exists. + tags, err := r.Tags(prefix + "v") + if err != nil { + return "", err + } + if len(tags) == 0 { + return "", nil + } + + // There are plausible tags, but we don't know if rev is a descendent of any of them. + // Fetch the history to find out. + + r.mu.Lock() + defer r.mu.Unlock() + + if r.fetchLevel < fetchAll { + // Fetch all heads and tags and see if that gives us enough history. + if err := r.fetchUnshallow("refs/heads/*:refs/heads/*", "refs/tags/*:refs/tags/*"); err != nil { + return "", err + } + r.fetchLevel = fetchAll + } + + // If we've reached this point, we have all of the commits that are reachable + // from all heads and tags. + // + // The only refs we should be missing are those that are no longer reachable + // (or never were reachable) from any branch or tag, including the master + // branch, and we don't want to resolve them anyway (they're probably + // unreachable for a reason). + // + // Try one last time in case some other goroutine fetched rev while we were + // waiting on r.mu. + describe() + return tag, err +} + +func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) { + // TODO: Use maxSize or drop it. + args := []string{} + if subdir != "" { + args = append(args, "--", subdir) + } + info, err := r.Stat(rev) // download rev into local git repo + if err != nil { + return nil, "", err + } + + // Incredibly, git produces different archives depending on whether + // it is running on a Windows system or not, in an attempt to normalize + // text file line endings. Setting -c core.autocrlf=input means only + // translate files on the way into the repo, not on the way out (archive). + // The -c core.eol=lf should be unnecessary but set it anyway. + archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args) + if err != nil { + if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) { + return nil, "", os.ErrNotExist + } + return nil, "", err + } + + return ioutil.NopCloser(bytes.NewReader(archive)), "", nil +} diff --git a/src/cmd/go/internal/modfetch/gitrepo/fetch_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go similarity index 68% rename from src/cmd/go/internal/modfetch/gitrepo/fetch_test.go rename to src/cmd/go/internal/modfetch/codehost/git_test.go index ca932808e8..da9e705040 100644 --- a/src/cmd/go/internal/modfetch/gitrepo/fetch_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -2,31 +2,45 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package gitrepo +package codehost import ( "archive/zip" "bytes" + "flag" "fmt" "internal/testenv" "io/ioutil" "log" "os" "os/exec" + "path" "path/filepath" "reflect" "strings" "testing" "time" - - "cmd/go/internal/modfetch/codehost" ) func TestMain(m *testing.M) { + // needed for initializing the test environment variables as testing.Short + // and HasExternalNetwork + flag.Parse() os.Exit(testMain(m)) } -const gitrepo1 = "https://vcs-test.golang.org/git/gitrepo1" +const ( + gitrepo1 = "https://vcs-test.golang.org/git/gitrepo1" + hgrepo1 = "https://vcs-test.golang.org/hg/hgrepo1" +) + +var altRepos = []string{ + "localGitRepo", + hgrepo1, +} + +// TODO: Convert gitrepo1 to svn, bzr, fossil and add tests. +// For now, at least the hgrepo1 tests check the general vcs.go logic. // localGitRepo is like gitrepo1 but allows archive access. var localGitRepo string @@ -43,7 +57,7 @@ func testMain(m *testing.M) int { log.Fatal(err) } defer os.RemoveAll(dir) - codehost.WorkRoot = dir + WorkRoot = dir if testenv.HasExternalNetwork() && testenv.HasExec() { // Clone gitrepo1 into a local directory. @@ -51,10 +65,10 @@ func testMain(m *testing.M) int { // then git starts up all the usual protocol machinery, // which will let us test remote git archive invocations. localGitRepo = filepath.Join(dir, "gitrepo2") - if _, err := codehost.Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { + if _, err := Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil { log.Fatal(err) } - if _, err := codehost.Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { + if _, err := Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil { log.Fatal(err) } } @@ -62,13 +76,17 @@ func testMain(m *testing.M) int { return m.Run() } -func testRepo(remote string) (codehost.Repo, error) { +func testRepo(remote string) (Repo, error) { if remote == "localGitRepo" { - remote = "file://" + filepath.ToSlash(localGitRepo) + return LocalGitRepo(filepath.ToSlash(localGitRepo)) } - // Re ?root: nothing should care about the second argument, - // so use a string that will be distinctive if it does show up. - return LocalRepo(remote, "?root") + kind := "git" + for _, k := range []string{"hg"} { + if strings.Contains(remote, "/"+k+"/") { + kind = k + } + } + return NewRepo(kind, remote) } var tagsTests = []struct { @@ -101,25 +119,36 @@ func TestTags(t *testing.T) { t.Errorf("Tags: incorrect tags\nhave %v\nwant %v", tags, tt.tags) } } - t.Run(tt.repo+"/"+tt.prefix, f) + t.Run(path.Base(tt.repo)+"/"+tt.prefix, f) if tt.repo == gitrepo1 { - tt.repo = "localGitRepo" - t.Run(tt.repo+"/"+tt.prefix, f) + for _, tt.repo = range altRepos { + t.Run(path.Base(tt.repo)+"/"+tt.prefix, f) + } } } } var latestTests = []struct { repo string - info *codehost.RevInfo + info *RevInfo }{ { gitrepo1, - &codehost.RevInfo{ + &RevInfo{ Name: "ede458df7cd0fdca520df19a33158086a8a68e81", Short: "ede458df7cd0", Version: "ede458df7cd0fdca520df19a33158086a8a68e81", Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), + Tags: []string{"v1.2.3", "v1.2.4-annotated"}, + }, + }, + { + hgrepo1, + &RevInfo{ + Name: "18518c07eb8ed5c80221e997e518cccaa8c0c287", + Short: "18518c07eb8e", + Version: "18518c07eb8ed5c80221e997e518cccaa8c0c287", + Time: time.Date(2018, 6, 27, 16, 16, 30, 0, time.UTC), }, }, } @@ -138,14 +167,14 @@ func TestLatest(t *testing.T) { if err != nil { t.Fatal(err) } - if *info != *tt.info { + if !reflect.DeepEqual(info, tt.info) { t.Errorf("Latest: incorrect info\nhave %+v\nwant %+v", *info, *tt.info) } } - t.Run(tt.repo, f) + t.Run(path.Base(tt.repo), f) if tt.repo == gitrepo1 { tt.repo = "localGitRepo" - t.Run(tt.repo, f) + t.Run(path.Base(tt.repo), f) } } } @@ -159,7 +188,7 @@ var readFileTests = []struct { }{ { repo: gitrepo1, - rev: "HEAD", + rev: "latest", file: "README", data: "", }, @@ -173,7 +202,7 @@ var readFileTests = []struct { repo: gitrepo1, rev: "v2.3.4", file: "another.txt", - err: "file not found", + err: os.ErrNotExist.Error(), }, } @@ -207,10 +236,11 @@ func TestReadFile(t *testing.T) { t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data) } } - t.Run(tt.repo+"/"+tt.rev+"/"+tt.file, f) + t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, f) if tt.repo == gitrepo1 { - tt.repo = "localGitRepo" - t.Run(tt.repo+"/"+tt.rev+"/"+tt.file, f) + for _, tt.repo = range altRepos { + t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, f) + } } } } @@ -233,6 +263,17 @@ var readZipTests = []struct { "prefix/v2": 3, }, }, + { + repo: hgrepo1, + rev: "v2.3.4", + subdir: "", + files: map[string]uint64{ + "prefix/.hg_archival.txt": ^uint64(0), + "prefix/README": 0, + "prefix/v2": 3, + }, + }, + { repo: gitrepo1, rev: "v2", @@ -245,6 +286,19 @@ var readZipTests = []struct { "prefix/foo.txt": 13, }, }, + { + repo: hgrepo1, + rev: "v2", + subdir: "", + files: map[string]uint64{ + "prefix/.hg_archival.txt": ^uint64(0), + "prefix/README": 0, + "prefix/v2": 3, + "prefix/another.txt": 8, + "prefix/foo.txt": 13, + }, + }, + { repo: gitrepo1, rev: "v3", @@ -258,6 +312,18 @@ var readZipTests = []struct { "prefix/README": 0, }, }, + { + repo: hgrepo1, + rev: "v3", + subdir: "", + files: map[string]uint64{ + "prefix/.hg_archival.txt": ^uint64(0), + "prefix/.hgtags": 405, + "prefix/v3/sub/dir/file.txt": 16, + "prefix/README": 0, + }, + }, + { repo: gitrepo1, rev: "v3", @@ -270,6 +336,15 @@ var readZipTests = []struct { "prefix/v3/sub/dir/file.txt": 16, }, }, + { + repo: hgrepo1, + rev: "v3", + subdir: "v3/sub/dir", + files: map[string]uint64{ + "prefix/v3/sub/dir/file.txt": 16, + }, + }, + { repo: gitrepo1, rev: "v3", @@ -282,12 +357,28 @@ var readZipTests = []struct { "prefix/v3/sub/dir/file.txt": 16, }, }, + { + repo: hgrepo1, + rev: "v3", + subdir: "v3/sub", + files: map[string]uint64{ + "prefix/v3/sub/dir/file.txt": 16, + }, + }, + { repo: gitrepo1, rev: "aaaaaaaaab", subdir: "", - err: "cannot find hash", + err: "unknown revision", }, + { + repo: hgrepo1, + rev: "aaaaaaaaab", + subdir: "", + err: "unknown revision", + }, + { repo: "https://github.com/rsc/vgotest1", rev: "submod/v1.0.4", @@ -353,7 +444,7 @@ func TestReadZip(t *testing.T) { continue } have[f.Name] = true - if f.UncompressedSize64 != size { + if size != ^uint64(0) && f.UncompressedSize64 != size { t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size) } } @@ -363,84 +454,98 @@ func TestReadZip(t *testing.T) { } } } - t.Run(tt.repo+"/"+tt.rev+"/"+tt.subdir, f) + t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, f) if tt.repo == gitrepo1 { tt.repo = "localGitRepo" - t.Run(tt.repo+"/"+tt.rev+"/"+tt.subdir, f) + t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, f) } } } +var hgmap = map[string]string{ + "HEAD": "41964ddce1180313bdc01d0a39a2813344d6261d", // not tip due to bad hgrepo1 conversion + "9d02800338b8a55be062c838d1f02e0c5780b9eb": "8f49ee7a6ddcdec6f0112d9dca48d4a2e4c3c09e", + "76a00fb249b7f93091bc2c89a789dab1fc1bc26f": "88fde824ec8b41a76baa16b7e84212cee9f3edd0", + "ede458df7cd0fdca520df19a33158086a8a68e81": "41964ddce1180313bdc01d0a39a2813344d6261d", + "97f6aa59c81c623494825b43d39e445566e429a4": "c0cbbfb24c7c3c50c35c7b88e7db777da4ff625d", +} + var statTests = []struct { repo string rev string err string - info *codehost.RevInfo + info *RevInfo }{ { repo: gitrepo1, rev: "HEAD", - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "ede458df7cd0fdca520df19a33158086a8a68e81", Short: "ede458df7cd0", Version: "ede458df7cd0fdca520df19a33158086a8a68e81", Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), + Tags: []string{"v1.2.3", "v1.2.4-annotated"}, }, }, { repo: gitrepo1, rev: "v2", // branch - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb", Short: "9d02800338b8", Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb", Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC), + Tags: []string{"v2.0.2"}, }, }, { repo: gitrepo1, rev: "v2.3.4", // badly-named branch (semver should be a tag) - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", Short: "76a00fb249b7", Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), + Tags: []string{"v2.0.1", "v2.3"}, }, }, { repo: gitrepo1, rev: "v2.3", // badly-named tag (we only respect full semver v2.3.0) - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", Short: "76a00fb249b7", Version: "v2.3", Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), + Tags: []string{"v2.0.1", "v2.3"}, }, }, { repo: gitrepo1, rev: "v1.2.3", // tag - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "ede458df7cd0fdca520df19a33158086a8a68e81", Short: "ede458df7cd0", Version: "v1.2.3", Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), + Tags: []string{"v1.2.3", "v1.2.4-annotated"}, }, }, { repo: gitrepo1, rev: "ede458df", // hash prefix in refs - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "ede458df7cd0fdca520df19a33158086a8a68e81", Short: "ede458df7cd0", Version: "ede458df7cd0fdca520df19a33158086a8a68e81", Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), + Tags: []string{"v1.2.3", "v1.2.4-annotated"}, }, }, { repo: gitrepo1, rev: "97f6aa59", // hash prefix not in refs - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "97f6aa59c81c623494825b43d39e445566e429a4", Short: "97f6aa59c81c", Version: "97f6aa59c81c623494825b43d39e445566e429a4", @@ -450,17 +555,18 @@ var statTests = []struct { { repo: gitrepo1, rev: "v1.2.4-annotated", // annotated tag uses unwrapped commit hash - info: &codehost.RevInfo{ + info: &RevInfo{ Name: "ede458df7cd0fdca520df19a33158086a8a68e81", Short: "ede458df7cd0", Version: "v1.2.4-annotated", Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), + Tags: []string{"v1.2.3", "v1.2.4-annotated"}, }, }, { repo: gitrepo1, rev: "aaaaaaaaab", - err: "cannot find hash", + err: "unknown revision", }, } @@ -487,14 +593,43 @@ func TestStat(t *testing.T) { } return } - if *info != *tt.info { + if !reflect.DeepEqual(info, tt.info) { t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info) } } - t.Run(filepath.Base(tt.repo)+"/"+tt.rev, f) + t.Run(path.Base(tt.repo)+"/"+tt.rev, f) if tt.repo == gitrepo1 { - tt.repo = "localGitRepo" - t.Run(filepath.Base(tt.repo)+"/"+tt.rev, f) + for _, tt.repo = range altRepos { + old := tt + var m map[string]string + if tt.repo == hgrepo1 { + m = hgmap + } + if tt.info != nil { + info := *tt.info + tt.info = &info + tt.info.Name = remap(tt.info.Name, m) + tt.info.Version = remap(tt.info.Version, m) + tt.info.Short = remap(tt.info.Short, m) + } + tt.rev = remap(tt.rev, m) + t.Run(path.Base(tt.repo)+"/"+tt.rev, f) + tt = old + } } } } + +func remap(name string, m map[string]string) string { + if m[name] != "" { + return m[name] + } + if AllHex(name) { + for k, v := range m { + if strings.HasPrefix(k, name) { + return v[:len(name)] + } + } + } + return name +} diff --git a/src/cmd/go/internal/modfetch/codehost/shell.go b/src/cmd/go/internal/modfetch/codehost/shell.go new file mode 100644 index 0000000000..7b813c3740 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/shell.go @@ -0,0 +1,140 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Interactive debugging shell for codehost.Repo implementations. + +package main + +import ( + "archive/zip" + "bufio" + "bytes" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "strings" + "time" + + "cmd/go/internal/modfetch/codehost" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go run shell.go vcs remote\n") + os.Exit(2) +} + +func main() { + codehost.WorkRoot = "/tmp/vcswork" + log.SetFlags(0) + log.SetPrefix("shell: ") + flag.Usage = usage + flag.Parse() + if flag.NArg() != 2 { + usage() + } + + repo, err := codehost.NewRepo(flag.Arg(0), flag.Arg(1)) + if err != nil { + log.Fatal(err) + } + + b := bufio.NewReader(os.Stdin) + for { + fmt.Fprintf(os.Stderr, ">>> ") + line, err := b.ReadString('\n') + if err != nil { + log.Fatal(err) + } + f := strings.Fields(line) + if len(f) == 0 { + continue + } + switch f[0] { + default: + fmt.Fprintf(os.Stderr, "?unknown command\n") + continue + case "tags": + prefix := "" + if len(f) == 2 { + prefix = f[1] + } + if len(f) > 2 { + fmt.Fprintf(os.Stderr, "?usage: tags [prefix]\n") + continue + } + tags, err := repo.Tags(prefix) + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + for _, tag := range tags { + fmt.Printf("%s\n", tag) + } + + case "stat": + if len(f) != 2 { + fmt.Fprintf(os.Stderr, "?usage: stat rev\n") + continue + } + info, err := repo.Stat(f[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + fmt.Printf("name=%s short=%s version=%s time=%s\n", info.Name, info.Short, info.Version, info.Time.UTC().Format(time.RFC3339)) + + case "read": + if len(f) != 3 { + fmt.Fprintf(os.Stderr, "?usage: read rev file\n") + continue + } + data, err := repo.ReadFile(f[1], f[2], 10<<20) + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + os.Stdout.Write(data) + + case "zip": + if len(f) != 4 { + fmt.Fprintf(os.Stderr, "?usage: zip rev subdir output\n") + continue + } + subdir := f[2] + if subdir == "-" { + subdir = "" + } + rc, _, err := repo.ReadZip(f[1], subdir, 10<<20) + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + data, err := ioutil.ReadAll(rc) + rc.Close() + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + + if f[3] != "-" { + if err := ioutil.WriteFile(f[3], data, 0666); err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + } + z, err := zip.NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + fmt.Fprintf(os.Stderr, "?%s\n", err) + continue + } + for _, f := range z.File { + fmt.Printf("%s %d\n", f.Name, f.UncompressedSize64) + } + } + } +} diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go new file mode 100644 index 0000000000..9e862a0ef8 --- /dev/null +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -0,0 +1,528 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codehost + +import ( + "encoding/xml" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "regexp" + "sort" + "strconv" + "strings" + "sync" + "time" + + "cmd/go/internal/par" + "cmd/go/internal/str" +) + +// A VCSError indicates an error using a version control system. +// The implication of a VCSError is that we know definitively where +// to get the code, but we can't access it due to the error. +// The caller should report this error instead of continuing to probe +// other possible module paths. +type VCSError struct { + Err error +} + +func (e *VCSError) Error() string { return e.Err.Error() } + +func NewRepo(vcs, remote string) (Repo, error) { + type key struct { + vcs string + remote string + } + type cached struct { + repo Repo + err error + } + c := vcsRepoCache.Do(key{vcs, remote}, func() interface{} { + repo, err := newVCSRepo(vcs, remote) + if err != nil { + err = &VCSError{err} + } + return cached{repo, err} + }).(cached) + + return c.repo, c.err +} + +var vcsRepoCache par.Cache + +type vcsRepo struct { + remote string + cmd *vcsCmd + dir string + + tagsOnce sync.Once + tags map[string]bool + + branchesOnce sync.Once + branches map[string]bool + + fetchOnce sync.Once + fetchErr error +} + +func newVCSRepo(vcs, remote string) (Repo, error) { + if vcs == "git" { + return newGitRepo(remote, false) + } + cmd := vcsCmds[vcs] + if cmd == nil { + return nil, fmt.Errorf("unknown vcs: %s %s", vcs, remote) + } + if !strings.Contains(remote, "://") { + return nil, fmt.Errorf("invalid vcs remote: %s %s", vcs, remote) + } + r := &vcsRepo{remote: remote, cmd: cmd} + if cmd.init == nil { + return r, nil + } + dir, err := WorkDir(vcsWorkDirType+vcs, r.remote) + if err != nil { + return nil, err + } + r.dir = dir + if _, err := os.Stat(filepath.Join(dir, "."+vcs)); err != nil { + if _, err := Run(dir, cmd.init(r.remote)); err != nil { + os.RemoveAll(dir) + return nil, err + } + } + return r, nil +} + +const vcsWorkDirType = "vcs1." + +type vcsCmd struct { + vcs string // vcs name "hg" + init func(remote string) []string // cmd to init repo to track remote + tags func(remote string) []string // cmd to list local tags + tagRE *regexp.Regexp // regexp to extract tag names from output of tags cmd + branches func(remote string) []string // cmd to list local branches + branchRE *regexp.Regexp // regexp to extract branch names from output of tags cmd + badLocalRevRE *regexp.Regexp // regexp of names that must not be served out of local cache without doing fetch first + statLocal func(rev, remote string) []string // cmd to stat local rev + parseStat func(rev, out string) (*RevInfo, error) // cmd to parse output of statLocal + fetch []string // cmd to fetch everything from remote + latest string // name of latest commit on remote (tip, HEAD, etc) + readFile func(rev, file, remote string) []string // cmd to read rev's file + readZip func(rev, subdir, remote, target string) []string // cmd to read rev's subdir as zip file +} + +var re = regexp.MustCompile + +var vcsCmds = map[string]*vcsCmd{ + "hg": { + vcs: "hg", + init: func(remote string) []string { + return []string{"hg", "clone", "-U", remote, "."} + }, + tags: func(remote string) []string { + return []string{"hg", "tags", "-q"} + }, + tagRE: re(`(?m)^[^\n]+$`), + branches: func(remote string) []string { + return []string{"hg", "branches", "-c", "-q"} + }, + branchRE: re(`(?m)^[^\n]+$`), + badLocalRevRE: re(`(?m)^(tip)$`), + statLocal: func(rev, remote string) []string { + return []string{"hg", "log", "-l1", "-r", rev, "--template", "{node} {date|hgdate} {tags}"} + }, + parseStat: hgParseStat, + fetch: []string{"hg", "pull", "-f"}, + latest: "tip", + readFile: func(rev, file, remote string) []string { + return []string{"hg", "cat", "-r", rev, file} + }, + readZip: func(rev, subdir, remote, target string) []string { + pattern := []string{} + if subdir != "" { + pattern = []string{"-I", subdir + "/**"} + } + return str.StringList("hg", "archive", "-t", "zip", "--no-decode", "-r", rev, "--prefix=prefix/", pattern, target) + }, + }, + + "svn": { + vcs: "svn", + init: nil, // no local checkout + tags: func(remote string) []string { + return []string{"svn", "list", strings.TrimSuffix(remote, "/trunk") + "/tags"} + }, + tagRE: re(`(?m)^(.*?)/?$`), + statLocal: func(rev, remote string) []string { + suffix := "@" + rev + if rev == "latest" { + suffix = "" + } + return []string{"svn", "log", "-l1", "--xml", remote + suffix} + }, + parseStat: svnParseStat, + latest: "latest", + readFile: func(rev, file, remote string) []string { + return []string{"svn", "cat", remote + "/" + file + "@" + rev} + }, + // TODO: zip + }, + + "bzr": { + vcs: "bzr", + init: func(remote string) []string { + return []string{"bzr", "branch", "--use-existing-dir", remote, "."} + }, + fetch: []string{ + "bzr", "pull", "--overwrite-tags", + }, + tags: func(remote string) []string { + return []string{"bzr", "tags"} + }, + tagRE: re(`(?m)^\S+`), + badLocalRevRE: re(`^revno:-`), + statLocal: func(rev, remote string) []string { + return []string{"bzr", "log", "-l1", "--long", "--show-ids", "-r", rev} + }, + parseStat: bzrParseStat, + latest: "revno:-1", + readFile: func(rev, file, remote string) []string { + return []string{"bzr", "cat", "-r", rev, file} + }, + readZip: func(rev, subdir, remote, target string) []string { + extra := []string{} + if subdir != "" { + extra = []string{"./" + subdir} + } + return str.StringList("bzr", "export", "--format=zip", "-r", rev, "--root=prefix/", target, extra) + }, + }, + + "fossil": { + vcs: "fossil", + init: func(remote string) []string { + return []string{"fossil", "clone", remote, ".fossil"} + }, + fetch: []string{"fossil", "pull", "-R", ".fossil"}, + tags: func(remote string) []string { + return []string{"fossil", "tag", "-R", ".fossil", "list"} + }, + tagRE: re(`XXXTODO`), + statLocal: func(rev, remote string) []string { + return []string{"fossil", "info", "-R", ".fossil", rev} + }, + parseStat: fossilParseStat, + latest: "trunk", + readFile: func(rev, file, remote string) []string { + return []string{"fossil", "cat", "-R", ".fossil", "-r", rev, file} + }, + readZip: func(rev, subdir, remote, target string) []string { + extra := []string{} + if subdir != "" && !strings.ContainsAny(subdir, "*?[],") { + extra = []string{"--include", subdir} + } + // Note that vcsRepo.ReadZip below rewrites this command + // to run in a different directory, to work around a fossil bug. + return str.StringList("fossil", "zip", "-R", ".fossil", "--name", "prefix", extra, rev, target) + }, + }, +} + +func (r *vcsRepo) loadTags() { + out, err := Run(r.dir, r.cmd.tags(r.remote)) + if err != nil { + return + } + + // Run tag-listing command and extract tags. + r.tags = make(map[string]bool) + for _, tag := range r.cmd.tagRE.FindAllString(string(out), -1) { + if r.cmd.badLocalRevRE != nil && r.cmd.badLocalRevRE.MatchString(tag) { + continue + } + r.tags[tag] = true + } +} + +func (r *vcsRepo) loadBranches() { + if r.cmd.branches == nil { + return + } + + out, err := Run(r.dir, r.cmd.branches(r.remote)) + if err != nil { + return + } + + r.branches = make(map[string]bool) + for _, branch := range r.cmd.branchRE.FindAllString(string(out), -1) { + if r.cmd.badLocalRevRE != nil && r.cmd.badLocalRevRE.MatchString(branch) { + continue + } + r.branches[branch] = true + } +} + +func (r *vcsRepo) Tags(prefix string) ([]string, error) { + r.tagsOnce.Do(r.loadTags) + + tags := []string{} + for tag := range r.tags { + if strings.HasPrefix(tag, prefix) { + tags = append(tags, tag) + } + } + sort.Strings(tags) + return tags, nil +} + +func (r *vcsRepo) Stat(rev string) (*RevInfo, error) { + if rev == "latest" { + rev = r.cmd.latest + } + r.branchesOnce.Do(r.loadBranches) + revOK := (r.cmd.badLocalRevRE == nil || !r.cmd.badLocalRevRE.MatchString(rev)) && !r.branches[rev] + if revOK { + if info, err := r.statLocal(rev); err == nil { + return info, nil + } + } + + r.fetchOnce.Do(r.fetch) + if r.fetchErr != nil { + return nil, r.fetchErr + } + info, err := r.statLocal(rev) + if err != nil { + return nil, err + } + if !revOK { + info.Version = info.Name + } + return info, nil +} + +func (r *vcsRepo) fetch() { + _, r.fetchErr = Run(r.dir, r.cmd.fetch) +} + +func (r *vcsRepo) statLocal(rev string) (*RevInfo, error) { + out, err := Run(r.dir, r.cmd.statLocal(rev, r.remote)) + if err != nil { + return nil, fmt.Errorf("unknown revision %s", rev) + } + return r.cmd.parseStat(rev, string(out)) +} + +func (r *vcsRepo) Latest() (*RevInfo, error) { + return r.Stat("latest") +} + +func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) { + if rev == "latest" { + rev = r.cmd.latest + } + _, err := r.Stat(rev) // download rev into local repo + if err != nil { + return nil, err + } + out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote)) + if err != nil { + return nil, os.ErrNotExist + } + return out, nil +} + +func (r *vcsRepo) ReadFileRevs(revs []string, file string, maxSize int64) (map[string]*FileRev, error) { + return nil, fmt.Errorf("ReadFileRevs not implemented") +} + +func (r *vcsRepo) RecentTag(rev, prefix string) (tag string, err error) { + return "", fmt.Errorf("RecentTags not implemented") +} + +func (r *vcsRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) { + if rev == "latest" { + rev = r.cmd.latest + } + f, err := ioutil.TempFile("", "go-readzip-*.zip") + if err != nil { + return nil, "", err + } + if r.cmd.vcs == "fossil" { + // If you run + // fossil zip -R .fossil --name prefix trunk /tmp/x.zip + // fossil fails with "unable to create directory /tmp" [sic]. + // Change the command to run in /tmp instead, + // replacing the -R argument with an absolute path. + args := r.cmd.readZip(rev, subdir, r.remote, filepath.Base(f.Name())) + for i := range args { + if args[i] == ".fossil" { + args[i] = filepath.Join(r.dir, ".fossil") + } + } + _, err = Run(filepath.Dir(f.Name()), args) + } else { + _, err = Run(r.dir, r.cmd.readZip(rev, subdir, r.remote, f.Name())) + } + if err != nil { + f.Close() + os.Remove(f.Name()) + return nil, "", err + } + return &deleteCloser{f}, "", nil +} + +// deleteCloser is a file that gets deleted on Close. +type deleteCloser struct { + *os.File +} + +func (d *deleteCloser) Close() error { + defer os.Remove(d.File.Name()) + return d.File.Close() +} + +func hgParseStat(rev, out string) (*RevInfo, error) { + f := strings.Fields(string(out)) + if len(f) < 3 { + return nil, fmt.Errorf("unexpected response from hg log: %q", out) + } + hash := f[0] + version := rev + if strings.HasPrefix(hash, version) { + version = hash // extend to full hash + } + t, err := strconv.ParseInt(f[1], 10, 64) + if err != nil { + return nil, fmt.Errorf("invalid time from hg log: %q", out) + } + + var tags []string + for _, tag := range f[3:] { + if tag != "tip" { + tags = append(tags, tag) + } + } + sort.Strings(tags) + + info := &RevInfo{ + Name: hash, + Short: ShortenSHA1(hash), + Time: time.Unix(t, 0).UTC(), + Version: version, + Tags: tags, + } + return info, nil +} + +func svnParseStat(rev, out string) (*RevInfo, error) { + var log struct { + Logentry struct { + Revision int64 `xml:"revision,attr"` + Date string `xml:"date"` + } `xml:"logentry"` + } + if err := xml.Unmarshal([]byte(out), &log); err != nil { + return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out) + } + + t, err := time.Parse(time.RFC3339, log.Logentry.Date) + if err != nil { + return nil, fmt.Errorf("unexpected response from svn log --xml: %v\n%s", err, out) + } + + info := &RevInfo{ + Name: fmt.Sprintf("%d", log.Logentry.Revision), + Short: fmt.Sprintf("%012d", log.Logentry.Revision), + Time: t.UTC(), + Version: rev, + } + return info, nil +} + +func bzrParseStat(rev, out string) (*RevInfo, error) { + var revno int64 + var tm time.Time + for _, line := range strings.Split(out, "\n") { + if line == "" || line[0] == ' ' || line[0] == '\t' { + // End of header, start of commit message. + break + } + if line[0] == '-' { + continue + } + i := strings.Index(line, ":") + if i < 0 { + // End of header, start of commit message. + break + } + key, val := line[:i], strings.TrimSpace(line[i+1:]) + switch key { + case "revno": + if j := strings.Index(val, " "); j >= 0 { + val = val[:j] + } + i, err := strconv.ParseInt(val, 10, 64) + if err != nil { + return nil, fmt.Errorf("unexpected revno from bzr log: %q", line) + } + revno = i + case "timestamp": + j := strings.Index(val, " ") + if j < 0 { + return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line) + } + t, err := time.Parse("2006-01-02 15:04:05 -0700", val[j+1:]) + if err != nil { + return nil, fmt.Errorf("unexpected timestamp from bzr log: %q", line) + } + tm = t.UTC() + } + } + if revno == 0 || tm.IsZero() { + return nil, fmt.Errorf("unexpected response from bzr log: %q", out) + } + + info := &RevInfo{ + Name: fmt.Sprintf("%d", revno), + Short: fmt.Sprintf("%012d", revno), + Time: tm, + Version: rev, + } + return info, nil +} + +func fossilParseStat(rev, out string) (*RevInfo, error) { + for _, line := range strings.Split(out, "\n") { + if strings.HasPrefix(line, "uuid:") { + f := strings.Fields(line) + if len(f) != 5 || len(f[1]) != 40 || f[4] != "UTC" { + return nil, fmt.Errorf("unexpected response from fossil info: %q", line) + } + t, err := time.Parse("2006-01-02 15:04:05", f[2]+" "+f[3]) + if err != nil { + return nil, fmt.Errorf("unexpected response from fossil info: %q", line) + } + hash := f[1] + version := rev + if strings.HasPrefix(hash, version) { + version = hash // extend to full hash + } + info := &RevInfo{ + Name: hash, + Short: ShortenSHA1(hash), + Time: t, + Version: version, + } + return info, nil + } + } + return nil, fmt.Errorf("unexpected response from fossil info: %q", out) +} diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index bb6e8ac179..9cf0e91150 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -6,20 +6,13 @@ package modfetch import ( "archive/zip" - "bytes" - "errors" "fmt" "io" "io/ioutil" "os" "path" - "path/filepath" - "regexp" - "strconv" "strings" - "time" - "cmd/go/internal/modconv" "cmd/go/internal/modfetch/codehost" "cmd/go/internal/modfile" "cmd/go/internal/module" @@ -28,7 +21,8 @@ import ( // A codeRepo implements modfetch.Repo using an underlying codehost.Repo. type codeRepo struct { - modPath string + modPath string + code codehost.Repo codeRoot string codeDir string @@ -39,10 +33,9 @@ type codeRepo struct { pseudoMajor string } -func newCodeRepo(code codehost.Repo, path string) (Repo, error) { - codeRoot := code.Root() - if !hasPathPrefix(path, codeRoot) { - return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path) +func newCodeRepo(code codehost.Repo, root, path string) (Repo, error) { + if !hasPathPrefix(path, root) { + return nil, fmt.Errorf("mismatched repo: found %s for %s", root, path) } pathPrefix, pathMajor, ok := module.SplitPathVersion(path) if !ok { @@ -62,7 +55,7 @@ func newCodeRepo(code codehost.Repo, path string) (Repo, error) { // // Compute codeDir = bar, the subdirectory within the repo // corresponding to the module root. - codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, codeRoot), "/") + codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, root), "/") if strings.HasPrefix(path, "gopkg.in/") { // But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot. // For example we might have: @@ -78,7 +71,7 @@ func newCodeRepo(code codehost.Repo, path string) (Repo, error) { r := &codeRepo{ modPath: path, code: code, - codeRoot: codeRoot, + codeRoot: root, codeDir: codeDir, pathPrefix: pathPrefix, pathMajor: pathMajor, @@ -93,6 +86,13 @@ func (r *codeRepo) ModulePath() string { } func (r *codeRepo) Versions(prefix string) ([]string, error) { + // Special case: gopkg.in/macaroon-bakery.v2-unstable + // does not use the v2 tags (those are for macaroon-bakery.v2). + // It has no possible tags at all. + if strings.HasPrefix(r.modPath, "gopkg.in/") && strings.HasSuffix(r.modPath, "-unstable") { + return nil, nil + } + p := prefix if r.codeDir != "" { p = r.codeDir + "/" + p @@ -101,7 +101,9 @@ func (r *codeRepo) Versions(prefix string) ([]string, error) { if err != nil { return nil, err } + list := []string{} + var incompatible []string for _, tag := range tags { if !strings.HasPrefix(tag, p) { continue @@ -110,11 +112,34 @@ func (r *codeRepo) Versions(prefix string) ([]string, error) { if r.codeDir != "" { v = v[len(r.codeDir)+1:] } - if !semver.IsValid(v) || v != semver.Canonical(v) || isPseudoVersion(v) || !module.MatchPathMajor(v, r.pathMajor) { + if v == "" || v != module.CanonicalVersion(v) || IsPseudoVersion(v) { + continue + } + if !module.MatchPathMajor(v, r.pathMajor) { + if r.codeDir == "" && r.pathMajor == "" && semver.Major(v) > "v1" { + incompatible = append(incompatible, v) + } continue } list = append(list, v) } + + if len(incompatible) > 0 { + // Check for later versions that were created not following semantic import versioning, + // as indicated by the absence of a go.mod file. Those versions can be addressed + // by referring to them with a +incompatible suffix, as in v17.0.0+incompatible. + files, err := r.code.ReadFileRevs(incompatible, "go.mod", codehost.MaxGoMod) + if err != nil { + return nil, err + } + for _, rev := range incompatible { + f := files[rev] + if os.IsNotExist(f.Err) { + list = append(list, rev+"+incompatible") + } + } + } + SortVersions(list) return list, nil } @@ -131,7 +156,7 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) { if err != nil { return nil, err } - return r.convert(info) + return r.convert(info, rev) } func (r *codeRepo) Latest() (*RevInfo, error) { @@ -139,42 +164,99 @@ func (r *codeRepo) Latest() (*RevInfo, error) { if err != nil { return nil, err } - return r.convert(info) + return r.convert(info, "") } -func (r *codeRepo) convert(info *codehost.RevInfo) (*RevInfo, error) { - versionOK := func(v string) bool { - return semver.IsValid(v) && v == semver.Canonical(v) && !isPseudoVersion(v) && module.MatchPathMajor(v, r.pathMajor) +func (r *codeRepo) convert(info *codehost.RevInfo, statVers string) (*RevInfo, error) { + info2 := &RevInfo{ + Name: info.Name, + Short: info.Short, + Time: info.Time, } - v := info.Version - if r.codeDir == "" { - if !versionOK(v) { - v = PseudoVersion(r.pseudoMajor, info.Time, info.Short) - } + + // Determine version. + if module.CanonicalVersion(statVers) == statVers && module.MatchPathMajor(statVers, r.pathMajor) { + // The original call was repo.Stat(statVers), and requestedVersion is OK, so use it. + info2.Version = statVers } else { - p := r.codeDir + "/" - if strings.HasPrefix(v, p) && versionOK(v[len(p):]) { + // Otherwise derive a version from a code repo tag. + // Tag must have a prefix matching codeDir. + p := "" + if r.codeDir != "" { + p = r.codeDir + "/" + } + + // If this is a plain tag (no dir/ prefix) + // and the module path is unversioned, + // and if the underlying file tree has no go.mod, + // then allow using the tag with a +incompatible suffix. + canUseIncompatible := false + if r.codeDir == "" && r.pathMajor == "" { + _, errGoMod := r.code.ReadFile(info.Name, "go.mod", codehost.MaxGoMod) + if errGoMod != nil { + canUseIncompatible = true + } + } + + tagToVersion := func(v string) string { + if !strings.HasPrefix(v, p) { + return "" + } v = v[len(p):] + if module.CanonicalVersion(v) != v || IsPseudoVersion(v) { + return "" + } + if module.MatchPathMajor(v, r.pathMajor) { + return v + } + if canUseIncompatible { + return v + "+incompatible" + } + return "" + } + + // If info.Version is OK, use it. + if v := tagToVersion(info.Version); v != "" { + info2.Version = v } else { - v = PseudoVersion(r.pseudoMajor, info.Time, info.Short) + // Otherwise look through all known tags for latest in semver ordering. + for _, tag := range info.Tags { + if v := tagToVersion(tag); v != "" && semver.Compare(info2.Version, v) < 0 { + info2.Version = v + } + } + // Otherwise make a pseudo-version. + if info2.Version == "" { + tag, _ := r.code.RecentTag(statVers, p) + v = tagToVersion(tag) + // TODO: Check that v is OK for r.pseudoMajor or else is OK for incompatible. + info2.Version = PseudoVersion(r.pseudoMajor, v, info.Time, info.Short) + } } } - info2 := &RevInfo{ - Name: info.Name, - Short: info.Short, - Time: info.Time, - Version: v, + // Do not allow a successful stat of a pseudo-version for a subdirectory + // unless the subdirectory actually does have a go.mod. + if IsPseudoVersion(info2.Version) && r.codeDir != "" { + _, _, _, err := r.findDir(info2.Version) + if err != nil { + // TODO: It would be nice to return an error like "not a module". + // Right now we return "missing go.mod", which is a little confusing. + return nil, err + } } + return info2, nil } func (r *codeRepo) revToRev(rev string) string { if semver.IsValid(rev) { - if isPseudoVersion(rev) { - i := strings.Index(rev, "-") - j := strings.Index(rev[i+1:], "-") - return rev[i+1+j+1:] + if IsPseudoVersion(rev) { + r, _ := PseudoVersionRev(rev) + return r + } + if semver.Build(rev) == "+incompatible" { + rev = rev[:len(rev)-len("+incompatible")] } if r.codeDir == "" { return rev @@ -196,82 +278,100 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e if err != nil { return "", "", nil, err } - if r.pathMajor == "" || strings.HasPrefix(r.pathMajor, ".") { - if r.codeDir == "" { - return rev, "", nil, nil - } - file1 := path.Join(r.codeDir, "go.mod") - gomod1, err1 := r.code.ReadFile(rev, file1, codehost.MaxGoMod) - if err1 != nil { - return "", "", nil, fmt.Errorf("missing go.mod") - } - return rev, r.codeDir, gomod1, nil - } - // Suppose pathMajor is "/v2". - // Either go.mod should claim v2 and v2/go.mod should not exist, - // or v2/go.mod should exist and claim v2. Not both. - // Note that we don't check the full path, just the major suffix, - // because of replacement modules. This might be a fork of - // the real module, found at a different path, usable only in - // a replace directive. + // Load info about go.mod but delay consideration + // (except I/O error) until we rule out v2/go.mod. file1 := path.Join(r.codeDir, "go.mod") - file2 := path.Join(r.codeDir, r.pathMajor[1:], "go.mod") gomod1, err1 := r.code.ReadFile(rev, file1, codehost.MaxGoMod) - gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod) - found1 := err1 == nil && isMajor(gomod1, r.pathMajor) - found2 := err2 == nil && isMajor(gomod2, r.pathMajor) + if err1 != nil && !os.IsNotExist(err1) { + return "", "", nil, fmt.Errorf("reading %s/%s at revision %s: %v", r.pathPrefix, file1, rev, err1) + } + mpath1 := modfile.ModulePath(gomod1) + found1 := err1 == nil && isMajor(mpath1, r.pathMajor) - if err2 == nil && !found2 { - return "", "", nil, fmt.Errorf("%s has non-...%s module path", file2, r.pathMajor) - } - if found1 && found2 { - return "", "", nil, fmt.Errorf("both %s and %s claim ...%s module", file1, file2, r.pathMajor) - } - if found2 { - return rev, filepath.Join(r.codeDir, r.pathMajor), gomod2, nil + var file2 string + if r.pathMajor != "" && !strings.HasPrefix(r.pathMajor, ".") { + // Suppose pathMajor is "/v2". + // Either go.mod should claim v2 and v2/go.mod should not exist, + // or v2/go.mod should exist and claim v2. Not both. + // Note that we don't check the full path, just the major suffix, + // because of replacement modules. This might be a fork of + // the real module, found at a different path, usable only in + // a replace directive. + dir2 := path.Join(r.codeDir, r.pathMajor[1:]) + file2 = path.Join(dir2, "go.mod") + gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod) + if err2 != nil && !os.IsNotExist(err2) { + return "", "", nil, fmt.Errorf("reading %s/%s at revision %s: %v", r.pathPrefix, file2, rev, err2) + } + mpath2 := modfile.ModulePath(gomod2) + found2 := err2 == nil && isMajor(mpath2, r.pathMajor) + + if found1 && found2 { + return "", "", nil, fmt.Errorf("%s/%s and ...%s/go.mod both have ...%s module paths at revision %s", r.pathPrefix, file1, r.pathMajor, r.pathMajor, rev) + } + if found2 { + return rev, dir2, gomod2, nil + } + if err2 == nil { + if mpath2 == "" { + return "", "", nil, fmt.Errorf("%s/%s is missing module path at revision %s", r.pathPrefix, file2, rev) + } + return "", "", nil, fmt.Errorf("%s/%s has non-...%s module path %q at revision %s", r.pathPrefix, file2, r.pathMajor, mpath2, rev) + } } + + // Not v2/go.mod, so it's either go.mod or nothing. Which is it? if found1 { + // Explicit go.mod with matching module path OK. return rev, r.codeDir, gomod1, nil } - return "", "", nil, fmt.Errorf("missing or invalid go.mod") -} - -func isMajor(gomod []byte, pathMajor string) bool { - return strings.HasSuffix(modPath(gomod), pathMajor) -} - -var moduleStr = []byte("module") - -func modPath(mod []byte) string { - for len(mod) > 0 { - line := mod - mod = nil - if i := bytes.IndexByte(line, '\n'); i >= 0 { - line, mod = line[:i], line[i+1:] + if err1 == nil { + // Explicit go.mod with non-matching module path disallowed. + suffix := "" + if file2 != "" { + suffix = fmt.Sprintf(" (and ...%s/go.mod does not exist)", r.pathMajor) } - line = bytes.TrimSpace(line) - if !bytes.HasPrefix(line, moduleStr) { - continue + if mpath1 == "" { + return "", "", nil, fmt.Errorf("%s is missing module path%s at revision %s", file1, suffix, rev) } - line = line[len(moduleStr):] - n := len(line) - line = bytes.TrimSpace(line) - if len(line) == n || len(line) == 0 { - continue + if r.pathMajor != "" { // ".v1", ".v2" for gopkg.in + return "", "", nil, fmt.Errorf("%s has non-...%s module path %q%s at revision %s", file1, r.pathMajor, mpath1, suffix, rev) } - - if line[0] == '"' || line[0] == '`' { - p, err := strconv.Unquote(string(line)) - if err != nil { - return "" // malformed quoted string or multiline module path - } - return p - } - - return string(line) + return "", "", nil, fmt.Errorf("%s has post-%s module path %q%s at revision %s", file1, semver.Major(version), mpath1, suffix, rev) } - return "" // missing module path + + if r.codeDir == "" && (r.pathMajor == "" || strings.HasPrefix(r.pathMajor, ".")) { + // Implicit go.mod at root of repo OK for v0/v1 and for gopkg.in. + return rev, "", nil, nil + } + + // Implicit go.mod below root of repo or at v2+ disallowed. + // Be clear about possibility of using either location for v2+. + if file2 != "" { + return "", "", nil, fmt.Errorf("missing %s/go.mod and ...%s/go.mod at revision %s", r.pathPrefix, r.pathMajor, rev) + } + return "", "", nil, fmt.Errorf("missing %s/go.mod at revision %s", r.pathPrefix, rev) +} + +func isMajor(mpath, pathMajor string) bool { + if mpath == "" { + return false + } + if pathMajor == "" { + // mpath must NOT have version suffix. + i := len(mpath) + for i > 0 && '0' <= mpath[i-1] && mpath[i-1] <= '9' { + i-- + } + if i < len(mpath) && i >= 2 && mpath[i-1] == 'v' && mpath[i-2] == '/' { + // Found valid suffix. + return false + } + return true + } + // Otherwise pathMajor is ".v1", ".v2" (gopkg.in), or "/v2", "/v3" etc. + return strings.HasSuffix(mpath, pathMajor) } func (r *codeRepo) GoMod(version string) (data []byte, err error) { @@ -284,7 +384,7 @@ func (r *codeRepo) GoMod(version string) (data []byte, err error) { } data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod) if err != nil { - if e := strings.ToLower(err.Error()); strings.Contains(e, "not found") || strings.Contains(e, "404") { // TODO + if os.IsNotExist(err) { return r.legacyGoMod(rev, dir), nil } return nil, err @@ -292,41 +392,15 @@ func (r *codeRepo) GoMod(version string) (data []byte, err error) { return data, nil } -var altConfigs = []string{ - "Gopkg.lock", - - "GLOCKFILE", - "Godeps/Godeps.json", - "dependencies.tsv", - "glide.lock", - "vendor.conf", - "vendor.yml", - "vendor/manifest", - "vendor/vendor.json", -} - func (r *codeRepo) legacyGoMod(rev, dir string) []byte { - mf := new(modfile.File) - mf.AddModuleStmt(r.modPath) - for _, file := range altConfigs { - data, err := r.code.ReadFile(rev, path.Join(dir, file), codehost.MaxGoMod) - if err != nil { - continue - } - convert := modconv.Converters[file] - if convert == nil { - continue - } - if err := ConvertLegacyConfig(mf, file, data); err != nil { - continue - } - break - } - data, err := mf.Format() - if err != nil { - return []byte(fmt.Sprintf("%s\nmodule %q\n", modconv.Prefix, r.modPath)) - } - return append([]byte(modconv.Prefix+"\n"), data...) + // We used to try to build a go.mod reflecting pre-existing + // package management metadata files, but the conversion + // was inherently imperfect (because those files don't have + // exactly the same semantics as go.mod) and, when done + // for dependencies in the middle of a build, impossible to + // correct. So we stopped. + // Return a fake go.mod that simply declares the module path. + return []byte(fmt.Sprintf("module %s\n", modfile.AutoQuote(r.modPath))) } func (r *codeRepo) modPrefix(rev string) string { @@ -348,7 +422,7 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/") // Spool to local file. - f, err := ioutil.TempFile(tmpdir, "vgo-codehost-") + f, err := ioutil.TempFile(tmpdir, "go-codehost-") if err != nil { dl.Close() return "", err @@ -375,7 +449,7 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error if err != nil { return "", err } - f2, err := ioutil.TempFile(tmpdir, "vgo-") + f2, err := ioutil.TempFile(tmpdir, "go-codezip-") if err != nil { return "", err } @@ -441,6 +515,11 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error if !strings.HasPrefix(name, subdir) { continue } + if name == ".hg_archival.txt" { + // Inserted by hg archive. + // Not correct to drop from other version control systems, but too bad. + continue + } name = strings.TrimPrefix(name, subdir) if isVendoredPackage(name) { continue @@ -476,7 +555,8 @@ func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error } if !haveLICENSE && subdir != "" { - if data, err := r.code.ReadFile(rev, "LICENSE", codehost.MaxLICENSE); err == nil { + data, err := r.code.ReadFile(rev, "LICENSE", codehost.MaxLICENSE) + if err == nil { w, err := zw.Create(r.modPrefix(version) + "/LICENSE") if err != nil { return "", err @@ -523,54 +603,3 @@ func isVendoredPackage(name string) bool { } return strings.Contains(name[i:], "/") } - -func PseudoVersion(major string, t time.Time, rev string) string { - if major == "" { - major = "v0" - } - return fmt.Sprintf("%s.0.0-%s-%s", major, t.UTC().Format("20060102150405"), rev) -} - -var ErrNotPseudoVersion = errors.New("not a pseudo-version") - -/* -func ParsePseudoVersion(repo Repo, version string) (rev string, err error) { - major := semver.Major(version) - if major == "" { - return "", ErrNotPseudoVersion - } - majorPrefix := major + ".0.0-" - if !strings.HasPrefix(version, majorPrefix) || !strings.Contains(version[len(majorPrefix):], "-") { - return "", ErrNotPseudoVersion - } - versionSuffix := version[len(majorPrefix):] - for i := 0; versionSuffix[i] != '-'; i++ { - c := versionSuffix[i] - if c < '0' || '9' < c { - return "", ErrNotPseudoVersion - } - } - rev = versionSuffix[strings.Index(versionSuffix, "-")+1:] - if rev == "" { - return "", ErrNotPseudoVersion - } - if proxyURL != "" { - return version, nil - } - fullRev, t, err := repo.CommitInfo(rev) - if err != nil { - return "", fmt.Errorf("unknown pseudo-version %s: loading %v: %v", version, rev, err) - } - v := PseudoVersion(major, t, repo.ShortRev(fullRev)) - if v != version { - return "", fmt.Errorf("unknown pseudo-version %s: %v is %v", version, rev, v) - } - return fullRev, nil -} -*/ - -var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.0\.0-[0-9]{14}-[A-Za-z0-9]+$`) - -func isPseudoVersion(v string) bool { - return pseudoVersionRE.MatchString(v) -} diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go index e3b106e195..79b82786cb 100644 --- a/src/cmd/go/internal/modfetch/coderepo_test.go +++ b/src/cmd/go/internal/modfetch/coderepo_test.go @@ -19,10 +19,6 @@ import ( "cmd/go/internal/modfetch/codehost" ) -func init() { - isTest = true -} - func TestMain(m *testing.M) { os.Exit(testMain(m)) } @@ -38,6 +34,15 @@ func testMain(m *testing.M) int { return m.Run() } +const ( + vgotest1git = "github.com/rsc/vgotest1" + vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg" +) + +var altVgotests = []string{ + vgotest1hg, +} + var codeRepoTests = []struct { path string lookerr string @@ -83,15 +88,15 @@ var codeRepoTests = []struct { path: "github.com/rsc/vgotest1/v2", rev: "v2.0.0", version: "v2.0.0", - name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", - short: "80d85c5d4d17", - time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), - ziperr: "missing go.mod", + name: "45f53230a74ad275c7127e117ac46914c8126160", + short: "45f53230a74a", + time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC), + ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", }, { path: "github.com/rsc/vgotest1", - rev: "80d85", - version: "v0.0.0-20180219231006-80d85c5d4d17", + rev: "80d85c5", + version: "v1.0.0", name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", short: "80d85c5d4d17", time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), @@ -104,7 +109,7 @@ var codeRepoTests = []struct { { path: "github.com/rsc/vgotest1", rev: "mytag", - version: "v0.0.0-20180219231006-80d85c5d4d17", + version: "v1.0.0", name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", short: "80d85c5d4d17", time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), @@ -116,32 +121,32 @@ var codeRepoTests = []struct { }, { path: "github.com/rsc/vgotest1/v2", - rev: "80d85", - version: "v2.0.0-20180219231006-80d85c5d4d17", - name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", - short: "80d85c5d4d17", - time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), - gomoderr: "missing go.mod", - ziperr: "missing go.mod", + rev: "45f53230a", + version: "v2.0.0", + name: "45f53230a74ad275c7127e117ac46914c8126160", + short: "45f53230a74a", + time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC), + gomoderr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", + ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", }, { path: "github.com/rsc/vgotest1/v54321", - rev: "80d85", + rev: "80d85c5", version: "v54321.0.0-20180219231006-80d85c5d4d17", name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", short: "80d85c5d4d17", time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), - ziperr: "missing go.mod", + ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17", }, { path: "github.com/rsc/vgotest1/submod", rev: "v1.0.0", - err: "unknown revision \"submod/v1.0.0\"", + err: "unknown revision submod/v1.0.0", }, { path: "github.com/rsc/vgotest1/submod", rev: "v1.0.3", - err: "unknown revision \"submod/v1.0.3\"", + err: "unknown revision submod/v1.0.3", }, { path: "github.com/rsc/vgotest1/submod", @@ -188,7 +193,7 @@ var codeRepoTests = []struct { name: "f18795870fb14388a21ef3ebc1d75911c8694f31", short: "f18795870fb1", time: time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC), - gomoderr: "v2/go.mod has non-.../v2 module path", + gomoderr: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3", }, { path: "github.com/rsc/vgotest1/v2", @@ -197,7 +202,7 @@ var codeRepoTests = []struct { name: "1f863feb76bc7029b78b21c5375644838962f88d", short: "1f863feb76bc", time: time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC), - gomoderr: "both go.mod and v2/go.mod claim .../v2 module", + gomoderr: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4", }, { path: "github.com/rsc/vgotest1/v2", @@ -208,33 +213,6 @@ var codeRepoTests = []struct { time: time.Date(2018, 2, 20, 0, 3, 59, 0, time.UTC), gomod: "module \"github.com/rsc/vgotest1/v2\" // v2/go.mod\n", }, - { - path: "go.googlesource.com/scratch", - rev: "0f302529858", - version: "v0.0.0-20180220024720-0f3025298580", - name: "0f30252985809011f026b5a2d5cf456e021623da", - short: "0f3025298580", - time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule go.googlesource.com/scratch\n", - }, - { - path: "go.googlesource.com/scratch/rsc", - rev: "0f302529858", - version: "v0.0.0-20180220024720-0f3025298580", - name: "0f30252985809011f026b5a2d5cf456e021623da", - short: "0f3025298580", - time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC), - gomod: "", - }, - { - path: "go.googlesource.com/scratch/cbro", - rev: "0f302529858", - version: "v0.0.0-20180220024720-0f3025298580", - name: "0f30252985809011f026b5a2d5cf456e021623da", - short: "0f3025298580", - time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC), - gomoderr: "missing go.mod", - }, { // redirect to github path: "rsc.io/quote", @@ -250,16 +228,15 @@ var codeRepoTests = []struct { path: "swtch.com/testmod", rev: "v1.0.0", version: "v1.0.0", - name: "v1.0.0", - short: "v1.0.0", - time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC), - gomod: "module \"swtch.com/testmod\"\n", + // NO name or short - we intentionally ignore those in the proxy protocol + time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC), + gomod: "module \"swtch.com/testmod\"\n", }, { // redirect to googlesource path: "golang.org/x/text", rev: "4e4a3210bb", - version: "v0.0.0-20180208041248-4e4a3210bb54", + version: "v0.3.1-0.20180208041248-4e4a3210bb54", name: "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1", short: "4e4a3210bb54", time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC), @@ -274,27 +251,26 @@ var codeRepoTests = []struct { }, { // package in subdirectory - custom domain - path: "golang.org/x/net/context", - lookerr: "module root is \"golang.org/x/net\"", + // In general we can't reject these definitively in Lookup, + // but gopkg.in is special. + path: "gopkg.in/yaml.v2/abc", + lookerr: "invalid module path \"gopkg.in/yaml.v2/abc\"", }, { // package in subdirectory - github - path: "github.com/rsc/quote/buggy", - rev: "c4d4236f", - version: "v0.0.0-20180214154420-c4d4236f9242", - name: "c4d4236f92427c64bfbcf1cc3f8142ab18f30b22", - short: "c4d4236f9242", - time: time.Date(2018, 2, 14, 15, 44, 20, 0, time.UTC), - gomoderr: "missing go.mod", + // Because it's a package, Stat should fail entirely. + path: "github.com/rsc/quote/buggy", + rev: "c4d4236f", + err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242", }, { path: "gopkg.in/yaml.v2", rev: "d670f940", - version: "v2.0.0-20180109114331-d670f9405373", + version: "v2.0.0", name: "d670f9405373e636a5a2765eea47fac0c9bc91a4", short: "d670f9405373", time: time.Date(2018, 1, 9, 11, 43, 31, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule gopkg.in/yaml.v2\n", + gomod: "module gopkg.in/yaml.v2\n", }, { path: "gopkg.in/check.v1", @@ -303,12 +279,12 @@ var codeRepoTests = []struct { name: "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec", short: "20d25e280405", time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule gopkg.in/check.v1\n", + gomod: "module gopkg.in/check.v1\n", }, { path: "gopkg.in/yaml.v2", rev: "v2", - version: "v2.0.0-20180328195020-5420a8b6744d", + version: "v2.2.1", name: "5420a8b6744d3b0345ab293f6fcba19c978f1183", short: "5420a8b6744d", time: time.Date(2018, 3, 28, 19, 50, 20, 0, time.UTC), @@ -317,11 +293,11 @@ var codeRepoTests = []struct { { path: "vcs-test.golang.org/go/mod/gitrepo1", rev: "master", - version: "v0.0.0-20180417194322-ede458df7cd0", + version: "v1.2.4-annotated", name: "ede458df7cd0fdca520df19a33158086a8a68e81", short: "ede458df7cd0", time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule vcs-test.golang.org/go/mod/gitrepo1\n", + gomod: "module vcs-test.golang.org/go/mod/gitrepo1\n", }, { path: "gopkg.in/natefinch/lumberjack.v2", @@ -330,7 +306,7 @@ var codeRepoTests = []struct { name: "a96e63847dc3c67d17befa69c303767e2f84e54f", short: "a96e63847dc3", time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule gopkg.in/natefinch/lumberjack.v2\n", + gomod: "module gopkg.in/natefinch/lumberjack.v2\n", }, { path: "gopkg.in/natefinch/lumberjack.v2", @@ -345,7 +321,7 @@ var codeRepoTests = []struct { name: "a96e63847dc3c67d17befa69c303767e2f84e54f", short: "a96e63847dc3", time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC), - gomod: "//vgo 0.0.4\n\nmodule gopkg.in/natefinch/lumberjack.v2\n", + gomod: "module gopkg.in/natefinch/lumberjack.v2\n", }, } @@ -358,15 +334,15 @@ func TestCodeRepo(t *testing.T) { } defer os.RemoveAll(tmpdir) for _, tt := range codeRepoTests { - t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, func(t *testing.T) { + f := func(t *testing.T) { repo, err := Lookup(tt.path) - if err != nil { - if tt.lookerr != "" { - if err.Error() == tt.lookerr { - return - } - t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr) + if tt.lookerr != "" { + if err != nil && err.Error() == tt.lookerr { + return } + t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr) + } + if err != nil { t.Fatalf("Lookup(%q): %v", tt.path, err) } if tt.mpath == "" { @@ -446,68 +422,73 @@ func TestCodeRepo(t *testing.T) { t.Fatalf("zip = %v\nwant %v\n", names, tt.zip) } } - }) - } -} - -var importTests = []struct { - path string - mpath string - err string -}{ - { - path: "golang.org/x/net/context", - mpath: "golang.org/x/net", - }, - { - path: "github.com/rsc/quote/buggy", - mpath: "github.com/rsc/quote", - }, - { - path: "golang.org/x/net", - mpath: "golang.org/x/net", - }, - { - path: "github.com/rsc/quote", - mpath: "github.com/rsc/quote", - }, - { - path: "golang.org/x/foo/bar", - err: "unknown module golang.org/x/foo/bar: no go-import tags", - }, -} - -func TestImport(t *testing.T) { - testenv.MustHaveExternalNetwork(t) - - for _, tt := range importTests { - t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) { - repo, info, err := Import(tt.path, nil) - if err != nil { - if tt.err != "" { - if err.Error() == tt.err { - return - } - t.Errorf("Import(%q): %v, want error %q", tt.path, err, tt.err) + } + t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f) + if strings.HasPrefix(tt.path, vgotest1git) { + for _, alt := range altVgotests { + // Note: Communicating with f through tt; should be cleaned up. + old := tt + tt.path = alt + strings.TrimPrefix(tt.path, vgotest1git) + if strings.HasPrefix(tt.mpath, vgotest1git) { + tt.mpath = alt + strings.TrimPrefix(tt.mpath, vgotest1git) } - t.Fatalf("Lookup(%q): %v", tt.path, err) + var m map[string]string + if alt == vgotest1hg { + m = hgmap + } + tt.version = remap(tt.version, m) + tt.name = remap(tt.name, m) + tt.short = remap(tt.short, m) + tt.rev = remap(tt.rev, m) + tt.gomoderr = remap(tt.gomoderr, m) + tt.ziperr = remap(tt.ziperr, m) + t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, f) + tt = old } - if mpath := repo.ModulePath(); mpath != tt.mpath { - t.Errorf("repo.ModulePath() = %q (%v), want %q", mpath, info.Version, tt.mpath) - } - }) + } } } +var hgmap = map[string]string{ + "github.com/rsc/vgotest1/": "vcs-test.golang.org/hg/vgotest1.hg/", + "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6", + "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7", + "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832", + "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44", + "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46", + "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71", + "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459", + "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4", +} + +func remap(name string, m map[string]string) string { + if m[name] != "" { + return m[name] + } + if codehost.AllHex(name) { + for k, v := range m { + if strings.HasPrefix(k, name) { + return v[:len(name)] + } + } + } + for k, v := range m { + name = strings.Replace(name, k, v, -1) + if codehost.AllHex(k) { + name = strings.Replace(name, k[:12], v[:12], -1) + } + } + return name +} + var codeRepoVersionsTests = []struct { path string prefix string versions []string }{ - // TODO: Why do we allow a prefix here at all? { path: "github.com/rsc/vgotest1", - versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0"}, + versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0", "v2.0.0+incompatible"}, }, { path: "github.com/rsc/vgotest1", @@ -528,7 +509,7 @@ var codeRepoVersionsTests = []struct { }, { path: "gopkg.in/natefinch/lumberjack.v2", - versions: []string{}, + versions: nil, }, } @@ -570,6 +551,10 @@ var latestTests = []struct { path: "github.com/rsc/vgotest1", version: "v0.0.0-20180219223237-a08abb797a67", }, + { + path: "github.com/rsc/vgotest1/subdir", + err: "missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67", + }, { path: "swtch.com/testmod", version: "v1.1.1", @@ -601,6 +586,9 @@ func TestLatest(t *testing.T) { } t.Fatalf("Latest(): %v", err) } + if tt.err != "" { + t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err) + } if info.Version != tt.version { t.Fatalf("Latest() = %v, want %v", info.Version, tt.version) } @@ -610,23 +598,26 @@ func TestLatest(t *testing.T) { // fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags type fixedTagsRepo struct { - root string tags []string } func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil } -func (ch *fixedTagsRepo) Root() string { return ch.root } func (ch *fixedTagsRepo) Latest() (*codehost.RevInfo, error) { panic("not impl") } func (ch *fixedTagsRepo) ReadFile(string, string, int64) ([]byte, error) { panic("not impl") } +func (ch *fixedTagsRepo) ReadFileRevs([]string, string, int64) (map[string]*codehost.FileRev, error) { + panic("not impl") +} func (ch *fixedTagsRepo) ReadZip(string, string, int64) (io.ReadCloser, string, error) { panic("not impl") } +func (ch *fixedTagsRepo) RecentTag(string, string) (string, error) { + panic("not impl") +} func (ch *fixedTagsRepo) Stat(string) (*codehost.RevInfo, error) { panic("not impl") } func TestNonCanonicalSemver(t *testing.T) { root := "golang.org/x/issue24476" ch := &fixedTagsRepo{ - root: root, tags: []string{ "", "huh?", "1.0.1", // what about "version 1 dot dogcow"? @@ -637,7 +628,7 @@ func TestNonCanonicalSemver(t *testing.T) { }, } - cr, err := newCodeRepo(ch, root) + cr, err := newCodeRepo(ch, root, root) if err != nil { t.Fatal(err) } @@ -650,39 +641,3 @@ func TestNonCanonicalSemver(t *testing.T) { t.Fatal("unexpected versions returned:", v) } } - -var modPathTests = []struct { - input []byte - expected string -}{ - {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"}, - {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"}, - {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"}, - {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"}, - {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"}, - {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"}, - {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"}, - {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"}, - {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"}, - {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""}, - {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"}, - {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""}, - {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""}, - {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""}, -} - -func TestModPath(t *testing.T) { - for _, test := range modPathTests { - t.Run(string(test.input), func(t *testing.T) { - result := modPath(test.input) - if result != test.expected { - t.Fatalf("modPath(%s): %s, want %s", string(test.input), result, test.expected) - } - }) - } -} diff --git a/src/cmd/go/internal/modfetch/domain.go b/src/cmd/go/internal/modfetch/domain.go deleted file mode 100644 index 2494f80ab0..0000000000 --- a/src/cmd/go/internal/modfetch/domain.go +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Support for custom domains. - -package modfetch - -import ( - "encoding/xml" - "fmt" - "io" - "net/url" - "os" - "strings" - - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/gitrepo" -) - -// metaImport represents the parsed tags from HTML files. -type metaImport struct { - Prefix, VCS, RepoRoot string -} - -func lookupCustomDomain(path string) (Repo, error) { - dom := path - if i := strings.Index(dom, "/"); i >= 0 { - dom = dom[:i] - } - if !strings.Contains(dom, ".") { - return nil, fmt.Errorf("unknown module %s: not a domain name", path) - } - var body io.ReadCloser - err := webGetGoGet("https://"+path+"?go-get=1", &body) - if body != nil { - defer body.Close() - } - if err != nil { - fmt.Fprintf(os.Stderr, "FindRepo: %v\n", err) - return nil, err - } - // Note: accepting a non-200 OK here, so people can serve a - // meta import in their http 404 page. - imports, err := parseMetaGoImports(body) - if err != nil { - fmt.Fprintf(os.Stderr, "findRepo: %v\n", err) - return nil, err - } - if len(imports) == 0 { - return nil, fmt.Errorf("unknown module %s: no go-import tags", path) - } - - // First look for new module definition. - for _, imp := range imports { - if path == imp.Prefix || strings.HasPrefix(path, imp.Prefix+"/") { - if imp.VCS == "mod" { - u, err := url.Parse(imp.RepoRoot) - if err != nil { - return nil, fmt.Errorf("invalid module URL %q", imp.RepoRoot) - } else if u.Scheme != "https" { - // TODO: Allow -insecure flag as a build flag? - return nil, fmt.Errorf("invalid module URL %q: must be HTTPS", imp.RepoRoot) - } - return newProxyRepo(imp.RepoRoot, imp.Prefix), nil - } - } - } - - // Fall back to redirections to known version control systems. - for _, imp := range imports { - if path == imp.Prefix { - if !strings.HasPrefix(imp.RepoRoot, "https://") { - // TODO: Allow -insecure flag as a build flag? - return nil, fmt.Errorf("invalid server URL %q: must be HTTPS", imp.RepoRoot) - } - if imp.VCS == "git" { - code, err := gitrepo.Repo(imp.RepoRoot, imp.Prefix) - if err != nil { - return nil, err - } - return newCodeRepo(code, path) - } - return nil, fmt.Errorf("unknown VCS, Repo: %s, %s", imp.VCS, imp.RepoRoot) - } - } - - // Check for redirect to repo root. - for _, imp := range imports { - if strings.HasPrefix(path, imp.Prefix+"/") { - return nil, &ModuleSubdirError{imp.Prefix} - } - } - - return nil, fmt.Errorf("unknown module %s: no matching go-import tags", path) -} - -type ModuleSubdirError struct { - ModulePath string -} - -func (e *ModuleSubdirError) Error() string { - return fmt.Sprintf("module root is %q", e.ModulePath) -} - -type customPrefix struct { - codehost.Repo - root string -} - -func (c *customPrefix) Root() string { - return c.root -} - -// parseMetaGoImports returns meta imports from the HTML in r. -// Parsing ends at the end of the section or the beginning of the . -func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) { - d := xml.NewDecoder(r) - d.CharsetReader = charsetReader - d.Strict = false - var t xml.Token - for { - t, err = d.RawToken() - if err != nil { - if err == io.EOF || len(imports) > 0 { - err = nil - } - return - } - if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") { - return - } - if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") { - return - } - e, ok := t.(xml.StartElement) - if !ok || !strings.EqualFold(e.Name.Local, "meta") { - continue - } - if attrValue(e.Attr, "name") != "go-import" { - continue - } - if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 { - imports = append(imports, metaImport{ - Prefix: f[0], - VCS: f[1], - RepoRoot: f[2], - }) - } - } -} - -// attrValue returns the attribute value for the case-insensitive key -// `name', or the empty string if nothing is found. -func attrValue(attrs []xml.Attr, name string) string { - for _, a := range attrs { - if strings.EqualFold(a.Name.Local, name) { - return a.Value - } - } - return "" -} - -// charsetReader returns a reader for the given charset. Currently -// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful -// error which is printed by go get, so the user can find why the package -// wasn't downloaded if the encoding is not supported. Note that, in -// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters -// greater than 0x7f are not rejected). -func charsetReader(charset string, input io.Reader) (io.Reader, error) { - switch strings.ToLower(charset) { - case "ascii": - return input, nil - default: - return nil, fmt.Errorf("can't decode XML document using charset %q", charset) - } -} diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go new file mode 100644 index 0000000000..2e26bac434 --- /dev/null +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -0,0 +1,365 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modfetch + +import ( + "archive/zip" + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "sort" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/dirhash" + "cmd/go/internal/module" + "cmd/go/internal/par" +) + +var downloadCache par.Cache + +// Download downloads the specific module version to the +// local download cache and returns the name of the directory +// corresponding to the root of the module's file tree. +func Download(mod module.Version) (dir string, err error) { + if PkgMod == "" { + // Do not download to current directory. + return "", fmt.Errorf("missing modfetch.PkgMod") + } + + // The par.Cache here avoids duplicate work but also + // avoids conflicts from simultaneous calls by multiple goroutines + // for the same version. + type cached struct { + dir string + err error + } + c := downloadCache.Do(mod, func() interface{} { + dir, err := DownloadDir(mod) + if err != nil { + return cached{"", err} + } + if files, _ := ioutil.ReadDir(dir); len(files) == 0 { + zipfile, err := DownloadZip(mod) + if err != nil { + return cached{"", err} + } + modpath := mod.Path + "@" + mod.Version + if err := Unzip(dir, zipfile, modpath, 0); err != nil { + fmt.Fprintf(os.Stderr, "-> %s\n", err) + return cached{"", err} + } + } + checkSum(mod) + return cached{dir, nil} + }).(cached) + return c.dir, c.err +} + +var downloadZipCache par.Cache + +// DownloadZip downloads the specific module version to the +// local zip cache and returns the name of the zip file. +func DownloadZip(mod module.Version) (zipfile string, err error) { + // The par.Cache here avoids duplicate work but also + // avoids conflicts from simultaneous calls by multiple goroutines + // for the same version. + type cached struct { + zipfile string + err error + } + c := downloadZipCache.Do(mod, func() interface{} { + zipfile, err := CachePath(mod, "zip") + if err != nil { + return cached{"", err} + } + if _, err := os.Stat(zipfile); err == nil { + // Use it. + // This should only happen if the mod/cache directory is preinitialized + // or if pkg/mod/path was removed but not pkg/mod/cache/download. + if cfg.CmdName != "mod download" { + fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version) + } + } else { + if err := os.MkdirAll(filepath.Dir(zipfile), 0777); err != nil { + return cached{"", err} + } + if cfg.CmdName != "mod download" { + fmt.Fprintf(os.Stderr, "go: downloading %s %s\n", mod.Path, mod.Version) + } + if err := downloadZip(mod, zipfile); err != nil { + return cached{"", err} + } + } + return cached{zipfile, nil} + }).(cached) + return c.zipfile, c.err +} + +func downloadZip(mod module.Version, target string) error { + repo, err := Lookup(mod.Path) + if err != nil { + return err + } + tmpfile, err := repo.Zip(mod.Version, os.TempDir()) + if err != nil { + return err + } + defer os.Remove(tmpfile) + + // Double-check zip file looks OK. + z, err := zip.OpenReader(tmpfile) + if err != nil { + return err + } + prefix := mod.Path + "@" + mod.Version + for _, f := range z.File { + if !strings.HasPrefix(f.Name, prefix) { + z.Close() + return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name) + } + } + z.Close() + + hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash) + if err != nil { + return err + } + checkOneSum(mod, hash) // check before installing the zip file + r, err := os.Open(tmpfile) + if err != nil { + return err + } + defer r.Close() + w, err := os.Create(target) + if err != nil { + return err + } + if _, err := io.Copy(w, r); err != nil { + w.Close() + return fmt.Errorf("copying: %v", err) + } + if err := w.Close(); err != nil { + return err + } + return ioutil.WriteFile(target+"hash", []byte(hash), 0666) +} + +var GoSumFile string // path to go.sum; set by package modload + +var goSum struct { + mu sync.Mutex + m map[module.Version][]string // content of go.sum file (+ go.modverify if present) + enabled bool // whether to use go.sum at all + modverify string // path to go.modverify, to be deleted +} + +// initGoSum initializes the go.sum data. +// It reports whether use of go.sum is now enabled. +// The goSum lock must be held. +func initGoSum() bool { + if GoSumFile == "" { + return false + } + if goSum.m != nil { + return true + } + + goSum.m = make(map[module.Version][]string) + data, err := ioutil.ReadFile(GoSumFile) + if err != nil && !os.IsNotExist(err) { + base.Fatalf("go: %v", err) + } + goSum.enabled = true + readGoSum(GoSumFile, data) + + // Add old go.modverify file. + // We'll delete go.modverify in WriteGoSum. + alt := strings.TrimSuffix(GoSumFile, ".sum") + ".modverify" + if data, err := ioutil.ReadFile(alt); err == nil { + readGoSum(alt, data) + goSum.modverify = alt + } + return true +} + +// emptyGoModHash is the hash of a 1-file tree containing a 0-length go.mod. +// A bug caused us to write these into go.sum files for non-modules. +// We detect and remove them. +const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY=" + +// readGoSum parses data, which is the content of file, +// and adds it to goSum.m. The goSum lock must be held. +func readGoSum(file string, data []byte) { + lineno := 0 + for len(data) > 0 { + var line []byte + lineno++ + i := bytes.IndexByte(data, '\n') + if i < 0 { + line, data = data, nil + } else { + line, data = data[:i], data[i+1:] + } + f := strings.Fields(string(line)) + if len(f) == 0 { + // blank line; skip it + continue + } + if len(f) != 3 { + base.Fatalf("go: malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f)) + } + if f[2] == emptyGoModHash { + // Old bug; drop it. + continue + } + mod := module.Version{Path: f[0], Version: f[1]} + goSum.m[mod] = append(goSum.m[mod], f[2]) + } +} + +// checkSum checks the given module's checksum. +func checkSum(mod module.Version) { + if PkgMod == "" { + // Do not use current directory. + return + } + + // Do the file I/O before acquiring the go.sum lock. + ziphash, err := CachePath(mod, "ziphash") + if err != nil { + base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err) + } + data, err := ioutil.ReadFile(ziphash) + if err != nil { + if os.IsNotExist(err) { + // This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes. + return + } + base.Fatalf("go: verifying %s@%s: %v", mod.Path, mod.Version, err) + } + h := strings.TrimSpace(string(data)) + if !strings.HasPrefix(h, "h1:") { + base.Fatalf("go: verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h) + } + + checkOneSum(mod, h) +} + +// goModSum returns the checksum for the go.mod contents. +func goModSum(data []byte) (string, error) { + return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) { + return ioutil.NopCloser(bytes.NewReader(data)), nil + }) +} + +// checkGoMod checks the given module's go.mod checksum; +// data is the go.mod content. +func checkGoMod(path, version string, data []byte) { + h, err := goModSum(data) + if err != nil { + base.Fatalf("go: verifying %s %s go.mod: %v", path, version, err) + } + + checkOneSum(module.Version{Path: path, Version: version + "/go.mod"}, h) +} + +// checkOneSum checks that the recorded hash for mod is h. +func checkOneSum(mod module.Version, h string) { + goSum.mu.Lock() + defer goSum.mu.Unlock() + if !initGoSum() { + return + } + + for _, vh := range goSum.m[mod] { + if h == vh { + return + } + if strings.HasPrefix(vh, "h1:") { + base.Fatalf("go: verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\tgo.sum: %v", mod.Path, mod.Version, h, vh) + } + } + if len(goSum.m[mod]) > 0 { + fmt.Fprintf(os.Stderr, "warning: verifying %s@%s: unknown hashes in go.sum: %v; adding %v", mod.Path, mod.Version, strings.Join(goSum.m[mod], ", "), h) + } + goSum.m[mod] = append(goSum.m[mod], h) +} + +// Sum returns the checksum for the downloaded copy of the given module, +// if present in the download cache. +func Sum(mod module.Version) string { + if PkgMod == "" { + // Do not use current directory. + return "" + } + + ziphash, err := CachePath(mod, "ziphash") + if err != nil { + return "" + } + data, err := ioutil.ReadFile(ziphash) + if err != nil { + return "" + } + return strings.TrimSpace(string(data)) +} + +// WriteGoSum writes the go.sum file if it needs to be updated. +func WriteGoSum() { + goSum.mu.Lock() + defer goSum.mu.Unlock() + if !initGoSum() { + return + } + + var mods []module.Version + for m := range goSum.m { + mods = append(mods, m) + } + module.Sort(mods) + var buf bytes.Buffer + for _, m := range mods { + list := goSum.m[m] + sort.Strings(list) + for _, h := range list { + fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h) + } + } + + data, _ := ioutil.ReadFile(GoSumFile) + if !bytes.Equal(data, buf.Bytes()) { + if err := ioutil.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil { + base.Fatalf("go: writing go.sum: %v", err) + } + } + + if goSum.modverify != "" { + os.Remove(goSum.modverify) + } +} + +// TrimGoSum trims go.sum to contain only the modules for which keep[m] is true. +func TrimGoSum(keep map[module.Version]bool) { + goSum.mu.Lock() + defer goSum.mu.Unlock() + if !initGoSum() { + return + } + + for m := range goSum.m { + // If we're keeping x@v we also keep x@v/go.mod. + // Map x@v/go.mod back to x@v for the keep lookup. + noGoMod := module.Version{Path: m.Path, Version: strings.TrimSuffix(m.Version, "/go.mod")} + if !keep[m] && !keep[noGoMod] { + delete(goSum.m, m) + } + } +} diff --git a/src/cmd/go/internal/modfetch/github/fetch.go b/src/cmd/go/internal/modfetch/github/fetch.go deleted file mode 100644 index a2a90f166c..0000000000 --- a/src/cmd/go/internal/modfetch/github/fetch.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package github - -import ( - "fmt" - "strings" - - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/gitrepo" -) - -// Lookup returns the code repository enclosing the given module path, -// which must begin with github.com/. -func Lookup(path string) (codehost.Repo, error) { - f := strings.Split(path, "/") - if len(f) < 3 || f[0] != "github.com" { - return nil, fmt.Errorf("github repo must be github.com/org/project") - } - path = f[0] + "/" + f[1] + "/" + f[2] - return gitrepo.Repo("https://"+path, path) -} diff --git a/src/cmd/go/internal/modfetch/gitrepo/fetch.go b/src/cmd/go/internal/modfetch/gitrepo/fetch.go deleted file mode 100644 index 0d6eb4b7e9..0000000000 --- a/src/cmd/go/internal/modfetch/gitrepo/fetch.go +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package gitrepo provides a Git-based implementation of codehost.Repo. -package gitrepo - -import ( - "archive/zip" - "bytes" - "cmd/go/internal/modfetch/codehost" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - "sync" - "time" -) - -// Repo returns the code repository at the given Git remote reference. -// The returned repo reports the given root as its module root. -func Repo(remote, root string) (codehost.Repo, error) { - return newRepo(remote, root, false) -} - -// LocalRepo is like Repo but accepts both Git remote references -// and paths to repositories on the local file system. -// The returned repo reports the given root as its module root. -func LocalRepo(remote, root string) (codehost.Repo, error) { - return newRepo(remote, root, true) -} - -const workDirType = "git2" - -func newRepo(remote, root string, localOK bool) (codehost.Repo, error) { - r := &repo{remote: remote, root: root, canArchive: true} - if strings.Contains(remote, "://") { - // This is a remote path. - dir, err := codehost.WorkDir(workDirType, r.remote) - if err != nil { - return nil, err - } - r.dir = dir - if _, err := os.Stat(filepath.Join(dir, "objects")); err != nil { - if _, err := codehost.Run(dir, "git", "init", "--bare"); err != nil { - os.RemoveAll(dir) - return nil, err - } - // We could just say git fetch https://whatever later, - // but this lets us say git fetch origin instead, which - // is a little nicer. More importantly, using a named remote - // avoids a problem with Git LFS. See golang.org/issue/25605. - if _, err := codehost.Run(dir, "git", "remote", "add", "origin", r.remote); err != nil { - os.RemoveAll(dir) - return nil, err - } - r.remote = "origin" - } - } else { - // Local path. - // Disallow colon (not in ://) because sometimes - // that's rcp-style host:path syntax and sometimes it's not (c:\work). - // The go command has always insisted on URL syntax for ssh. - if strings.Contains(remote, ":") { - return nil, fmt.Errorf("git remote cannot use host:path syntax") - } - if !localOK { - return nil, fmt.Errorf("git remote must not be local directory") - } - r.local = true - info, err := os.Stat(remote) - if err != nil { - return nil, err - } - if !info.IsDir() { - return nil, fmt.Errorf("%s exists but is not a directory", remote) - } - r.dir = remote - } - return r, nil -} - -type repo struct { - remote string - local bool - root string - dir string - canArchive bool - - refsOnce sync.Once - refs map[string]string - refsErr error -} - -func (r *repo) Root() string { - return r.root -} - -// loadRefs loads heads and tags references from the remote into the map r.refs. -// Should only be called as r.refsOnce.Do(r.loadRefs). -func (r *repo) loadRefs() { - // The git protocol sends all known refs and ls-remote filters them on the client side, - // so we might as well record both heads and tags in one shot. - // Most of the time we only care about tags but sometimes we care about heads too. - out, err := codehost.Run(r.dir, "git", "ls-remote", "-q", r.remote) - if err != nil { - r.refsErr = err - return - } - - r.refs = make(map[string]string) - for _, line := range strings.Split(string(out), "\n") { - f := strings.Fields(line) - if len(f) != 2 { - continue - } - if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") { - r.refs[f[1]] = f[0] - } - } - for ref, hash := range r.refs { - if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag - r.refs[strings.TrimSuffix(ref, "^{}")] = hash - delete(r.refs, ref) - } - } -} - -func (r *repo) Tags(prefix string) ([]string, error) { - r.refsOnce.Do(r.loadRefs) - if r.refsErr != nil { - return nil, r.refsErr - } - - tags := []string{} - for ref := range r.refs { - if !strings.HasPrefix(ref, "refs/tags/") { - continue - } - tag := ref[len("refs/tags/"):] - if !strings.HasPrefix(tag, prefix) { - continue - } - tags = append(tags, tag) - } - sort.Strings(tags) - return tags, nil -} - -func (r *repo) Latest() (*codehost.RevInfo, error) { - r.refsOnce.Do(r.loadRefs) - if r.refsErr != nil { - return nil, r.refsErr - } - if r.refs["HEAD"] == "" { - return nil, fmt.Errorf("no commits") - } - return r.Stat(r.refs["HEAD"]) -} - -// findRef finds some ref name for the given hash, -// for use when the server requires giving a ref instead of a hash. -// There may be multiple ref names for a given hash, -// in which case this returns some name - it doesn't matter which. -func (r *repo) findRef(hash string) (ref string, ok bool) { - r.refsOnce.Do(r.loadRefs) - for ref, h := range r.refs { - if h == hash { - return ref, true - } - } - return "", false -} - -func unshallow(gitDir string) []string { - if _, err := os.Stat(filepath.Join(gitDir, "shallow")); err == nil { - return []string{"--unshallow"} - } - return []string{} -} - -// statOrArchive tries to stat the given rev in the local repository, -// or else it tries to obtain an archive at the rev with the given arguments, -// or else it falls back to aggressive fetching and then a local stat. -// The archive step is an optimization for servers that support it -// (most do not, but maybe that will change), to let us minimize -// the amount of code downloaded. -func (r *repo) statOrArchive(rev string, archiveArgs ...string) (info *codehost.RevInfo, archive []byte, err error) { - // Do we have this rev? - r.refsOnce.Do(r.loadRefs) - var hash string - if k := "refs/tags/" + rev; r.refs[k] != "" { - hash = r.refs[k] - } else if k := "refs/heads/" + rev; r.refs[k] != "" { - hash = r.refs[k] - rev = hash - } else if rev == "HEAD" && r.refs["HEAD"] != "" { - hash = r.refs["HEAD"] - rev = hash - } else if len(rev) >= 5 && len(rev) <= 40 && codehost.AllHex(rev) { - hash = rev - } else { - return nil, nil, fmt.Errorf("unknown revision %q", rev) - } - - out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash) - if err == nil { - hash = strings.TrimSpace(string(out)) - goto Found - } - - // We don't have the rev. Can we fetch it? - if r.local { - return nil, nil, fmt.Errorf("unknown revision %q", rev) - } - - if r.canArchive { - // git archive with --remote requires a ref, not a hash. - // Proceed only if we know a ref for this hash. - if ref, ok := r.findRef(hash); ok { - out, err := codehost.Run(r.dir, "git", "archive", "--format=zip", "--remote="+r.remote, "--prefix=prefix/", ref, archiveArgs) - if err == nil { - return &codehost.RevInfo{Version: rev}, out, nil - } - if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("did not match any files")) { - return nil, nil, fmt.Errorf("file not found") - } - if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("Operation not supported by protocol")) { - r.canArchive = false - } - } - } - - // Maybe it's a prefix of a ref we know. - // Iterating through all the refs is faster than doing unnecessary fetches. - // This is not strictly correct, in that the short ref might be ambiguous - // in the git repo as a whole, but not ambiguous in the list of named refs, - // so that we will resolve it where the git server would not. - // But this check avoids great expense, and preferring a known ref does - // not seem like such a bad failure mode. - if len(hash) >= 5 && len(hash) < 40 { - var full string - for _, h := range r.refs { - if strings.HasPrefix(h, hash) { - if full != "" { - // Prefix is ambiguous even in the ref list! - full = "" - break - } - full = h - } - } - if full != "" { - hash = full - } - } - - // Fetch it. - if len(hash) == 40 { - name := hash - if ref, ok := r.findRef(hash); ok { - name = ref - } - if _, err = codehost.Run(r.dir, "git", "fetch", "--depth=1", r.remote, name); err == nil { - goto Found - } - if !strings.Contains(err.Error(), "unadvertised object") && !strings.Contains(err.Error(), "no such remote ref") && !strings.Contains(err.Error(), "does not support shallow") { - return nil, nil, err - } - } - - // It's a prefix, and we don't have a way to make the server resolve the prefix for us, - // or it's a full hash but also an unadvertised object. - // Download progressively more of the repo to look for it. - - // Fetch the main branch (non-shallow). - if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), r.remote); err != nil { - return nil, nil, err - } - if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil { - hash = strings.TrimSpace(string(out)) - goto Found - } - - // Fetch all tags (non-shallow). - if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", "--tags", r.remote); err != nil { - return nil, nil, err - } - if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil { - hash = strings.TrimSpace(string(out)) - goto Found - } - - // Fetch all branches (non-shallow). - if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", r.remote, "refs/heads/*:refs/heads/*"); err != nil { - return nil, nil, err - } - if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil { - hash = strings.TrimSpace(string(out)) - goto Found - } - - // Fetch all refs (non-shallow). - if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", r.remote, "refs/*:refs/*"); err != nil { - return nil, nil, err - } - if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil { - hash = strings.TrimSpace(string(out)) - goto Found - } - return nil, nil, fmt.Errorf("cannot find hash %s", hash) -Found: - - if strings.HasPrefix(hash, rev) { - rev = hash - } - - out, err = codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%ct", hash) - if err != nil { - return nil, nil, err - } - t, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64) - if err != nil { - return nil, nil, fmt.Errorf("invalid time from git log: %q", out) - } - - info = &codehost.RevInfo{ - Name: hash, - Short: codehost.ShortenSHA1(hash), - Time: time.Unix(t, 0).UTC(), - Version: rev, - } - return info, nil, nil -} - -func (r *repo) Stat(rev string) (*codehost.RevInfo, error) { - // If the server will give us a git archive, we can pull the - // commit ID and the commit time out of the archive. - // We want an archive as small as possible (for speed), - // but we have to specify a pattern that matches at least one file name. - // The pattern here matches README, .gitignore, .gitattributes, - // and go.mod (and some other incidental file names); - // hopefully most repos will have at least one of these. - info, archive, err := r.statOrArchive(rev, "[Rg.][Ego][A.i][Dmt][Miao][Edgt]*") - if err != nil { - return nil, err - } - if archive != nil { - return zip2info(archive, info.Version) - } - return info, nil -} - -func (r *repo) ReadFile(rev, file string, maxSize int64) ([]byte, error) { - info, archive, err := r.statOrArchive(rev, file) - if err != nil { - return nil, err - } - if archive != nil { - return zip2file(archive, file, maxSize) - } - out, err := codehost.Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file) - if err != nil { - return nil, fmt.Errorf("file not found") - } - return out, nil -} - -func (r *repo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) { - // TODO: Use maxSize or drop it. - args := []string{} - if subdir != "" { - args = append(args, "--", subdir) - } - info, archive, err := r.statOrArchive(rev, args...) - if err != nil { - return nil, "", err - } - if archive == nil { - archive, err = codehost.Run(r.dir, "git", "archive", "--format=zip", "--prefix=prefix/", info.Name, args) - if err != nil { - if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("did not match any files")) { - return nil, "", fmt.Errorf("file not found") - } - return nil, "", err - } - } - - return ioutil.NopCloser(bytes.NewReader(archive)), "", nil -} - -func zip2info(archive []byte, rev string) (*codehost.RevInfo, error) { - r, err := zip.NewReader(bytes.NewReader(archive), int64(len(archive))) - if err != nil { - return nil, err - } - if r.Comment == "" { - return nil, fmt.Errorf("missing commit ID in git zip comment") - } - hash := r.Comment - if len(hash) != 40 || !codehost.AllHex(hash) { - return nil, fmt.Errorf("invalid commit ID in git zip comment") - } - if len(r.File) == 0 { - return nil, fmt.Errorf("git zip has no files") - } - info := &codehost.RevInfo{ - Name: hash, - Short: codehost.ShortenSHA1(hash), - Time: r.File[0].Modified.UTC(), - Version: rev, - } - return info, nil -} - -func zip2file(archive []byte, file string, maxSize int64) ([]byte, error) { - r, err := zip.NewReader(bytes.NewReader(archive), int64(len(archive))) - if err != nil { - return nil, err - } - for _, f := range r.File { - if f.Name != "prefix/"+file { - continue - } - rc, err := f.Open() - if err != nil { - return nil, err - } - defer rc.Close() - l := &io.LimitedReader{R: rc, N: maxSize + 1} - data, err := ioutil.ReadAll(l) - if err != nil { - return nil, err - } - if l.N <= 0 { - return nil, fmt.Errorf("file %s too large", file) - } - return data, nil - } - return nil, fmt.Errorf("incomplete git zip archive: cannot find %s", file) -} diff --git a/src/cmd/go/internal/modfetch/googlesource/fetch.go b/src/cmd/go/internal/modfetch/googlesource/fetch.go deleted file mode 100644 index 8317ac3e29..0000000000 --- a/src/cmd/go/internal/modfetch/googlesource/fetch.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package googlesource - -import ( - "fmt" - "strings" - - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/gitrepo" -) - -func Lookup(path string) (codehost.Repo, error) { - i := strings.Index(path, "/") - if i+1 == len(path) || !strings.HasSuffix(path[:i+1], ".googlesource.com/") { - return nil, fmt.Errorf("not *.googlesource.com/*") - } - j := strings.Index(path[i+1:], "/") - if j >= 0 { - path = path[:i+1+j] - } - return gitrepo.Repo("https://"+path, path) -} diff --git a/src/cmd/go/internal/modfetch/gopkgin.go b/src/cmd/go/internal/modfetch/gopkgin.go deleted file mode 100644 index d49b60b3f0..0000000000 --- a/src/cmd/go/internal/modfetch/gopkgin.go +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// TODO: Figure out what gopkg.in should do. - -package modfetch - -import ( - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/gitrepo" - "cmd/go/internal/modfile" - "fmt" -) - -func gopkginLookup(path string) (codehost.Repo, error) { - root, _, _, _, ok := modfile.ParseGopkgIn(path) - if !ok { - return nil, fmt.Errorf("invalid gopkg.in/ path: %q", path) - } - return gitrepo.Repo("https://"+root, root) -} diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go index 419323bb3b..5f856b80d2 100644 --- a/src/cmd/go/internal/modfetch/proxy.go +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -14,19 +14,90 @@ import ( "strings" "time" + "cmd/go/internal/base" "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" "cmd/go/internal/semver" ) +var HelpGoproxy = &base.Command{ + UsageLine: "goproxy", + Short: "module proxy protocol", + Long: ` +The go command by default downloads modules from version control systems +directly, just as 'go get' always has. The GOPROXY environment variable allows +further control over the download source. If GOPROXY is unset, is the empty string, +or is the string "direct", downloads use the default direct connection to version +control systems. Setting GOPROXY to "off" disallows downloading modules from +any source. Otherwise, GOPROXY is expected to be the URL of a module proxy, +in which case the go command will fetch all modules from that proxy. +No matter the source of the modules, downloaded modules must match existing +entries in go.sum (see 'go help modules' for discussion of verification). + +A Go module proxy is any web server that can respond to GET requests for +URLs of a specified form. The requests have no query parameters, so even +a site serving from a fixed file system (including a file:/// URL) +can be a module proxy. + +The GET requests sent to a Go module proxy are: + +GET $GOPROXY//@v/list returns a list of all known versions of the +given module, one per line. + +GET $GOPROXY//@v/.info returns JSON-formatted metadata +about that version of the given module. + +GET $GOPROXY//@v/.mod returns the go.mod file +for that version of the given module. + +GET $GOPROXY//@v/.zip returns the zip archive +for that version of the given module. + +To avoid problems when serving from case-sensitive file systems, +the and elements are case-encoded, replacing every +uppercase letter with an exclamation mark followed by the corresponding +lower-case letter: github.com/Azure encodes as github.com/!azure. + +The JSON-formatted metadata about a given module corresponds to +this Go data structure, which may be expanded in the future: + + type Info struct { + Version string // version string + Time time.Time // commit time + } + +The zip archive for a specific version of a given module is a +standard zip file that contains the file tree corresponding +to the module's source code and related files. The archive uses +slash-separated paths, and every file path in the archive must +begin with @/, where the module and version are +substituted directly, not case-encoded. The root of the module +file tree corresponds to the @/ prefix in the +archive. + +Even when downloading directly from version control systems, +the go command synthesizes explicit info, mod, and zip files +and stores them in its local cache, $GOPATH/pkg/mod/cache/download, +the same as if it had downloaded them directly from a proxy. +The cache layout is the same as the proxy URL space, so +serving $GOPATH/pkg/mod/cache/download at (or copying it to) +https://example.com/proxy would let other users access those +cached module versions with GOPROXY=https://example.com/proxy. +`, +} + var proxyURL = os.Getenv("GOPROXY") func lookupProxy(path string) (Repo, error) { + if strings.Contains(proxyURL, ",") { + return nil, fmt.Errorf("invalid $GOPROXY setting: cannot have comma") + } u, err := url.Parse(proxyURL) if err != nil || u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "file" { // Don't echo $GOPROXY back in case it has user:password in it (sigh). - return nil, fmt.Errorf("invalid $GOPROXY setting") + return nil, fmt.Errorf("invalid $GOPROXY setting: malformed URL or invalid scheme (must be http, https, file)") } - return newProxyRepo(u.String(), path), nil + return newProxyRepo(u.String(), path) } type proxyRepo struct { @@ -34,8 +105,12 @@ type proxyRepo struct { path string } -func newProxyRepo(baseURL, path string) Repo { - return &proxyRepo{strings.TrimSuffix(baseURL, "/") + "/" + pathEscape(path), path} +func newProxyRepo(baseURL, path string) (Repo, error) { + enc, err := module.EncodePath(path) + if err != nil { + return nil, err + } + return &proxyRepo{strings.TrimSuffix(baseURL, "/") + "/" + pathEscape(enc), path}, nil } func (p *proxyRepo) ModulePath() string { @@ -55,6 +130,7 @@ func (p *proxyRepo) Versions(prefix string) ([]string, error) { list = append(list, f[0]) } } + SortVersions(list) return list, nil } @@ -90,7 +166,11 @@ func (p *proxyRepo) latest() (*RevInfo, error) { func (p *proxyRepo) Stat(rev string) (*RevInfo, error) { var data []byte - err := webGetBytes(p.url+"/@v/"+pathEscape(rev)+".info", &data) + encRev, err := module.EncodeVersion(rev) + if err != nil { + return nil, err + } + err = webGetBytes(p.url+"/@v/"+pathEscape(encRev)+".info", &data) if err != nil { return nil, err } @@ -118,7 +198,11 @@ func (p *proxyRepo) Latest() (*RevInfo, error) { func (p *proxyRepo) GoMod(version string) ([]byte, error) { var data []byte - err := webGetBytes(p.url+"/@v/"+pathEscape(version)+".mod", &data) + encVer, err := module.EncodeVersion(version) + if err != nil { + return nil, err + } + err = webGetBytes(p.url+"/@v/"+pathEscape(encVer)+".mod", &data) if err != nil { return nil, err } @@ -127,14 +211,18 @@ func (p *proxyRepo) GoMod(version string) ([]byte, error) { func (p *proxyRepo) Zip(version string, tmpdir string) (tmpfile string, err error) { var body io.ReadCloser - err = webGetBody(p.url+"/@v/"+pathEscape(version)+".zip", &body) + encVer, err := module.EncodeVersion(version) + if err != nil { + return "", err + } + err = webGetBody(p.url+"/@v/"+pathEscape(encVer)+".zip", &body) if err != nil { return "", err } defer body.Close() // Spool to local file. - f, err := ioutil.TempFile(tmpdir, "vgo-proxy-download-") + f, err := ioutil.TempFile(tmpdir, "go-proxy-download-") if err != nil { return "", err } diff --git a/src/cmd/go/internal/modfetch/pseudo.go b/src/cmd/go/internal/modfetch/pseudo.go new file mode 100644 index 0000000000..32c7bf883b --- /dev/null +++ b/src/cmd/go/internal/modfetch/pseudo.go @@ -0,0 +1,129 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Pseudo-versions +// +// Code authors are expected to tag the revisions they want users to use, +// including prereleases. However, not all authors tag versions at all, +// and not all commits a user might want to try will have tags. +// A pseudo-version is a version with a special form that allows us to +// address an untagged commit and order that version with respect to +// other versions we might encounter. +// +// A pseudo-version takes one of the general forms: +// +// (1) vX.0.0-yyyymmddhhmmss-abcdef123456 +// (2) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456 +// (3) vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdef123456+incompatible +// (4) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456 +// (5) vX.Y.Z-pre.0.yyyymmddhhmmss-abcdef123456+incompatible +// +// If there is no recently tagged version with the right major version vX, +// then form (1) is used, creating a space of pseudo-versions at the bottom +// of the vX version range, less than any tagged version, including the unlikely v0.0.0. +// +// If the most recent tagged version before the target commit is vX.Y.Z or vX.Y.Z+incompatible, +// then the pseudo-version uses form (2) or (3), making it a prerelease for the next +// possible semantic version after vX.Y.Z. The leading 0 segment in the prerelease string +// ensures that the pseudo-version compares less than possible future explicit prereleases +// like vX.Y.(Z+1)-rc1 or vX.Y.(Z+1)-1. +// +// If the most recent tagged version before the target commit is vX.Y.Z-pre or vX.Y.Z-pre+incompatible, +// then the pseudo-version uses form (4) or (5), making it a slightly later prerelease. + +package modfetch + +import ( + "cmd/go/internal/semver" + "fmt" + "regexp" + "strings" + "time" +) + +// PseudoVersion returns a pseudo-version for the given major version ("v1") +// preexisting older tagged version ("" or "v1.2.3" or "v1.2.3-pre"), revision time, +// and revision identifier (usually a 12-byte commit hash prefix). +func PseudoVersion(major, older string, t time.Time, rev string) string { + if major == "" { + major = "v0" + } + major = strings.TrimSuffix(major, "-unstable") // make gopkg.in/macaroon-bakery.v2-unstable use "v2" + segment := fmt.Sprintf("%s-%s", t.UTC().Format("20060102150405"), rev) + build := semver.Build(older) + older = semver.Canonical(older) + if older == "" { + return major + ".0.0-" + segment // form (1) + } + if semver.Prerelease(older) != "" { + return older + ".0." + segment + build // form (4), (5) + } + + // Form (2), (3). + // Extract patch from vMAJOR.MINOR.PATCH + v := older[:len(older)] + i := strings.LastIndex(v, ".") + 1 + v, patch := v[:i], v[i:] + + // Increment PATCH by adding 1 to decimal: + // scan right to left turning 9s to 0s until you find a digit to increment. + // (Number might exceed int64, but math/big is overkill.) + digits := []byte(patch) + for i = len(digits) - 1; i >= 0 && digits[i] == '9'; i-- { + digits[i] = '0' + } + if i >= 0 { + digits[i]++ + } else { + // digits is all zeros + digits[0] = '1' + digits = append(digits, '0') + } + patch = string(digits) + + // Reassemble. + return v + patch + "-0." + segment + build +} + +var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.(0\.0-|\d+\.\d+-([^+]*\.)?0\.)\d{14}-[A-Za-z0-9]+(\+incompatible)?$`) + +// IsPseudoVersion reports whether v is a pseudo-version. +func IsPseudoVersion(v string) bool { + return strings.Count(v, "-") >= 2 && semver.IsValid(v) && pseudoVersionRE.MatchString(v) +} + +// PseudoVersionTime returns the time stamp of the pseudo-version v. +// It returns an error if v is not a pseudo-version or if the time stamp +// embedded in the pseudo-version is not a valid time. +func PseudoVersionTime(v string) (time.Time, error) { + timestamp, _, err := parsePseudoVersion(v) + t, err := time.Parse("20060102150405", timestamp) + if err != nil { + return time.Time{}, fmt.Errorf("pseudo-version with malformed time %s: %q", timestamp, v) + } + return t, nil +} + +// PseudoVersionRev returns the revision identifier of the pseudo-version v. +// It returns an error if v is not a pseudo-version. +func PseudoVersionRev(v string) (rev string, err error) { + _, rev, err = parsePseudoVersion(v) + return +} + +func parsePseudoVersion(v string) (timestamp, rev string, err error) { + if !IsPseudoVersion(v) { + return "", "", fmt.Errorf("malformed pseudo-version %q", v) + } + v = strings.TrimSuffix(v, "+incompatible") + j := strings.LastIndex(v, "-") + v, rev = v[:j], v[j+1:] + i := strings.LastIndex(v, "-") + if j := strings.LastIndex(v, "."); j > i { + timestamp = v[j+1:] + } else { + timestamp = v[i+1:] + } + return timestamp, rev, nil +} diff --git a/src/cmd/go/internal/modfetch/pseudo_test.go b/src/cmd/go/internal/modfetch/pseudo_test.go new file mode 100644 index 0000000000..3c2fa51468 --- /dev/null +++ b/src/cmd/go/internal/modfetch/pseudo_test.go @@ -0,0 +1,74 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modfetch + +import ( + "testing" + "time" +) + +var pseudoTests = []struct { + major string + older string + version string +}{ + {"", "", "v0.0.0-20060102150405-hash"}, + {"v0", "", "v0.0.0-20060102150405-hash"}, + {"v1", "", "v1.0.0-20060102150405-hash"}, + {"v2", "", "v2.0.0-20060102150405-hash"}, + {"unused", "v0.0.0", "v0.0.1-0.20060102150405-hash"}, + {"unused", "v1.2.3", "v1.2.4-0.20060102150405-hash"}, + {"unused", "v1.2.99999999999999999", "v1.2.100000000000000000-0.20060102150405-hash"}, + {"unused", "v1.2.3-pre", "v1.2.3-pre.0.20060102150405-hash"}, + {"unused", "v1.3.0-pre", "v1.3.0-pre.0.20060102150405-hash"}, +} + +var pseudoTime = time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC) + +func TestPseudoVersion(t *testing.T) { + for _, tt := range pseudoTests { + v := PseudoVersion(tt.major, tt.older, pseudoTime, "hash") + if v != tt.version { + t.Errorf("PseudoVersion(%q, %q, ...) = %v, want %v", tt.major, tt.older, v, tt.version) + } + } +} + +func TestIsPseudoVersion(t *testing.T) { + for _, tt := range pseudoTests { + if !IsPseudoVersion(tt.version) { + t.Errorf("IsPseudoVersion(%q) = false, want true", tt.version) + } + if IsPseudoVersion(tt.older) { + t.Errorf("IsPseudoVersion(%q) = true, want false", tt.older) + } + } +} + +func TestPseudoVersionTime(t *testing.T) { + for _, tt := range pseudoTests { + tm, err := PseudoVersionTime(tt.version) + if tm != pseudoTime || err != nil { + t.Errorf("PseudoVersionTime(%q) = %v, %v, want %v, nil", tt.version, tm.Format(time.RFC3339), err, pseudoTime.Format(time.RFC3339)) + } + tm, err = PseudoVersionTime(tt.older) + if tm != (time.Time{}) || err == nil { + t.Errorf("PseudoVersionTime(%q) = %v, %v, want %v, error", tt.older, tm.Format(time.RFC3339), err, time.Time{}.Format(time.RFC3339)) + } + } +} + +func TestPseudoVersionRev(t *testing.T) { + for _, tt := range pseudoTests { + rev, err := PseudoVersionRev(tt.version) + if rev != "hash" || err != nil { + t.Errorf("PseudoVersionRev(%q) = %q, %v, want %q, nil", tt.older, rev, err, "hash") + } + rev, err = PseudoVersionRev(tt.older) + if rev != "" || err == nil { + t.Errorf("PseudoVersionRev(%q) = %q, %v, want %q, error", tt.older, rev, err, "") + } + } +} diff --git a/src/cmd/go/internal/modfetch/query.go b/src/cmd/go/internal/modfetch/query.go deleted file mode 100644 index 5e9d86c411..0000000000 --- a/src/cmd/go/internal/modfetch/query.go +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package modfetch - -import ( - "cmd/go/internal/module" - "cmd/go/internal/semver" - "fmt" - "strings" -) - -// Query looks up a revision of a given module given a version query string. -// The module must be a complete module path. -// The version must take one of the following forms: -// -// - the literal string "latest", denoting the latest available tagged version -// - v1.2.3, a semantic version string -// - v1 or v1.2, an abbreviated semantic version string completed by adding zeroes (v1.0.0 or v1.2.0); -// - >v1.2.3, denoting the earliest available version after v1.2.3 -// - ") || strings.HasPrefix(vers, "<") || vers == "latest" { - var op string - if vers != "latest" { - if !semver.IsValid(vers[1:]) { - return nil, fmt.Errorf("invalid semantic version in range %s", vers) - } - op, vers = vers[:1], vers[1:] - } - versions, err := repo.Versions("") - if err != nil { - return nil, err - } - if len(versions) == 0 && vers == "latest" { - return repo.Latest() - } - if vers == "latest" { - for i := len(versions) - 1; i >= 0; i-- { - if allowed == nil || allowed(module.Version{Path: path, Version: versions[i]}) { - return repo.Stat(versions[i]) - } - } - } else if op == "<" { - for i := len(versions) - 1; i >= 0; i-- { - if semver.Compare(versions[i], vers) < 0 && (allowed == nil || allowed(module.Version{Path: path, Version: versions[i]})) { - return repo.Stat(versions[i]) - } - } - } else { - for i := 0; i < len(versions); i++ { - if semver.Compare(versions[i], vers) > 0 && (allowed == nil || allowed(module.Version{Path: path, Version: versions[i]})) { - return repo.Stat(versions[i]) - } - } - } - return nil, fmt.Errorf("no matching versions for %s%s", op, vers) - } - // TODO: Time queries, maybe. - - return repo.Stat(vers) -} diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go index 6e21a41777..0ea8c1f0e3 100644 --- a/src/cmd/go/internal/modfetch/repo.go +++ b/src/cmd/go/internal/modfetch/repo.go @@ -5,21 +5,23 @@ package modfetch import ( - "errors" - pathpkg "path" + "fmt" + "os" "sort" - "strings" "time" - "cmd/go/internal/modfetch/bitbucket" + "cmd/go/internal/cfg" + "cmd/go/internal/get" "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfetch/github" - "cmd/go/internal/modfetch/googlesource" - "cmd/go/internal/module" + "cmd/go/internal/par" "cmd/go/internal/semver" + web "cmd/go/internal/web" ) +const traceRepo = false // trace all repo actions, for debugging + // A Repo represents a repository storing all versions of a single module. +// It must be safe for simultaneous use by multiple goroutines. type Repo interface { // ModulePath returns the module path. ModulePath() string @@ -53,77 +55,245 @@ type Repo interface { // A Rev describes a single revision in a module repository. type RevInfo struct { Version string // version string - Name string // complete ID in underlying repository - Short string // shortened ID, for use in pseudo-version Time time.Time // commit time + + // These fields are used for Stat of arbitrary rev, + // but they are not recorded when talking about module versions. + Name string `json:"-"` // complete ID in underlying repository + Short string `json:"-"` // shortened ID, for use in pseudo-version } +// Re: module paths, import paths, repository roots, and lookups +// +// A module is a collection of Go packages stored in a file tree +// with a go.mod file at the root of the tree. +// The go.mod defines the module path, which is the import path +// corresponding to the root of the file tree. +// The import path of a directory within that file tree is the module path +// joined with the name of the subdirectory relative to the root. +// +// For example, the module with path rsc.io/qr corresponds to the +// file tree in the repository https://github.com/rsc/qr. +// That file tree has a go.mod that says "module rsc.io/qr". +// The package in the root directory has import path "rsc.io/qr". +// The package in the gf256 subdirectory has import path "rsc.io/qr/gf256". +// In this example, "rsc.io/qr" is both a module path and an import path. +// But "rsc.io/qr/gf256" is only an import path, not a module path: +// it names an importable package, but not a module. +// +// As a special case to incorporate code written before modules were +// introduced, if a path p resolves using the pre-module "go get" lookup +// to the root of a source code repository without a go.mod file, +// that repository is treated as if it had a go.mod in its root directory +// declaring module path p. (The go.mod is further considered to +// contain requirements corresponding to any legacy version +// tracking format such as Gopkg.lock, vendor/vendor.conf, and so on.) +// +// The presentation so far ignores the fact that a source code repository +// has many different versions of a file tree, and those versions may +// differ in whether a particular go.mod exists and what it contains. +// In fact there is a well-defined mapping only from a module path, version +// pair - often written path@version - to a particular file tree. +// For example rsc.io/qr@v0.1.0 depends on the "implicit go.mod at root of +// repository" rule, while rsc.io/qr@v0.2.0 has an explicit go.mod. +// Because the "go get" import paths rsc.io/qr and github.com/rsc/qr +// both redirect to the Git repository https://github.com/rsc/qr, +// github.com/rsc/qr@v0.1.0 is the same file tree as rsc.io/qr@v0.1.0 +// but a different module (a different name). In contrast, since v0.2.0 +// of that repository has an explicit go.mod that declares path rsc.io/qr, +// github.com/rsc/qr@v0.2.0 is an invalid module path, version pair. +// Before modules, import comments would have had the same effect. +// +// The set of import paths associated with a given module path is +// clearly not fixed: at the least, new directories with new import paths +// can always be added. But another potential operation is to split a +// subtree out of a module into its own module. If done carefully, +// this operation can be done while preserving compatibility for clients. +// For example, suppose that we want to split rsc.io/qr/gf256 into its +// own module, so that there would be two modules rsc.io/qr and rsc.io/qr/gf256. +// Then we can simultaneously issue rsc.io/qr v0.3.0 (dropping the gf256 subdirectory) +// and rsc.io/qr/gf256 v0.1.0, including in their respective go.mod +// cyclic requirements pointing at each other: rsc.io/qr v0.3.0 requires +// rsc.io/qr/gf256 v0.1.0 and vice versa. Then a build can be +// using an older rsc.io/qr module that includes the gf256 package, but if +// it adds a requirement on either the newer rsc.io/qr or the newer +// rsc.io/qr/gf256 module, it will automatically add the requirement +// on the complementary half, ensuring both that rsc.io/qr/gf256 is +// available for importing by the build and also that it is only defined +// by a single module. The gf256 package could move back into the +// original by another simultaneous release of rsc.io/qr v0.4.0 including +// the gf256 subdirectory and an rsc.io/qr/gf256 v0.2.0 with no code +// in its root directory, along with a new requirement cycle. +// The ability to shift module boundaries in this way is expected to be +// important in large-scale program refactorings, similar to the ones +// described in https://talks.golang.org/2016/refactor.article. +// +// The possibility of shifting module boundaries reemphasizes +// that you must know both the module path and its version +// to determine the set of packages provided directly by that module. +// +// On top of all this, it is possible for a single code repository +// to contain multiple modules, either in branches or subdirectories, +// as a limited kind of monorepo. For example rsc.io/qr/v2, +// the v2.x.x continuation of rsc.io/qr, is expected to be found +// in v2-tagged commits in https://github.com/rsc/qr, either +// in the root or in a v2 subdirectory, disambiguated by go.mod. +// Again the precise file tree corresponding to a module +// depends on which version we are considering. +// +// It is also possible for the underlying repository to change over time, +// without changing the module path. If I copy the github repo over +// to https://bitbucket.org/rsc/qr and update https://rsc.io/qr?go-get=1, +// then clients of all versions should start fetching from bitbucket +// instead of github. That is, in contrast to the exact file tree, +// the location of the source code repository associated with a module path +// does not depend on the module version. (This is by design, as the whole +// point of these redirects is to allow package authors to establish a stable +// name that can be updated as code moves from one service to another.) +// +// All of this is important background for the lookup APIs defined in this +// file. +// +// The Lookup function takes a module path and returns a Repo representing +// that module path. Lookup can do only a little with the path alone. +// It can check that the path is well-formed (see semver.CheckPath) +// and it can check that the path can be resolved to a target repository. +// To avoid version control access except when absolutely necessary, +// Lookup does not attempt to connect to the repository itself. +// +// The Import function takes an import path found in source code and +// determines which module to add to the requirement list to satisfy +// that import. It checks successive truncations of the import path +// to determine possible modules and stops when it finds a module +// in which the latest version satisfies the import path. +// +// The ImportRepoRev function is a variant of Import which is limited +// to code in a source code repository at a particular revision identifier +// (usually a commit hash or source code repository tag, not necessarily +// a module version). +// ImportRepoRev is used when converting legacy dependency requirements +// from older systems into go.mod files. Those older systems worked +// at either package or repository granularity, and most of the time they +// recorded commit hashes, not tagged versions. + +var lookupCache par.Cache + // Lookup returns the module with the given module path. +// A successful return does not guarantee that the module +// has any defined versions. func Lookup(path string) (Repo, error) { - if proxyURL != "" { + if traceRepo { + defer logCall("Lookup(%q)", path)() + } + + type cached struct { + r Repo + err error + } + c := lookupCache.Do(path, func() interface{} { + r, err := lookup(path) + if err == nil { + if traceRepo { + r = newLoggingRepo(r) + } + r = newCachingRepo(r) + } + return cached{r, err} + }).(cached) + + return c.r, c.err +} + +// lookup returns the module with the given module path. +func lookup(path string) (r Repo, err error) { + if cfg.BuildMod == "vendor" { + return nil, fmt.Errorf("module lookup disabled by -mod=%s", cfg.BuildMod) + } + if proxyURL == "off" { + return nil, fmt.Errorf("module lookup disabled by GOPROXY=%s", proxyURL) + } + if proxyURL != "" && proxyURL != "direct" { return lookupProxy(path) } - if code, err := lookupCodeHost(path, false); err != errNotHosted { - if err != nil { + + security := web.Secure + if get.Insecure { + security = web.Insecure + } + rr, err := get.RepoRootForImportPath(path, get.PreferMod, security) + if err != nil { + // We don't know where to find code for a module with this path. + return nil, err + } + + if rr.VCS == "mod" { + // Fetch module from proxy with base URL rr.Repo. + return newProxyRepo(rr.Repo, path) + } + + code, err := lookupCodeRepo(rr) + if err != nil { + return nil, err + } + return newCodeRepo(code, rr.Root, path) +} + +func lookupCodeRepo(rr *get.RepoRoot) (codehost.Repo, error) { + code, err := codehost.NewRepo(rr.VCS, rr.Repo) + if err != nil { + if _, ok := err.(*codehost.VCSError); ok { return nil, err } - return newCodeRepo(code, path) + return nil, fmt.Errorf("lookup %s: %v", rr.Root, err) } - return lookupCustomDomain(path) + return code, nil } -func Import(path string, allowed func(module.Version) bool) (Repo, *RevInfo, error) { - try := func(path string) (Repo, *RevInfo, error) { - r, err := Lookup(path) - if err != nil { - return nil, nil, err - } - info, err := Query(path, "latest", allowed) - if err != nil { - return nil, nil, err - } - _, err = r.GoMod(info.Version) - if err != nil { - return nil, nil, err - } - return r, info, nil +// ImportRepoRev returns the module and version to use to access +// the given import path loaded from the source code repository that +// the original "go get" would have used, at the specific repository revision +// (typically a commit hash, but possibly also a source control tag). +func ImportRepoRev(path, rev string) (Repo, *RevInfo, error) { + if cfg.BuildMod == "vendor" || cfg.BuildMod == "readonly" { + return nil, nil, fmt.Errorf("repo version lookup disabled by -mod=%s", cfg.BuildMod) } - var firstErr error - for { - r, info, err := try(path) - if err == nil { - return r, info, nil - } - if firstErr == nil { - firstErr = err - } - p := pathpkg.Dir(path) - if p == "." { - break - } - path = p + // Note: Because we are converting a code reference from a legacy + // version control system, we ignore meta tags about modules + // and use only direct source control entries (get.IgnoreMod). + security := web.Secure + if get.Insecure { + security = web.Insecure } - return nil, nil, firstErr -} - -var errNotHosted = errors.New("not hosted") - -var isTest bool - -func lookupCodeHost(path string, customDomain bool) (codehost.Repo, error) { - switch { - case strings.HasPrefix(path, "github.com/"): - return github.Lookup(path) - case strings.HasPrefix(path, "bitbucket.org/"): - return bitbucket.Lookup(path) - case customDomain && strings.HasSuffix(path[:strings.Index(path, "/")+1], ".googlesource.com/") || - isTest && strings.HasPrefix(path, "go.googlesource.com/scratch"): - return googlesource.Lookup(path) - case strings.HasPrefix(path, "gopkg.in/"): - return gopkginLookup(path) + rr, err := get.RepoRootForImportPath(path, get.IgnoreMod, security) + if err != nil { + return nil, nil, err } - return nil, errNotHosted + + code, err := lookupCodeRepo(rr) + if err != nil { + return nil, nil, err + } + + revInfo, err := code.Stat(rev) + if err != nil { + return nil, nil, err + } + + // TODO: Look in repo to find path, check for go.mod files. + // For now we're just assuming rr.Root is the module path, + // which is true in the absence of go.mod files. + + repo, err := newCodeRepo(code, rr.Root, rr.Root) + if err != nil { + return nil, nil, err + } + + info, err := repo.(*codeRepo).convert(revInfo, "") + if err != nil { + return nil, nil, err + } + return repo, info, nil } func SortVersions(list []string) { @@ -135,3 +305,59 @@ func SortVersions(list []string) { return list[i] < list[j] }) } + +// A loggingRepo is a wrapper around an underlying Repo +// that prints a log message at the start and end of each call. +// It can be inserted when debugging. +type loggingRepo struct { + r Repo +} + +func newLoggingRepo(r Repo) *loggingRepo { + return &loggingRepo{r} +} + +// logCall prints a log message using format and args and then +// also returns a function that will print the same message again, +// along with the elapsed time. +// Typical usage is: +// +// defer logCall("hello %s", arg)() +// +// Note the final (). +func logCall(format string, args ...interface{}) func() { + start := time.Now() + fmt.Fprintf(os.Stderr, "+++ %s\n", fmt.Sprintf(format, args...)) + return func() { + fmt.Fprintf(os.Stderr, "%.3fs %s\n", time.Since(start).Seconds(), fmt.Sprintf(format, args...)) + } +} + +func (l *loggingRepo) ModulePath() string { + return l.r.ModulePath() +} + +func (l *loggingRepo) Versions(prefix string) (tags []string, err error) { + defer logCall("Repo[%s]: Versions(%q)", l.r.ModulePath(), prefix)() + return l.r.Versions(prefix) +} + +func (l *loggingRepo) Stat(rev string) (*RevInfo, error) { + defer logCall("Repo[%s]: Stat(%q)", l.r.ModulePath(), rev)() + return l.r.Stat(rev) +} + +func (l *loggingRepo) Latest() (*RevInfo, error) { + defer logCall("Repo[%s]: Latest()", l.r.ModulePath())() + return l.r.Latest() +} + +func (l *loggingRepo) GoMod(version string) ([]byte, error) { + defer logCall("Repo[%s]: GoMod(%q)", l.r.ModulePath(), version)() + return l.r.GoMod(version) +} + +func (l *loggingRepo) Zip(version, tmpdir string) (string, error) { + defer logCall("Repo[%s]: Zip(%q, %q)", l.r.ModulePath(), version, tmpdir)() + return l.r.Zip(version, tmpdir) +} diff --git a/src/cmd/go/internal/modfetch/unzip.go b/src/cmd/go/internal/modfetch/unzip.go index 9d9e29889e..a50431fd86 100644 --- a/src/cmd/go/internal/modfetch/unzip.go +++ b/src/cmd/go/internal/modfetch/unzip.go @@ -10,10 +10,14 @@ import ( "io" "io/ioutil" "os" + "path" "path/filepath" + "sort" "strings" "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" + "cmd/go/internal/str" ) func Unzip(dir, zipfile, prefix string, maxSize int64) error { @@ -46,15 +50,46 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error { return fmt.Errorf("unzip %v: %s", zipfile, err) } - // Check total size. + foldPath := make(map[string]string) + var checkFold func(string) error + checkFold = func(name string) error { + fold := str.ToFold(name) + if foldPath[fold] == name { + return nil + } + dir := path.Dir(name) + if dir != "." { + if err := checkFold(dir); err != nil { + return err + } + } + if foldPath[fold] == "" { + foldPath[fold] = name + return nil + } + other := foldPath[fold] + return fmt.Errorf("unzip %v: case-insensitive file name collision: %q and %q", zipfile, other, name) + } + + // Check total size, valid file names. var size int64 for _, zf := range z.File { - if !strings.HasPrefix(zf.Name, prefix) { + if !str.HasPathPrefix(zf.Name, prefix) { return fmt.Errorf("unzip %v: unexpected file name %s", zipfile, zf.Name) } - if strings.HasSuffix(zf.Name, "/") { + if zf.Name == prefix || strings.HasSuffix(zf.Name, "/") { continue } + name := zf.Name[len(prefix)+1:] + if err := module.CheckFilePath(name); err != nil { + return fmt.Errorf("unzip %v: %v", zipfile, err) + } + if err := checkFold(name); err != nil { + return err + } + if path.Clean(zf.Name) != zf.Name || strings.HasPrefix(zf.Name[len(prefix)+1:], "/") { + return fmt.Errorf("unzip %v: invalid file name %s", zipfile, zf.Name) + } s := int64(zf.UncompressedSize64) if s < 0 || maxSize-size < s { return fmt.Errorf("unzip %v: content too large", zipfile) @@ -63,11 +98,18 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error { } // Unzip, enforcing sizes checked earlier. + dirs := map[string]bool{dir: true} for _, zf := range z.File { - if strings.HasSuffix(zf.Name, "/") { + if zf.Name == prefix || strings.HasSuffix(zf.Name, "/") { continue } - dst := filepath.Join(dir, zf.Name[len(prefix):]) + name := zf.Name[len(prefix):] + dst := filepath.Join(dir, name) + parent := filepath.Dir(dst) + for parent != dir { + dirs[parent] = true + parent = filepath.Dir(parent) + } if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil { return err } @@ -77,7 +119,6 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error { } r, err := zf.Open() if err != nil { - r.Close() w.Close() return fmt.Errorf("unzip %v: %v", zipfile, err) } @@ -96,5 +137,17 @@ func Unzip(dir, zipfile, prefix string, maxSize int64) error { } } + // Mark directories unwritable, best effort. + var dirlist []string + for dir := range dirs { + dirlist = append(dirlist, dir) + } + sort.Strings(dirlist) + + // Run over list backward to chmod children before parents. + for i := len(dirlist) - 1; i >= 0; i-- { + os.Chmod(dirlist[i], 0555) + } + return nil } diff --git a/src/cmd/go/internal/modfile/read.go b/src/cmd/go/internal/modfile/read.go index a0c88d6ca9..1d81ff1ab7 100644 --- a/src/cmd/go/internal/modfile/read.go +++ b/src/cmd/go/internal/modfile/read.go @@ -11,6 +11,7 @@ import ( "bytes" "fmt" "os" + "strconv" "strings" "unicode" "unicode/utf8" @@ -88,6 +89,131 @@ func (x *FileSyntax) Span() (start, end Position) { return start, end } +func (x *FileSyntax) addLine(hint Expr, tokens ...string) *Line { + if hint == nil { + // If no hint given, add to the last statement of the given type. + Loop: + for i := len(x.Stmt) - 1; i >= 0; i-- { + stmt := x.Stmt[i] + switch stmt := stmt.(type) { + case *Line: + if stmt.Token != nil && stmt.Token[0] == tokens[0] { + hint = stmt + break Loop + } + case *LineBlock: + if stmt.Token[0] == tokens[0] { + hint = stmt + break Loop + } + } + } + } + + if hint != nil { + for i, stmt := range x.Stmt { + switch stmt := stmt.(type) { + case *Line: + if stmt == hint { + // Convert line to line block. + stmt.InBlock = true + block := &LineBlock{Token: stmt.Token[:1], Line: []*Line{stmt}} + stmt.Token = stmt.Token[1:] + x.Stmt[i] = block + new := &Line{Token: tokens[1:], InBlock: true} + block.Line = append(block.Line, new) + return new + } + case *LineBlock: + if stmt == hint { + new := &Line{Token: tokens[1:], InBlock: true} + stmt.Line = append(stmt.Line, new) + return new + } + for j, line := range stmt.Line { + if line == hint { + // Add new line after hint. + stmt.Line = append(stmt.Line, nil) + copy(stmt.Line[j+2:], stmt.Line[j+1:]) + new := &Line{Token: tokens[1:], InBlock: true} + stmt.Line[j+1] = new + return new + } + } + } + } + } + + new := &Line{Token: tokens} + x.Stmt = append(x.Stmt, new) + return new +} + +func (x *FileSyntax) updateLine(line *Line, tokens ...string) { + if line.InBlock { + tokens = tokens[1:] + } + line.Token = tokens +} + +func (x *FileSyntax) removeLine(line *Line) { + line.Token = nil +} + +// Cleanup cleans up the file syntax x after any edit operations. +// To avoid quadratic behavior, removeLine marks the line as dead +// by setting line.Token = nil but does not remove it from the slice +// in which it appears. After edits have all been indicated, +// calling Cleanup cleans out the dead lines. +func (x *FileSyntax) Cleanup() { + w := 0 + for _, stmt := range x.Stmt { + switch stmt := stmt.(type) { + case *Line: + if stmt.Token == nil { + continue + } + case *LineBlock: + ww := 0 + for _, line := range stmt.Line { + if line.Token != nil { + stmt.Line[ww] = line + ww++ + } + } + if ww == 0 { + continue + } + if ww == 1 { + // Collapse block into single line. + line := &Line{ + Comments: Comments{ + Before: commentsAdd(stmt.Before, stmt.Line[0].Before), + Suffix: commentsAdd(stmt.Line[0].Suffix, stmt.Suffix), + After: commentsAdd(stmt.Line[0].After, stmt.After), + }, + Token: stringsAdd(stmt.Token, stmt.Line[0].Token), + } + x.Stmt[w] = line + w++ + continue + } + stmt.Line = stmt.Line[:ww] + } + x.Stmt[w] = stmt + w++ + } + x.Stmt = x.Stmt[:w] +} + +func commentsAdd(x, y []Comment) []Comment { + return append(x[:len(x):len(x)], y...) +} + +func stringsAdd(x, y []string) []string { + return append(x[:len(x):len(x)], y...) +} + // A CommentBlock represents a top-level block of comments separate // from any rule. type CommentBlock struct { @@ -102,9 +228,10 @@ func (x *CommentBlock) Span() (start, end Position) { // A Line is a single line of tokens. type Line struct { Comments - Start Position - Token []string - End Position + Start Position + Token []string + InBlock bool + End Position } func (x *Line) Span() (start, end Position) { @@ -679,9 +806,10 @@ func (in *input) parseLine(sym *symType) *Line { switch tok { case '\n', _EOF, _EOL: return &Line{ - Start: start, - Token: token, - End: end, + Start: start, + Token: token, + End: end, + InBlock: true, } default: token = append(token, sym.text) @@ -697,3 +825,45 @@ const ( _STRING _COMMENT ) + +var ( + slashSlash = []byte("//") + moduleStr = []byte("module") +) + +// ModulePath returns the module path from the gomod file text. +// If it cannot find a module path, it returns an empty string. +// It is tolerant of unrelated problems in the go.mod file. +func ModulePath(mod []byte) string { + for len(mod) > 0 { + line := mod + mod = nil + if i := bytes.IndexByte(line, '\n'); i >= 0 { + line, mod = line[:i], line[i+1:] + } + if i := bytes.Index(line, slashSlash); i >= 0 { + line = line[:i] + } + line = bytes.TrimSpace(line) + if !bytes.HasPrefix(line, moduleStr) { + continue + } + line = line[len(moduleStr):] + n := len(line) + line = bytes.TrimSpace(line) + if len(line) == n || len(line) == 0 { + continue + } + + if line[0] == '"' || line[0] == '`' { + p, err := strconv.Unquote(string(line)) + if err != nil { + return "" // malformed quoted string or multiline module path + } + return p + } + + return string(line) + } + return "" // missing module path +} diff --git a/src/cmd/go/internal/modfile/read_test.go b/src/cmd/go/internal/modfile/read_test.go index 2c617b82ae..8cb1a3908c 100644 --- a/src/cmd/go/internal/modfile/read_test.go +++ b/src/cmd/go/internal/modfile/read_test.go @@ -66,6 +66,21 @@ func testPrint(t *testing.T, in, out string) { } } +func TestParseLax(t *testing.T) { + badFile := []byte(`module m + surprise attack + x y ( + z + ) + exclude v1.2.3 + replace <-!!! + `) + _, err := ParseLax("file", badFile, nil) + if err != nil { + t.Fatalf("ParseLax did not ignore irrelevant errors: %v", err) + } +} + // Test that when files in the testdata directory are parsed // and printed and parsed again, we get the same parse tree // both times. @@ -304,3 +319,47 @@ func tdiff(t *testing.T, a, b string) { } t.Error(string(data)) } + +var modulePathTests = []struct { + input []byte + expected string +}{ + {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"}, + {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"}, + {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"}, + {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"}, + {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"}, + {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"}, + {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"}, + {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"}, + {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"}, + {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""}, + {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"}, + {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""}, + {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""}, + {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""}, + {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""}, + {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""}, + {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""}, + {input: []byte("module \nmodule a/b/c "), expected: "a/b/c"}, + {input: []byte("module \" \""), expected: " "}, + {input: []byte("module "), expected: ""}, + {input: []byte("module \" a/b/c \""), expected: " a/b/c "}, + {input: []byte("module \"github.com/rsc/vgotest1\" // with a comment"), expected: "github.com/rsc/vgotest1"}, +} + +func TestModulePath(t *testing.T) { + for _, test := range modulePathTests { + t.Run(string(test.input), func(t *testing.T) { + result := ModulePath(test.input) + if result != test.expected { + t.Fatalf("ModulePath(%q): %s, want %s", string(test.input), result, test.expected) + } + }) + } +} diff --git a/src/cmd/go/internal/modfile/rule.go b/src/cmd/go/internal/modfile/rule.go index 5a784a3a33..e11f0a6e31 100644 --- a/src/cmd/go/internal/modfile/rule.go +++ b/src/cmd/go/internal/modfile/rule.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "path/filepath" + "regexp" "sort" "strconv" "strings" @@ -18,8 +19,10 @@ import ( "cmd/go/internal/semver" ) +// A File is the parsed, interpreted form of a go.mod file. type File struct { Module *Module + Go *Go Require []*Require Exclude []*Exclude Replace []*Replace @@ -27,38 +30,52 @@ type File struct { Syntax *FileSyntax } +// A Module is the module statement. type Module struct { - Mod module.Version - Major string -} - -type Require struct { Mod module.Version Syntax *Line } +// A Go is the go statement. +type Go struct { + Version string // "1.23" + Syntax *Line +} + +// A Require is a single require statement. +type Require struct { + Mod module.Version + Indirect bool // has "// indirect" comment + Syntax *Line +} + +// An Exclude is a single exclude statement. type Exclude struct { Mod module.Version Syntax *Line } +// A Replace is a single replace statement. type Replace struct { - Old module.Version - New module.Version - + Old module.Version + New module.Version Syntax *Line } -func (f *File) AddModuleStmt(path string) { - f.Module = &Module{ - Mod: module.Version{Path: path}, - } +func (f *File) AddModuleStmt(path string) error { if f.Syntax == nil { f.Syntax = new(FileSyntax) } - f.Syntax.Stmt = append(f.Syntax.Stmt, &Line{ - Token: []string{"module", AutoQuote(path)}, - }) + if f.Module == nil { + f.Module = &Module{ + Mod: module.Version{Path: path}, + Syntax: f.Syntax.addLine(nil, "module", AutoQuote(path)), + } + } else { + f.Module.Mod.Path = path + f.Syntax.updateLine(f.Module.Syntax, "module", AutoQuote(path)) + } + return nil } func (f *File) AddComment(text string) { @@ -78,7 +95,24 @@ func (f *File) AddComment(text string) { type VersionFixer func(path, version string) (string, error) +// Parse parses the data, reported in errors as being from file, +// into a File struct. It applies fix, if non-nil, to canonicalize all module versions found. func Parse(file string, data []byte, fix VersionFixer) (*File, error) { + return parseToFile(file, data, fix, true) +} + +// ParseLax is like Parse but ignores unknown statements. +// It is used when parsing go.mod files other than the main module, +// under the theory that most statement types we add in the future will +// only apply in the main module, like exclude and replace, +// and so we get better gradual deployments if old go commands +// simply ignore those statements when found in go.mod files +// in dependencies. +func ParseLax(file string, data []byte, fix VersionFixer) (*File, error) { + return parseToFile(file, data, fix, false) +} + +func parseToFile(file string, data []byte, fix VersionFixer, strict bool) (*File, error) { fs, err := parse(file, data) if err != nil { return nil, err @@ -91,20 +125,24 @@ func Parse(file string, data []byte, fix VersionFixer) (*File, error) { for _, x := range fs.Stmt { switch x := x.(type) { case *Line: - f.add(&errs, x, x.Token[0], x.Token[1:], fix) + f.add(&errs, x, x.Token[0], x.Token[1:], fix, strict) case *LineBlock: if len(x.Token) > 1 { - fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + if strict { + fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + } continue } switch x.Token[0] { default: - fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + if strict { + fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " ")) + } continue case "module", "require", "exclude", "replace": for _, l := range x.Line { - f.add(&errs, l, x.Token[0], l.Token, fix) + f.add(&errs, l, x.Token[0], l.Token, fix, strict) } } } @@ -116,26 +154,45 @@ func Parse(file string, data []byte, fix VersionFixer) (*File, error) { return f, nil } -func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer) { - // TODO: We should pass in a flag saying whether this module is a dependency. - // If so, we should ignore all unknown directives and not attempt to parse - // replace and exclude either. They don't matter, and it will work better for - // forward compatibility if we can depend on modules that have local changes. +var goVersionRE = regexp.MustCompile(`([1-9][0-9]*)\.(0|[1-9][0-9]*)`) - // TODO: For the target module (not dependencies), maybe we should - // relax the semver requirement and rewrite the file with updated info - // after resolving any versions. That would let people type commit hashes - // or tags or branch names, and then vgo would fix them. +func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer, strict bool) { + // If strict is false, this module is a dependency. + // We ignore all unknown directives as well as main-module-only + // directives like replace and exclude. It will work better for + // forward compatibility if we can depend on modules that have unknown + // statements (presumed relevant only when acting as the main module) + // and simply ignore those statements. + if !strict { + switch verb { + case "module", "require", "go": + // want these even for dependency go.mods + default: + return + } + } switch verb { default: fmt.Fprintf(errs, "%s:%d: unknown directive: %s\n", f.Syntax.Name, line.Start.Line, verb) + + case "go": + if f.Go != nil { + fmt.Fprintf(errs, "%s:%d: repeated go statement\n", f.Syntax.Name, line.Start.Line) + return + } + if len(args) != 1 || !goVersionRE.MatchString(args[0]) { + fmt.Fprintf(errs, "%s:%d: usage: go 1.23\n", f.Syntax.Name, line.Start.Line) + return + } + f.Go = &Go{Syntax: line} + f.Go.Version = args[0] case "module": if f.Module != nil { fmt.Fprintf(errs, "%s:%d: repeated module statement\n", f.Syntax.Name, line.Start.Line) return } - f.Module = new(Module) + f.Module = &Module{Syntax: line} if len(args) != 1 { fmt.Fprintf(errs, "%s:%d: usage: module module/path [version]\n", f.Syntax.Name, line.Start.Line) @@ -163,19 +220,23 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f fmt.Fprintf(errs, "%s:%d: invalid module version %q: %v\n", f.Syntax.Name, line.Start.Line, old, err) return } - v1, err := moduleMajorVersion(s) + pathMajor, err := modulePathMajor(s) if err != nil { fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) return } - if v2 := semver.Major(v); v1 != v2 && (v1 != "v1" || v2 != "v0") { - fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, v1, v2, v) + if !module.MatchPathMajor(v, pathMajor) { + if pathMajor == "" { + pathMajor = "v0 or v1" + } + fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v) return } if verb == "require" { f.Require = append(f.Require, &Require{ - Mod: module.Version{Path: s, Version: v}, - Syntax: line, + Mod: module.Version{Path: s, Version: v}, + Syntax: line, + Indirect: isIndirect(line), }) } else { f.Exclude = append(f.Exclude, &Exclude{ @@ -184,8 +245,12 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f }) } case "replace": - if len(args) < 4 || len(args) > 5 || args[2] != "=>" { - fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3 => other/module v1.4\n\t or %s module/path v1.2.3 => ../local/directory", f.Syntax.Name, line.Start.Line, verb, verb) + arrow := 2 + if len(args) >= 2 && args[1] == "=>" { + arrow = 1 + } + if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" { + fmt.Fprintf(errs, "%s:%d: usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory\n", f.Syntax.Name, line.Start.Line, verb, verb) return } s, err := parseString(&args[0]) @@ -193,50 +258,55 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) return } - old := args[1] - v, err := parseVersion(s, &args[1], fix) - if err != nil { - fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err) - return - } - v1, err := moduleMajorVersion(s) + pathMajor, err := modulePathMajor(s) if err != nil { fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err) return } - if v2 := semver.Major(v); v1 != v2 && (v1 != "v1" || v2 != "v0") { - fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, v1, v2, v) - return + var v string + if arrow == 2 { + old := args[1] + v, err = parseVersion(s, &args[1], fix) + if err != nil { + fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err) + return + } + if !module.MatchPathMajor(v, pathMajor) { + if pathMajor == "" { + pathMajor = "v0 or v1" + } + fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, pathMajor, semver.Major(v), v) + return + } } - ns, err := parseString(&args[3]) + ns, err := parseString(&args[arrow+1]) if err != nil { fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err) return } nv := "" - if len(args) == 4 { - if !isDirectoryPath(ns) { - fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)", f.Syntax.Name, line.Start.Line) + if len(args) == arrow+2 { + if !IsDirectoryPath(ns) { + fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)\n", f.Syntax.Name, line.Start.Line) return } if filepath.Separator == '/' && strings.Contains(ns, `\`) { - fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)", f.Syntax.Name, line.Start.Line) + fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)\n", f.Syntax.Name, line.Start.Line) return } } - if len(args) == 5 { - old := args[4] - nv, err = parseVersion(ns, &args[4], fix) + if len(args) == arrow+3 { + old := args[arrow+1] + nv, err = parseVersion(ns, &args[arrow+2], fix) if err != nil { fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err) return } - if isDirectoryPath(ns) { - fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version", f.Syntax.Name, line.Start.Line, ns) + if IsDirectoryPath(ns) { + fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version\n", f.Syntax.Name, line.Start.Line, ns) return } } - // TODO: More sanity checks about directories vs module paths. f.Replace = append(f.Replace, &Replace{ Old: module.Version{Path: s, Version: v}, New: module.Version{Path: ns, Version: nv}, @@ -245,7 +315,58 @@ func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, f } } -func isDirectoryPath(ns string) bool { +// isIndirect reports whether line has a "// indirect" comment, +// meaning it is in go.mod only for its effect on indirect dependencies, +// so that it can be dropped entirely once the effective version of the +// indirect dependency reaches the given minimum version. +func isIndirect(line *Line) bool { + if len(line.Suffix) == 0 { + return false + } + f := strings.Fields(line.Suffix[0].Token) + return (len(f) == 2 && f[1] == "indirect" || len(f) > 2 && f[1] == "indirect;") && f[0] == "//" +} + +// setIndirect sets line to have (or not have) a "// indirect" comment. +func setIndirect(line *Line, indirect bool) { + if isIndirect(line) == indirect { + return + } + if indirect { + // Adding comment. + if len(line.Suffix) == 0 { + // New comment. + line.Suffix = []Comment{{Token: "// indirect", Suffix: true}} + return + } + // Insert at beginning of existing comment. + com := &line.Suffix[0] + space := " " + if len(com.Token) > 2 && com.Token[2] == ' ' || com.Token[2] == '\t' { + space = "" + } + com.Token = "// indirect;" + space + com.Token[2:] + return + } + + // Removing comment. + f := strings.Fields(line.Suffix[0].Token) + if len(f) == 2 { + // Remove whole comment. + line.Suffix = nil + return + } + + // Remove comment prefix. + com := &line.Suffix[0] + i := strings.Index(com.Token, "indirect;") + com.Token = "//" + com.Token[i+len("indirect;"):] +} + +// IsDirectoryPath reports whether the given path should be interpreted +// as a directory path. Just like on the go command line, relative paths +// and rooted paths are directory paths; the rest are module paths. +func IsDirectoryPath(ns string) bool { // Because go.mod files can move from one system to another, // we check all known path syntaxes, both Unix and Windows. return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") || @@ -253,19 +374,21 @@ func isDirectoryPath(ns string) bool { len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':' } -func mustQuote(t string) bool { - for _, r := range t { +// MustQuote reports whether s must be quoted in order to appear as +// a single token in a go.mod line. +func MustQuote(s string) bool { + for _, r := range s { if !unicode.IsPrint(r) || r == ' ' || r == '"' || r == '\'' || r == '`' { return true } } - return t == "" || strings.Contains(t, "//") || strings.Contains(t, "/*") + return s == "" || strings.Contains(s, "//") || strings.Contains(s, "/*") } // AutoQuote returns s or, if quoting is required for s to appear in a go.mod, // the quotation of s. func AutoQuote(s string) string { - if mustQuote(s) { + if MustQuote(s) { return strconv.Quote(s) } return s @@ -300,89 +423,99 @@ func parseVersion(path string, s *string, fix VersionFixer) (string, error) { return "", err } } - if semver.IsValid(t) { - *s = semver.Canonical(t) + if v := module.CanonicalVersion(t); v != "" { + *s = v return *s, nil } return "", fmt.Errorf("version must be of the form v1.2.3") } -func moduleMajorVersion(p string) (string, error) { - if _, _, major, _, ok := ParseGopkgIn(p); ok { - return major, nil +func modulePathMajor(path string) (string, error) { + _, major, ok := module.SplitPathVersion(path) + if !ok { + return "", fmt.Errorf("invalid module path") } - - start := strings.LastIndex(p, "/") + 1 - v := p[start:] - if !isMajorVersion(v) { - return "v1", nil - } - if v[1] == '0' || v == "v1" { - return "", fmt.Errorf("module path has invalid version number %s", v) - } - return v, nil -} - -func isMajorVersion(v string) bool { - if len(v) < 2 || v[0] != 'v' { - return false - } - for i := 1; i < len(v); i++ { - if v[i] < '0' || '9' < v[i] { - return false - } - } - return true + return major, nil } func (f *File) Format() ([]byte, error) { return Format(f.Syntax), nil } -func (x *File) AddRequire(path, vers string) { - var syntax *Line +// Cleanup cleans up the file f after any edit operations. +// To avoid quadratic behavior, modifications like DropRequire +// clear the entry but do not remove it from the slice. +// Cleanup cleans out all the cleared entries. +func (f *File) Cleanup() { + w := 0 + for _, r := range f.Require { + if r.Mod.Path != "" { + f.Require[w] = r + w++ + } + } + f.Require = f.Require[:w] - for i, stmt := range x.Syntax.Stmt { - switch stmt := stmt.(type) { - case *LineBlock: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - syntax = &Line{Token: []string{AutoQuote(path), vers}} - stmt.Line = append(stmt.Line, syntax) - goto End - } - case *Line: - if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - stmt.Token = stmt.Token[1:] - syntax = &Line{Token: []string{AutoQuote(path), vers}} - x.Syntax.Stmt[i] = &LineBlock{ - Comments: stmt.Comments, - Token: []string{"require"}, - Line: []*Line{ - stmt, - syntax, - }, - } - goto End + w = 0 + for _, x := range f.Exclude { + if x.Mod.Path != "" { + f.Exclude[w] = x + w++ + } + } + f.Exclude = f.Exclude[:w] + + w = 0 + for _, r := range f.Replace { + if r.Old.Path != "" { + f.Replace[w] = r + w++ + } + } + f.Replace = f.Replace[:w] + + f.Syntax.Cleanup() +} + +func (f *File) AddRequire(path, vers string) error { + need := true + for _, r := range f.Require { + if r.Mod.Path == path { + if need { + r.Mod.Version = vers + f.Syntax.updateLine(r.Syntax, "require", AutoQuote(path), vers) + need = false + } else { + f.Syntax.removeLine(r.Syntax) + *r = Require{} } } } - syntax = &Line{Token: []string{"require", AutoQuote(path), vers}} - x.Syntax.Stmt = append(x.Syntax.Stmt, syntax) - -End: - x.Require = append(x.Require, &Require{module.Version{Path: path, Version: vers}, syntax}) + if need { + f.AddNewRequire(path, vers, false) + } + return nil } -func (f *File) SetRequire(req []module.Version) { +func (f *File) AddNewRequire(path, vers string, indirect bool) { + line := f.Syntax.addLine(nil, "require", AutoQuote(path), vers) + setIndirect(line, indirect) + f.Require = append(f.Require, &Require{module.Version{Path: path, Version: vers}, indirect, line}) +} + +func (f *File) SetRequire(req []*Require) { need := make(map[string]string) - for _, m := range req { - need[m.Path] = m.Version + indirect := make(map[string]bool) + for _, r := range req { + need[r.Mod.Path] = r.Mod.Version + indirect[r.Mod.Path] = r.Indirect } for _, r := range f.Require { if v, ok := need[r.Mod.Path]; ok { r.Mod.Version = v + r.Indirect = indirect[r.Mod.Path] } } @@ -393,9 +526,10 @@ func (f *File) SetRequire(req []module.Version) { if len(stmt.Token) > 0 && stmt.Token[0] == "require" { var newLines []*Line for _, line := range stmt.Line { - if p, err := strconv.Unquote(line.Token[0]); err == nil && need[p] != "" { + if p, err := parseString(&line.Token[0]); err == nil && need[p] != "" { line.Token[1] = need[p] delete(need, p) + setIndirect(line, indirect[p]) newLines = append(newLines, line) } } @@ -407,9 +541,10 @@ func (f *File) SetRequire(req []module.Version) { case *Line: if len(stmt.Token) > 0 && stmt.Token[0] == "require" { - if p, err := strconv.Unquote(stmt.Token[1]); err == nil && need[p] != "" { + if p, err := parseString(&stmt.Token[1]); err == nil && need[p] != "" { stmt.Token[2] = need[p] delete(need, p) + setIndirect(stmt, indirect[p]) } else { continue // drop stmt } @@ -420,11 +555,93 @@ func (f *File) SetRequire(req []module.Version) { f.Syntax.Stmt = newStmts for path, vers := range need { - f.AddRequire(path, vers) + f.AddNewRequire(path, vers, indirect[path]) } f.SortBlocks() } +func (f *File) DropRequire(path string) error { + for _, r := range f.Require { + if r.Mod.Path == path { + f.Syntax.removeLine(r.Syntax) + *r = Require{} + } + } + return nil +} + +func (f *File) AddExclude(path, vers string) error { + var hint *Line + for _, x := range f.Exclude { + if x.Mod.Path == path && x.Mod.Version == vers { + return nil + } + if x.Mod.Path == path { + hint = x.Syntax + } + } + + f.Exclude = append(f.Exclude, &Exclude{Mod: module.Version{Path: path, Version: vers}, Syntax: f.Syntax.addLine(hint, "exclude", AutoQuote(path), vers)}) + return nil +} + +func (f *File) DropExclude(path, vers string) error { + for _, x := range f.Exclude { + if x.Mod.Path == path && x.Mod.Version == vers { + f.Syntax.removeLine(x.Syntax) + *x = Exclude{} + } + } + return nil +} + +func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error { + need := true + old := module.Version{Path: oldPath, Version: oldVers} + new := module.Version{Path: newPath, Version: newVers} + tokens := []string{"replace", AutoQuote(oldPath)} + if oldVers != "" { + tokens = append(tokens, oldVers) + } + tokens = append(tokens, "=>", AutoQuote(newPath)) + if newVers != "" { + tokens = append(tokens, newVers) + } + + var hint *Line + for _, r := range f.Replace { + if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) { + if need { + // Found replacement for old; update to use new. + r.New = new + f.Syntax.updateLine(r.Syntax, tokens...) + need = false + continue + } + // Already added; delete other replacements for same. + f.Syntax.removeLine(r.Syntax) + *r = Replace{} + } + if r.Old.Path == oldPath { + hint = r.Syntax + } + } + if need { + f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)}) + } + return nil +} + +func (f *File) DropReplace(oldPath, oldVers string) error { + for _, r := range f.Replace { + if r.Old.Path == oldPath && r.Old.Version == oldVers { + f.Syntax.removeLine(r.Syntax) + *r = Replace{} + } + } + return nil +} + func (f *File) SortBlocks() { f.removeDups() // otherwise sorting is unsafe diff --git a/src/cmd/go/internal/modfile/rule_test.go b/src/cmd/go/internal/modfile/rule_test.go new file mode 100644 index 0000000000..b88ad62916 --- /dev/null +++ b/src/cmd/go/internal/modfile/rule_test.go @@ -0,0 +1,90 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modfile + +import ( + "bytes" + "fmt" + "testing" +) + +var addRequireTests = []struct { + in string + path string + vers string + out string +}{ + { + ` + module m + require x.y/z v1.2.3 + `, + "x.y/z", "v1.5.6", + ` + module m + require x.y/z v1.5.6 + `, + }, + { + ` + module m + require x.y/z v1.2.3 + `, + "x.y/w", "v1.5.6", + ` + module m + require ( + x.y/z v1.2.3 + x.y/w v1.5.6 + ) + `, + }, + { + ` + module m + require x.y/z v1.2.3 + require x.y/q/v2 v2.3.4 + `, + "x.y/w", "v1.5.6", + ` + module m + require x.y/z v1.2.3 + require ( + x.y/q/v2 v2.3.4 + x.y/w v1.5.6 + ) + `, + }, +} + +func TestAddRequire(t *testing.T) { + for i, tt := range addRequireTests { + t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { + f, err := Parse("in", []byte(tt.in), nil) + if err != nil { + t.Fatal(err) + } + g, err := Parse("out", []byte(tt.out), nil) + if err != nil { + t.Fatal(err) + } + golden, err := g.Format() + if err != nil { + t.Fatal(err) + } + + if err := f.AddRequire(tt.path, tt.vers); err != nil { + t.Fatal(err) + } + out, err := f.Format() + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(out, golden) { + t.Errorf("have:\n%s\nwant:\n%s", out, golden) + } + }) + } +} diff --git a/src/cmd/go/internal/modfile/testdata/replace2.golden b/src/cmd/go/internal/modfile/testdata/replace2.golden index 1d18a3b461..e1d9c728df 100644 --- a/src/cmd/go/internal/modfile/testdata/replace2.golden +++ b/src/cmd/go/internal/modfile/testdata/replace2.golden @@ -5,4 +5,6 @@ replace ( xyz v1.3.4 => my/xyz v1.3.4-me xyz v1.4.5 => "/tmp/my dir" xyz v1.5.6 => my/xyz v1.5.6 + + xyz => my/other/xyz v1.5.4 ) diff --git a/src/cmd/go/internal/modfile/testdata/replace2.in b/src/cmd/go/internal/modfile/testdata/replace2.in index 78c46694a2..786469866f 100644 --- a/src/cmd/go/internal/modfile/testdata/replace2.in +++ b/src/cmd/go/internal/modfile/testdata/replace2.in @@ -5,4 +5,6 @@ replace ( "xyz" v1.3.4 => "my/xyz" "v1.3.4-me" xyz "v1.4.5" => "/tmp/my dir" xyz v1.5.6 => my/xyz v1.5.6 + + xyz => my/other/xyz v1.5.4 ) diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go new file mode 100644 index 0000000000..90a5bd8130 --- /dev/null +++ b/src/cmd/go/internal/modget/get.go @@ -0,0 +1,656 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package modget implements the module-aware ``go get'' command. +package modget + +import ( + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/get" + "cmd/go/internal/load" + "cmd/go/internal/modfetch" + "cmd/go/internal/modload" + "cmd/go/internal/module" + "cmd/go/internal/mvs" + "cmd/go/internal/par" + "cmd/go/internal/search" + "cmd/go/internal/semver" + "cmd/go/internal/str" + "cmd/go/internal/work" + "fmt" + "os" + pathpkg "path" + "path/filepath" + "strings" +) + +var CmdGet = &base.Command{ + // Note: -d -m -u are listed explicitly because they are the most common get flags. + // Do not send CLs removing them because they're covered by [get flags]. + UsageLine: "go get [-d] [-m] [-u] [-v] [-insecure] [build flags] [packages]", + Short: "add dependencies to current module and install them", + Long: ` +Get resolves and adds dependencies to the current development module +and then builds and installs them. + +The first step is to resolve which dependencies to add. + +For each named package or package pattern, get must decide which version of +the corresponding module to use. By default, get chooses the latest tagged +release version, such as v0.4.5 or v1.2.3. If there are no tagged release +versions, get chooses the latest tagged prerelease version, such as +v0.0.1-pre1. If there are no tagged versions at all, get chooses the latest +known commit. + +This default version selection can be overridden by adding an @version +suffix to the package argument, as in 'go get golang.org/x/text@v0.3.0'. +For modules stored in source control repositories, the version suffix can +also be a commit hash, branch identifier, or other syntax known to the +source control system, as in 'go get golang.org/x/text@master'. +The version suffix @latest explicitly requests the default behavior +described above. + +If a module under consideration is already a dependency of the current +development module, then get will update the required version. +Specifying a version earlier than the current required version is valid and +downgrades the dependency. The version suffix @none indicates that the +dependency should be removed entirely. + +Although get defaults to using the latest version of the module containing +a named package, it does not use the latest version of that module's +dependencies. Instead it prefers to use the specific dependency versions +requested by that module. For example, if the latest A requires module +B v1.2.3, while B v1.2.4 and v1.3.1 are also available, then 'go get A' +will use the latest A but then use B v1.2.3, as requested by A. (If there +are competing requirements for a particular module, then 'go get' resolves +those requirements by taking the maximum requested version.) + +The -u flag instructs get to update dependencies to use newer minor or +patch releases when available. Continuing the previous example, +'go get -u A' will use the latest A with B v1.3.1 (not B v1.2.3). + +The -u=patch flag (not -u patch) instructs get to update dependencies +to use newer patch releases when available. Continuing the previous example, +'go get -u=patch A' will use the latest A with B v1.2.4 (not B v1.2.3). + +In general, adding a new dependency may require upgrading +existing dependencies to keep a working build, and 'go get' does +this automatically. Similarly, downgrading one dependency may +require downgrading other dependenceis, and 'go get' does +this automatically as well. + +The -m flag instructs get to stop here, after resolving, upgrading, +and downgrading modules and updating go.mod. When using -m, +each specified package path must be a module path as well, +not the import path of a package below the module root. + +The -insecure flag permits fetching from repositories and resolving +custom domains using insecure schemes such as HTTP. Use with caution. + +The second step is to download (if needed), build, and install +the named packages. + +If an argument names a module but not a package (because there is no +Go source code in the module's root directory), then the install step +is skipped for that argument, instead of causing a build failure. +For example 'go get golang.org/x/perf' succeeds even though there +is no code corresponding to that import path. + +Note that package patterns are allowed and are expanded after resolving +the module versions. For example, 'go get golang.org/x/perf/cmd/...' +adds the latest golang.org/x/perf and then installs the commands in that +latest version. + +The -d flag instructs get to download the source code needed to build +the named packages, including downloading necessary dependencies, +but not to build and install them. + +With no package arguments, 'go get' applies to the main module, +and to the Go package in the current directory, if any. In particular, +'go get -u' and 'go get -u=patch' update all the dependencies of the +main module. With no package arguments and also without -u, +'go get' is not much more than 'go install', and 'go get -d' not much +more than 'go list'. + +For more about modules, see 'go help modules'. + +For more about specifying packages, see 'go help packages'. + +This text describes the behavior of get using modules to manage source +code and dependencies. If instead the go command is running in GOPATH +mode, the details of get's flags and effects change, as does 'go help get'. +See 'go help modules' and 'go help gopath-get'. + +See also: go build, go install, go clean, go mod. + `, +} + +// Note that this help text is a stopgap to make the module-aware get help text +// available even in non-module settings. It should be deleted when the old get +// is deleted. It should NOT be considered to set a precedent of having hierarchical +// help names with dashes. +var HelpModuleGet = &base.Command{ + UsageLine: "module-get", + Short: "module-aware go get", + Long: ` +The 'go get' command changes behavior depending on whether the +go command is running in module-aware mode or legacy GOPATH mode. +This help text, accessible as 'go help module-get' even in legacy GOPATH mode, +describes 'go get' as it operates in module-aware mode. + +Usage: ` + CmdGet.UsageLine + ` +` + CmdGet.Long, +} + +var ( + getD = CmdGet.Flag.Bool("d", false, "") + getF = CmdGet.Flag.Bool("f", false, "") + getFix = CmdGet.Flag.Bool("fix", false, "") + getM = CmdGet.Flag.Bool("m", false, "") + getT = CmdGet.Flag.Bool("t", false, "") + getU upgradeFlag + // -insecure is get.Insecure + // -v is cfg.BuildV +) + +// upgradeFlag is a custom flag.Value for -u. +type upgradeFlag string + +func (*upgradeFlag) IsBoolFlag() bool { return true } // allow -u + +func (v *upgradeFlag) Set(s string) error { + if s == "false" { + s = "" + } + *v = upgradeFlag(s) + return nil +} + +func (v *upgradeFlag) String() string { return "" } + +func init() { + work.AddBuildFlags(CmdGet) + CmdGet.Run = runGet // break init loop + CmdGet.Flag.BoolVar(&get.Insecure, "insecure", get.Insecure, "") + CmdGet.Flag.Var(&getU, "u", "") +} + +// A task holds the state for processing a single get argument (path@vers). +type task struct { + arg string // original argument + index int + path string // package path part of arg + forceModulePath bool // path must be interpreted as a module path + vers string // version part of arg + m module.Version // module version indicated by argument + req []module.Version // m's requirement list (not upgraded) +} + +func runGet(cmd *base.Command, args []string) { + // -mod=readonly has no effect on "go get". + if cfg.BuildMod == "readonly" { + cfg.BuildMod = "" + } + + switch getU { + case "", "patch", "true": + // ok + default: + base.Fatalf("go get: unknown upgrade flag -u=%s", getU) + } + if *getF { + fmt.Fprintf(os.Stderr, "go get: -f flag is a no-op when using modules\n") + } + if *getFix { + fmt.Fprintf(os.Stderr, "go get: -fix flag is a no-op when using modules\n") + } + if *getT { + fmt.Fprintf(os.Stderr, "go get: -t flag is a no-op when using modules\n") + } + + if cfg.BuildMod == "vendor" { + base.Fatalf("go get: disabled by -mod=%s", cfg.BuildMod) + } + + modload.LoadBuildList() + + // Do not allow any updating of go.mod until we've applied + // all the requested changes and checked that the result matches + // what was requested. + modload.DisallowWriteGoMod() + + // Build task and install lists. + // The command-line arguments are of the form path@version + // or simply path, with implicit @latest. path@none is "downgrade away". + // At the end of the loop, we've resolved the list of arguments into + // a list of tasks (a path@vers that needs further processing) + // and a list of install targets (for the "go install" at the end). + var tasks []*task + var install []string + for _, arg := range search.CleanPatterns(args) { + // Argument is module query path@vers, or else path with implicit @latest. + path := arg + vers := "" + if i := strings.Index(arg, "@"); i >= 0 { + path, vers = arg[:i], arg[i+1:] + } + if strings.Contains(vers, "@") || arg != path && vers == "" { + base.Errorf("go get %s: invalid module version syntax", arg) + continue + } + if vers != "none" { + install = append(install, path) + } + + // Deciding which module to upgrade/downgrade for a particular argument is difficult. + // Patterns only make it more difficult. + // We impose restrictions to avoid needing to interlace pattern expansion, + // like in in modload.ImportPaths. + // Specifically, these patterns are supported: + // + // - Relative paths like ../../foo or ../../foo... are restricted to matching directories + // in the current module and therefore map to the current module. + // It's possible that the pattern matches no packages, but we will still treat it + // as mapping to the current module. + // TODO: In followup, could just expand the full list and remove the discrepancy. + // - The pattern "all" has its usual package meaning and maps to the list of modules + // from which the matched packages are drawn. This is potentially a subset of the + // module pattern "all". If module A requires B requires C but A does not import + // the parts of B that import C, the packages matched by "all" are only from A and B, + // so only A and B end up on the tasks list. + // TODO: Even in -m mode? + // - The patterns "std" and "cmd" expand to packages in the standard library, + // which aren't upgradable, so we skip over those. + // In -m mode they expand to non-module-paths, so they are disallowed. + // - Import path patterns like foo/bar... are matched against the module list, + // assuming any package match would imply a module pattern match. + // TODO: What about -m mode? + // - Import paths without patterns are left as is, for resolution by getQuery (eventually modload.Import). + // + if search.IsRelativePath(path) { + // Check that this relative pattern only matches directories in the current module, + // and then record the current module as the target. + dir := path + if i := strings.Index(path, "..."); i >= 0 { + dir, _ = pathpkg.Split(path[:i]) + } + abs, err := filepath.Abs(dir) + if err != nil { + base.Errorf("go get %s: %v", arg, err) + continue + } + if !str.HasFilePathPrefix(abs, modload.ModRoot) { + base.Errorf("go get %s: directory %s is outside module root %s", arg, abs, modload.ModRoot) + continue + } + // TODO: Check if abs is inside a nested module. + tasks = append(tasks, &task{arg: arg, path: modload.Target.Path, vers: ""}) + continue + } + if path == "all" { + // TODO: If *getM, should this be the module pattern "all"? + + // This is the package pattern "all" not the module pattern "all": + // enumerate all the modules actually needed by builds of the packages + // in the main module, not incidental modules that happen to be + // in the package graph (and therefore build list). + // Note that LoadALL may add new modules to the build list to + // satisfy new imports, but vers == "latest" implicitly anyway, + // so we'll assume that's OK. + seen := make(map[module.Version]bool) + pkgs := modload.LoadALL() + for _, pkg := range pkgs { + m := modload.PackageModule(pkg) + if m.Path != "" && !seen[m] { + seen[m] = true + tasks = append(tasks, &task{arg: arg, path: m.Path, vers: "latest", forceModulePath: true}) + } + } + continue + } + if search.IsMetaPackage(path) { + // Already handled "all", so this must be "std" or "cmd", + // which are entirely in the standard library. + if path != arg { + base.Errorf("go get %s: cannot use pattern %q with explicit version", arg, arg) + } + if *getM { + base.Errorf("go get %s: cannot use pattern %q with -m", arg, arg) + continue + } + continue + } + if strings.Contains(path, "...") { + // Apply to modules in build list matched by pattern (golang.org/x/...), if any. + match := search.MatchPattern(path) + matched := false + for _, m := range modload.BuildList() { + if match(m.Path) || str.HasPathPrefix(path, m.Path) { + tasks = append(tasks, &task{arg: arg, path: m.Path, vers: vers, forceModulePath: true}) + matched = true + } + } + // If matched, we're done. + // Otherwise assume pattern is inside a single module + // (golang.org/x/text/unicode/...) and leave for usual lookup. + // Unless we're using -m. + if matched { + continue + } + if *getM { + base.Errorf("go get %s: pattern matches no modules in build list", arg) + continue + } + } + tasks = append(tasks, &task{arg: arg, path: path, vers: vers}) + } + base.ExitIfErrors() + + // Now we've reduced the upgrade/downgrade work to a list of path@vers pairs (tasks). + // Resolve each one in parallel. + reqs := modload.Reqs() + var lookup par.Work + for _, t := range tasks { + lookup.Add(t) + } + lookup.Do(10, func(item interface{}) { + t := item.(*task) + if t.vers == "none" { + // Wait for downgrade step. + t.m = module.Version{Path: t.path, Version: "none"} + return + } + m, err := getQuery(t.path, t.vers, t.forceModulePath) + if err != nil { + base.Errorf("go get %v: %v", t.arg, err) + return + } + t.m = m + }) + base.ExitIfErrors() + + // Now we know the specific version of each path@vers. + // The final build list will be the union of three build lists: + // 1. the original build list + // 2. the modules named on the command line (other than @none) + // 3. the upgraded requirements of those modules (if upgrading) + // Start building those lists. + // This loop collects (2). + // Also, because the list of paths might have named multiple packages in a single module + // (or even the same package multiple times), now that we know the module for each + // package, this loop deduplicates multiple references to a given module. + // (If a module is mentioned multiple times, the listed target version must be the same each time.) + var named []module.Version + byPath := make(map[string]*task) + for _, t := range tasks { + prev, ok := byPath[t.m.Path] + if prev != nil && prev.m != t.m { + base.Errorf("go get: conflicting versions for module %s: %s and %s", t.m.Path, prev.m.Version, t.m.Version) + byPath[t.m.Path] = nil // sentinel to stop errors + continue + } + if ok { + continue // already added + } + byPath[t.m.Path] = t + if t.m.Version != "none" { + named = append(named, t.m) + } + } + base.ExitIfErrors() + + // If the modules named on the command line have any dependencies + // and we're supposed to upgrade dependencies, + // chase down the full list of upgraded dependencies. + // This turns required from a not-yet-upgraded (3) to the final (3). + // (See list above.) + var required []module.Version + if getU != "" { + upgraded, err := mvs.UpgradeAll(upgradeTarget, &upgrader{ + Reqs: modload.Reqs(), + targets: named, + patch: getU == "patch", + tasks: byPath, + }) + if err != nil { + base.Fatalf("go get: %v", err) + } + required = upgraded[1:] // slice off upgradeTarget + base.ExitIfErrors() + } + + // Put together the final build list as described above (1) (2) (3). + // If we're not using -u, then len(required) == 0 and ReloadBuildList + // chases down the dependencies of all the named module versions + // in one operation. + var list []module.Version + list = append(list, modload.BuildList()...) + list = append(list, named...) + list = append(list, required...) + modload.SetBuildList(list) + modload.ReloadBuildList() // note: does not update go.mod + base.ExitIfErrors() + + // Scan for and apply any needed downgrades. + var down []module.Version + for _, m := range modload.BuildList() { + t := byPath[m.Path] + if t != nil && semver.Compare(m.Version, t.m.Version) > 0 { + down = append(down, module.Version{Path: m.Path, Version: t.m.Version}) + } + } + if len(down) > 0 { + list, err := mvs.Downgrade(modload.Target, modload.Reqs(), down...) + if err != nil { + base.Fatalf("go get: %v", err) + } + modload.SetBuildList(list) + modload.ReloadBuildList() // note: does not update go.mod + } + base.ExitIfErrors() + + // Scan for any upgrades lost by the downgrades. + lost := make(map[string]string) + for _, m := range modload.BuildList() { + t := byPath[m.Path] + if t != nil && semver.Compare(m.Version, t.m.Version) != 0 { + lost[m.Path] = m.Version + } + } + if len(lost) > 0 { + desc := func(m module.Version) string { + s := m.Path + "@" + m.Version + t := byPath[m.Path] + if t != nil && t.arg != s { + s += " from " + t.arg + } + return s + } + downByPath := make(map[string]module.Version) + for _, d := range down { + downByPath[d.Path] = d + } + var buf strings.Builder + fmt.Fprintf(&buf, "go get: inconsistent versions:") + for _, t := range tasks { + if lost[t.m.Path] == "" { + continue + } + // We lost t because its build list requires a newer version of something in down. + // Figure out exactly what. + // Repeatedly constructing the build list is inefficient + // if there are MANY command-line arguments, + // but at least all the necessary requirement lists are cached at this point. + list, err := mvs.BuildList(t.m, reqs) + if err != nil { + base.Fatalf("go get: %v", err) + } + + fmt.Fprintf(&buf, "\n\t%s", desc(t.m)) + sep := " requires" + for _, m := range list { + if down, ok := downByPath[m.Path]; ok && semver.Compare(down.Version, m.Version) < 0 { + fmt.Fprintf(&buf, "%s %s@%s (not %s)", sep, m.Path, m.Version, desc(down)) + sep = "," + } + } + if sep != "," { + // We have no idea why this happened. + // At least report the problem. + fmt.Fprintf(&buf, " ended up at %v unexpectedly (please report at golang.org/issue/new)", lost[t.m.Path]) + } + } + base.Fatalf("%v", buf.String()) + } + + // Everything succeeded. Update go.mod. + modload.AllowWriteGoMod() + modload.WriteGoMod() + + // If -m was specified, we're done after the module work. No download, no build. + if *getM { + return + } + + if len(install) > 0 { + // All requested versions were explicitly @none. + // Note that 'go get -u' without any arguments results in len(install) == 1: + // search.CleanImportPaths returns "." for empty args. + work.BuildInit() + pkgs := load.PackagesAndErrors(install) + var todo []*load.Package + for _, p := range pkgs { + // Ignore "no Go source files" errors for 'go get' operations on modules. + if p.Error != nil { + if len(args) == 0 && getU != "" && strings.HasPrefix(p.Error.Err, "no Go files") { + // Upgrading modules: skip the implicitly-requested package at the + // current directory, even if it is not tho module root. + continue + } + if strings.Contains(p.Error.Err, "cannot find module providing") && modload.ModuleInfo(p.ImportPath) != nil { + // Explicitly-requested module, but it doesn't contain a package at the + // module root. + continue + } + } + todo = append(todo, p) + } + + // If -d was specified, we're done after the download: no build. + // (The load.PackagesAndErrors is what did the download + // of the named packages and their dependencies.) + if len(todo) > 0 && !*getD { + work.InstallPackages(install, todo) + } + } +} + +// getQuery evaluates the given package path, version pair +// to determine the underlying module version being requested. +// If forceModulePath is set, getQuery must interpret path +// as a module path. +func getQuery(path, vers string, forceModulePath bool) (module.Version, error) { + if vers == "" { + vers = "latest" + } + + // First choice is always to assume path is a module path. + // If that works out, we're done. + info, err := modload.Query(path, vers, modload.Allowed) + if err == nil { + return module.Version{Path: path, Version: info.Version}, nil + } + + // Even if the query fails, if the path must be a real module, then report the query error. + if forceModulePath || *getM { + return module.Version{}, err + } + + // Otherwise, try a package path. + m, _, err := modload.QueryPackage(path, vers, modload.Allowed) + return m, err +} + +// An upgrader adapts an underlying mvs.Reqs to apply an +// upgrade policy to a list of targets and their dependencies. +// If patch=false, the upgrader implements "get -u". +// If patch=true, the upgrader implements "get -u=patch". +type upgrader struct { + mvs.Reqs + targets []module.Version + patch bool + tasks map[string]*task +} + +// upgradeTarget is a fake "target" requiring all the modules to be upgraded. +var upgradeTarget = module.Version{Path: "upgrade target", Version: ""} + +// Required returns the requirement list for m. +// Other than the upgradeTarget, we defer to u.Reqs. +func (u *upgrader) Required(m module.Version) ([]module.Version, error) { + if m == upgradeTarget { + return u.targets, nil + } + return u.Reqs.Required(m) +} + +// Upgrade returns the desired upgrade for m. +// If m is a tagged version, then Upgrade returns the latest tagged version. +// If m is a pseudo-version, then Upgrade returns the latest tagged version +// when that version has a time-stamp newer than m. +// Otherwise Upgrade returns m (preserving the pseudo-version). +// This special case prevents accidental downgrades +// when already using a pseudo-version newer than the latest tagged version. +func (u *upgrader) Upgrade(m module.Version) (module.Version, error) { + // Allow pkg@vers on the command line to override the upgrade choice v. + // If t's version is < v, then we're going to downgrade anyway, + // and it's cleaner to avoid moving back and forth and picking up + // extraneous other newer dependencies. + // If t's version is > v, then we're going to upgrade past v anyway, + // and again it's cleaner to avoid moving back and forth picking up + // extraneous other newer dependencies. + if t := u.tasks[m.Path]; t != nil { + return t.m, nil + } + + // Note that query "latest" is not the same as + // using repo.Latest. + // The query only falls back to untagged versions + // if nothing is tagged. The Latest method + // only ever returns untagged versions, + // which is not what we want. + query := "latest" + if u.patch { + // For patch upgrade, query "v1.2". + query = semver.MajorMinor(m.Version) + } + info, err := modload.Query(m.Path, query, modload.Allowed) + if err != nil { + // Report error but return m, to let version selection continue. + // (Reporting the error will fail the command at the next base.ExitIfErrors.) + // Special case: if the error is "no matching versions" then don't + // even report the error. Because Query does not consider pseudo-versions, + // it may happen that we have a pseudo-version but during -u=patch + // the query v0.0 matches no versions (not even the one we're using). + if !strings.Contains(err.Error(), "no matching versions") { + base.Errorf("go get: upgrading %s@%s: %v", m.Path, m.Version, err) + } + return m, nil + } + + // If we're on a later prerelease, keep using it, + // even though normally an Upgrade will ignore prereleases. + if semver.Compare(info.Version, m.Version) < 0 { + return m, nil + } + + // If we're on a pseudo-version chronologically after the latest tagged version, keep using it. + // This avoids some accidental downgrades. + if mTime, err := modfetch.PseudoVersionTime(m.Version); err == nil && info.Time.Before(mTime) { + return m, nil + } + + return module.Version{Path: m.Path, Version: info.Version}, nil +} diff --git a/src/cmd/go/internal/modinfo/info.go b/src/cmd/go/internal/modinfo/info.go index 6dff2d2c26..7341ce44d2 100644 --- a/src/cmd/go/internal/modinfo/info.go +++ b/src/cmd/go/internal/modinfo/info.go @@ -4,8 +4,46 @@ package modinfo +import "time" + +// Note that these structs are publicly visible (part of go list's API) +// and the fields are documented in the help text in ../list/list.go + type ModulePublic struct { - Top bool - Path string - Version string + Path string `json:",omitempty"` // module path + Version string `json:",omitempty"` // module version + Versions []string `json:",omitempty"` // available module versions + Replace *ModulePublic `json:",omitempty"` // replaced by this module + Time *time.Time `json:",omitempty"` // time version was created + Update *ModulePublic `json:",omitempty"` // available update (with -u) + Main bool `json:",omitempty"` // is this the main module? + Indirect bool `json:",omitempty"` // module is only indirectly needed by main module + Dir string `json:",omitempty"` // directory holding local copy of files, if any + GoMod string `json:",omitempty"` // path to go.mod file describing module, if any + Error *ModuleError `json:",omitempty"` // error loading module + GoVersion string `json:",omitempty"` // go version used in module +} + +type ModuleError struct { + Err string // error text +} + +func (m *ModulePublic) String() string { + s := m.Path + if m.Version != "" { + s += " " + m.Version + if m.Update != nil { + s += " [" + m.Update.Version + "]" + } + } + if m.Replace != nil { + s += " => " + m.Replace.Path + if m.Replace.Version != "" { + s += " " + m.Replace.Version + if m.Replace.Update != nil { + s += " [" + m.Replace.Update.Version + "]" + } + } + } + return s } diff --git a/src/cmd/go/internal/modload/build.go b/src/cmd/go/internal/modload/build.go new file mode 100644 index 0000000000..cebb802db9 --- /dev/null +++ b/src/cmd/go/internal/modload/build.go @@ -0,0 +1,244 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "bytes" + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch" + "cmd/go/internal/modinfo" + "cmd/go/internal/module" + "cmd/go/internal/search" + "encoding/hex" + "fmt" + "os" + "path/filepath" + "strings" +) + +var ( + infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6") + infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2") +) + +func isStandardImportPath(path string) bool { + return findStandardImportPath(path) != "" +} + +func findStandardImportPath(path string) string { + if search.IsStandardImportPath(path) { + dir := filepath.Join(cfg.GOROOT, "src", path) + if _, err := os.Stat(dir); err == nil { + return dir + } + dir = filepath.Join(cfg.GOROOT, "src/vendor", path) + if _, err := os.Stat(dir); err == nil { + return dir + } + } + return "" +} + +func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic { + if isStandardImportPath(pkgpath) || !Enabled() { + return nil + } + return moduleInfo(findModule(pkgpath, pkgpath), true) +} + +func ModuleInfo(path string) *modinfo.ModulePublic { + if !Enabled() { + return nil + } + + if i := strings.Index(path, "@"); i >= 0 { + return moduleInfo(module.Version{Path: path[:i], Version: path[i+1:]}, false) + } + + for _, m := range BuildList() { + if m.Path == path { + return moduleInfo(m, true) + } + } + + return &modinfo.ModulePublic{ + Path: path, + Error: &modinfo.ModuleError{ + Err: "module not in current build", + }, + } +} + +// addUpdate fills in m.Update if an updated version is available. +func addUpdate(m *modinfo.ModulePublic) { + if m.Version != "" { + if info, err := Query(m.Path, "latest", Allowed); err == nil && info.Version != m.Version { + m.Update = &modinfo.ModulePublic{ + Path: m.Path, + Version: info.Version, + Time: &info.Time, + } + } + } +} + +// addVersions fills in m.Versions with the list of known versions. +func addVersions(m *modinfo.ModulePublic) { + m.Versions, _ = versions(m.Path) +} + +func moduleInfo(m module.Version, fromBuildList bool) *modinfo.ModulePublic { + if m == Target { + info := &modinfo.ModulePublic{ + Path: m.Path, + Version: m.Version, + Main: true, + Dir: ModRoot, + GoMod: filepath.Join(ModRoot, "go.mod"), + } + if modFile.Go != nil { + info.GoVersion = modFile.Go.Version + } + return info + } + + info := &modinfo.ModulePublic{ + Path: m.Path, + Version: m.Version, + Indirect: fromBuildList && loaded != nil && !loaded.direct[m.Path], + } + if loaded != nil { + info.GoVersion = loaded.goVersion[m.Path] + } + + if cfg.BuildMod == "vendor" { + info.Dir = filepath.Join(ModRoot, "vendor", m.Path) + return info + } + + // complete fills in the extra fields in m. + complete := func(m *modinfo.ModulePublic) { + if m.Version != "" { + if q, err := Query(m.Path, m.Version, nil); err != nil { + m.Error = &modinfo.ModuleError{Err: err.Error()} + } else { + m.Version = q.Version + m.Time = &q.Time + } + + mod := module.Version{Path: m.Path, Version: m.Version} + gomod, err := modfetch.CachePath(mod, "mod") + if err == nil { + if info, err := os.Stat(gomod); err == nil && info.Mode().IsRegular() { + m.GoMod = gomod + } + } + dir, err := modfetch.DownloadDir(mod) + if err == nil { + if info, err := os.Stat(dir); err == nil && info.IsDir() { + m.Dir = dir + } + } + } + if cfg.BuildMod == "vendor" { + m.Dir = filepath.Join(ModRoot, "vendor", m.Path) + } + } + + complete(info) + + if fromBuildList { + if r := Replacement(m); r.Path != "" { + info.Replace = &modinfo.ModulePublic{ + Path: r.Path, + Version: r.Version, + GoVersion: info.GoVersion, + } + if r.Version == "" { + if filepath.IsAbs(r.Path) { + info.Replace.Dir = r.Path + } else { + info.Replace.Dir = filepath.Join(ModRoot, r.Path) + } + } + complete(info.Replace) + info.Dir = info.Replace.Dir + info.GoMod = filepath.Join(info.Dir, "go.mod") + info.Error = nil // ignore error loading original module version (it has been replaced) + } + } + + return info +} + +func PackageBuildInfo(path string, deps []string) string { + if isStandardImportPath(path) || !Enabled() { + return "" + } + target := findModule(path, path) + mdeps := make(map[module.Version]bool) + for _, dep := range deps { + if !isStandardImportPath(dep) { + mdeps[findModule(path, dep)] = true + } + } + var mods []module.Version + delete(mdeps, target) + for mod := range mdeps { + mods = append(mods, mod) + } + module.Sort(mods) + + var buf bytes.Buffer + fmt.Fprintf(&buf, "path\t%s\n", path) + tv := target.Version + if tv == "" { + tv = "(devel)" + } + fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, modfetch.Sum(target)) + for _, mod := range mods { + mv := mod.Version + if mv == "" { + mv = "(devel)" + } + r := Replacement(mod) + h := "" + if r.Path == "" { + h = "\t" + modfetch.Sum(mod) + } + fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h) + if r.Path != "" { + fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r)) + } + } + return buf.String() +} + +func findModule(target, path string) module.Version { + // TODO: This should use loaded. + if path == "." { + return buildList[0] + } + for _, mod := range buildList { + if maybeInModule(path, mod.Path) { + return mod + } + } + base.Fatalf("build %v: cannot find module for path %v", target, path) + panic("unreachable") +} + +func ModInfoProg(info string) []byte { + return []byte(fmt.Sprintf(` + package main + import _ "unsafe" + //go:linkname __debug_modinfo__ runtime/debug.modinfo + var __debug_modinfo__ string + func init() { + __debug_modinfo__ = %q + } + `, string(infoStart)+info+string(infoEnd))) +} diff --git a/src/cmd/go/internal/modload/help.go b/src/cmd/go/internal/modload/help.go new file mode 100644 index 0000000000..f2f3419724 --- /dev/null +++ b/src/cmd/go/internal/modload/help.go @@ -0,0 +1,462 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import "cmd/go/internal/base" + +// TODO(rsc): The "module code layout" section needs to be written. + +var HelpModules = &base.Command{ + UsageLine: "modules", + Short: "modules, module versions, and more", + Long: ` +A module is a collection of related Go packages. +Modules are the unit of source code interchange and versioning. +The go command has direct support for working with modules, +including recording and resolving dependencies on other modules. +Modules replace the old GOPATH-based approach to specifying +which source files are used in a given build. + +Preliminary module support + +Go 1.11 includes preliminary support for Go modules, +including a new module-aware 'go get' command. +We intend to keep revising this support, while preserving compatibility, +until it can be declared official (no longer preliminary), +and then at a later point we may remove support for work +in GOPATH and the old 'go get' command. + +The quickest way to take advantage of the new Go 1.11 module support +is to check out your repository into a directory outside GOPATH/src, +create a go.mod file (described in the next section) there, and run +go commands from within that file tree. + +For more fine-grained control, the module support in Go 1.11 respects +a temporary environment variable, GO111MODULE, which can be set to one +of three string values: off, on, or auto (the default). +If GO111MODULE=off, then the go command never uses the +new module support. Instead it looks in vendor directories and GOPATH +to find dependencies; we now refer to this as "GOPATH mode." +If GO111MODULE=on, then the go command requires the use of modules, +never consulting GOPATH. We refer to this as the command being +module-aware or running in "module-aware mode". +If GO111MODULE=auto or is unset, then the go command enables or +disables module support based on the current directory. +Module support is enabled only when the current directory is outside +GOPATH/src and itself contains a go.mod file or is below a directory +containing a go.mod file. + +In module-aware mode, GOPATH no longer defines the meaning of imports +during a build, but it still stores downloaded dependencies (in GOPATH/pkg/mod) +and installed commands (in GOPATH/bin, unless GOBIN is set). + +Defining a module + +A module is defined by a tree of Go source files with a go.mod file +in the tree's root directory. The directory containing the go.mod file +is called the module root. Typically the module root will also correspond +to a source code repository root (but in general it need not). +The module is the set of all Go packages in the module root and its +subdirectories, but excluding subtrees with their own go.mod files. + +The "module path" is the import path prefix corresponding to the module root. +The go.mod file defines the module path and lists the specific versions +of other modules that should be used when resolving imports during a build, +by giving their module paths and versions. + +For example, this go.mod declares that the directory containing it is the root +of the module with path example.com/m, and it also declares that the module +depends on specific versions of golang.org/x/text and gopkg.in/yaml.v2: + + module example.com/m + + require ( + golang.org/x/text v0.3.0 + gopkg.in/yaml.v2 v2.1.0 + ) + +The go.mod file can also specify replacements and excluded versions +that only apply when building the module directly; they are ignored +when the module is incorporated into a larger build. +For more about the go.mod file, see 'go help go.mod'. + +To start a new module, simply create a go.mod file in the root of the +module's directory tree, containing only a module statement. +The 'go mod init' command can be used to do this: + + go mod init example.com/m + +In a project already using an existing dependency management tool like +godep, glide, or dep, 'go mod init' will also add require statements +matching the existing configuration. + +Once the go.mod file exists, no additional steps are required: +go commands like 'go build', 'go test', or even 'go list' will automatically +add new dependencies as needed to satisfy imports. + +The main module and the build list + +The "main module" is the module containing the directory where the go command +is run. The go command finds the module root by looking for a go.mod in the +current directory, or else the current directory's parent directory, +or else the parent's parent directory, and so on. + +The main module's go.mod file defines the precise set of packages available +for use by the go command, through require, replace, and exclude statements. +Dependency modules, found by following require statements, also contribute +to the definition of that set of packages, but only through their go.mod +files' require statements: any replace and exclude statements in dependency +modules are ignored. The replace and exclude statements therefore allow the +main module complete control over its own build, without also being subject +to complete control by dependencies. + +The set of modules providing packages to builds is called the "build list". +The build list initially contains only the main module. Then the go command +adds to the list the exact module versions required by modules already +on the list, recursively, until there is nothing left to add to the list. +If multiple versions of a particular module are added to the list, +then at the end only the latest version (according to semantic version +ordering) is kept for use in the build. + +The 'go list' command provides information about the main module +and the build list. For example: + + go list -m # print path of main module + go list -m -f={{.Dir}} # print root directory of main module + go list -m all # print build list + +Maintaining module requirements + +The go.mod file is meant to be readable and editable by both +programmers and tools. The go command itself automatically updates the go.mod file +to maintain a standard formatting and the accuracy of require statements. + +Any go command that finds an unfamiliar import will look up the module +containing that import and add the latest version of that module +to go.mod automatically. In most cases, therefore, it suffices to +add an import to source code and run 'go build', 'go test', or even 'go list': +as part of analyzing the package, the go command will discover +and resolve the import and update the go.mod file. + +Any go command can determine that a module requirement is +missing and must be added, even when considering only a single +package from the module. On the other hand, determining that a module requirement +is no longer necessary and can be deleted requires a full view of +all packages in the module, across all possible build configurations +(architectures, operating systems, build tags, and so on). +The 'go mod tidy' command builds that view and then +adds any missing module requirements and removes unnecessary ones. + +As part of maintaining the require statements in go.mod, the go command +tracks which ones provide packages imported directly by the current module +and which ones provide packages only used indirectly by other module +dependencies. Requirements needed only for indirect uses are marked with a +"// indirect" comment in the go.mod file. Indirect requirements are +automatically removed from the go.mod file once they are implied by other +direct requirements. Indirect requirements only arise when using modules +that fail to state some of their own dependencies or when explicitly +upgrading a module's dependencies ahead of its own stated requirements. + +Because of this automatic maintenance, the information in go.mod is an +up-to-date, readable description of the build. + +The 'go get' command updates go.mod to change the module versions used in a +build. An upgrade of one module may imply upgrading others, and similarly a +downgrade of one module may imply downgrading others. The 'go get' command +makes these implied changes as well. If go.mod is edited directly, commands +like 'go build' or 'go list' will assume that an upgrade is intended and +automatically make any implied upgrades and update go.mod to reflect them. + +The 'go mod' command provides other functionality for use in maintaining +and understanding modules and go.mod files. See 'go help mod'. + +The -mod build flag provides additional control over updating and use of go.mod. + +If invoked with -mod=readonly, the go command is disallowed from the implicit +automatic updating of go.mod described above. Instead, it fails when any changes +to go.mod are needed. This setting is most useful to check that go.mod does +not need updates, such as in a continuous integration and testing system. +The "go get" command remains permitted to update go.mod even with -mod=readonly, +and the "go mod" commands do not take the -mod flag (or any other build flags). + +If invoked with -mod=vendor, the go command assumes that the vendor +directory holds the correct copies of dependencies and ignores +the dependency descriptions in go.mod. + +Pseudo-versions + +The go.mod file and the go command more generally use semantic versions as +the standard form for describing module versions, so that versions can be +compared to determine which should be considered earlier or later than another. +A module version like v1.2.3 is introduced by tagging a revision in the +underlying source repository. Untagged revisions can be referred to +using a "pseudo-version" like v0.0.0-yyyymmddhhmmss-abcdefabcdef, +where the time is the commit time in UTC and the final suffix is the prefix +of the commit hash. The time portion ensures that two pseudo-versions can +be compared to determine which happened later, the commit hash identifes +the underlying commit, and the prefix (v0.0.0- in this example) is derived from +the most recent tagged version in the commit graph before this commit. + +There are three pseudo-version forms: + +vX.0.0-yyyymmddhhmmss-abcdefabcdef is used when there is no earlier +versioned commit with an appropriate major version before the target commit. +(This was originally the only form, so some older go.mod files use this form +even for commits that do follow tags.) + +vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef is used when the most +recent versioned commit before the target commit is vX.Y.Z-pre. + +vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef is used when the most +recent versioned commit before the target commit is vX.Y.Z. + +Pseudo-versions never need to be typed by hand: the go command will accept +the plain commit hash and translate it into a pseudo-version (or a tagged +version if available) automatically. This conversion is an example of a +module query. + +Module queries + +The go command accepts a "module query" in place of a module version +both on the command line and in the main module's go.mod file. +(After evaluating a query found in the main module's go.mod file, +the go command updates the file to replace the query with its result.) + +A fully-specified semantic version, such as "v1.2.3", +evaluates to that specific version. + +A semantic version prefix, such as "v1" or "v1.2", +evaluates to the latest available tagged version with that prefix. + +A semantic version comparison, such as "=v1.5.6", +evaluates to the available tagged version nearest to the comparison target +(the latest version for < and <=, the earliest version for > and >=). + +The string "latest" matches the latest available tagged version, +or else the underlying source repository's latest untagged revision. + +A revision identifier for the underlying source repository, +such as a commit hash prefix, revision tag, or branch name, +selects that specific code revision. If the revision is +also tagged with a semantic version, the query evaluates to +that semantic version. Otherwise the query evaluates to a +pseudo-version for the commit. + +All queries prefer release versions to pre-release versions. +For example, " good/thing v1.4.5 + +The verbs are module, to define the module path; require, to require +a particular module at a given version or later; exclude, to exclude +a particular module version from use; and replace, to replace a module +version with a different module version. Exclude and replace apply only +in the main module's go.mod and are ignored in dependencies. +See https://research.swtch.com/vgo-mvs for details. + +The leading verb can be factored out of adjacent lines to create a block, +like in Go imports: + + require ( + new/thing v2.3.4 + old/thing v1.2.3 + ) + +The go.mod file is designed both to be edited directly and to be +easily updated by tools. The 'go mod edit' command can be used to +parse and edit the go.mod file from programs and tools. +See 'go help mod edit'. + +The go command automatically updates go.mod each time it uses the +module graph, to make sure go.mod always accurately reflects reality +and is properly formatted. For example, consider this go.mod file: + + module M + + require ( + A v1 + B v1.0.0 + C v1.0.0 + D v1.2.3 + E dev + ) + + exclude D v1.2.3 + +The update rewrites non-canonical version identifiers to semver form, +so A's v1 becomes v1.0.0 and E's dev becomes the pseudo-version for the +latest commit on the dev branch, perhaps v0.0.0-20180523231146-b3f5c0f6e5f1. + +The update modifies requirements to respect exclusions, so the +requirement on the excluded D v1.2.3 is updated to use the next +available version of D, perhaps D v1.2.4 or D v1.3.0. + +The update removes redundant or misleading requirements. +For example, if A v1.0.0 itself requires B v1.2.0 and C v1.0.0, +then go.mod's requirement of B v1.0.0 is misleading (superseded by +A's need for v1.2.0), and its requirement of C v1.0.0 is redundant +(implied by A's need for the same version), so both will be removed. +If module M contains packages that directly import packages from B or +C, then the requirements will be kept but updated to the actual +versions being used. + +Finally, the update reformats the go.mod in a canonical formatting, so +that future mechanical changes will result in minimal diffs. + +Because the module graph defines the meaning of import statements, any +commands that load packages also use and therefore update go.mod, +including go build, go get, go install, go list, go test, go mod graph, +go mod tidy, and go mod why. + `, +} diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go new file mode 100644 index 0000000000..12d9407f6e --- /dev/null +++ b/src/cmd/go/internal/modload/import.go @@ -0,0 +1,227 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "bytes" + "errors" + "fmt" + "go/build" + "os" + "path/filepath" + "strings" + + "cmd/go/internal/cfg" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" + "cmd/go/internal/par" + "cmd/go/internal/search" +) + +type ImportMissingError struct { + ImportPath string + Module module.Version +} + +func (e *ImportMissingError) Error() string { + if e.Module.Path == "" { + return "cannot find module providing package " + e.ImportPath + } + return "missing module for import: " + e.Module.Path + "@" + e.Module.Version + " provides " + e.ImportPath +} + +// Import finds the module and directory in the build list +// containing the package with the given import path. +// The answer must be unique: Import returns an error +// if multiple modules attempt to provide the same package. +// Import can return a module with an empty m.Path, for packages in the standard library. +// Import can return an empty directory string, for fake packages like "C" and "unsafe". +// +// If the package cannot be found in the current build list, +// Import returns an ImportMissingError as the error. +// If Import can identify a module that could be added to supply the package, +// the ImportMissingError records that module. +func Import(path string) (m module.Version, dir string, err error) { + if strings.Contains(path, "@") { + return module.Version{}, "", fmt.Errorf("import path should not have @version") + } + if build.IsLocalImport(path) { + return module.Version{}, "", fmt.Errorf("relative import not supported") + } + if path == "C" || path == "unsafe" { + // There's no directory for import "C" or import "unsafe". + return module.Version{}, "", nil + } + + // Is the package in the standard library? + if search.IsStandardImportPath(path) { + if strings.HasPrefix(path, "golang_org/") { + return module.Version{}, filepath.Join(cfg.GOROOT, "src/vendor", path), nil + } + dir := filepath.Join(cfg.GOROOT, "src", path) + if _, err := os.Stat(dir); err == nil { + return module.Version{}, dir, nil + } + } + + // -mod=vendor is special. + // Everything must be in the main module or the main module's vendor directory. + if cfg.BuildMod == "vendor" { + mainDir, mainOK := dirInModule(path, Target.Path, ModRoot, true) + vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot, "vendor"), false) + if mainOK && vendorOK { + return module.Version{}, "", fmt.Errorf("ambiguous import: found %s in multiple directories:\n\t%s\n\t%s", path, mainDir, vendorDir) + } + // Prefer to return main directory if there is one, + // Note that we're not checking that the package exists. + // We'll leave that for load. + if !vendorOK && mainDir != "" { + return Target, mainDir, nil + } + readVendorList() + return vendorMap[path], vendorDir, nil + } + + // Check each module on the build list. + var dirs []string + var mods []module.Version + for _, m := range buildList { + if !maybeInModule(path, m.Path) { + // Avoid possibly downloading irrelevant modules. + continue + } + root, isLocal, err := fetch(m) + if err != nil { + // Report fetch error. + // Note that we don't know for sure this module is necessary, + // but it certainly _could_ provide the package, and even if we + // continue the loop and find the package in some other module, + // we need to look at this module to make sure the import is + // not ambiguous. + return module.Version{}, "", err + } + dir, ok := dirInModule(path, m.Path, root, isLocal) + if ok { + mods = append(mods, m) + dirs = append(dirs, dir) + } + } + if len(mods) == 1 { + return mods[0], dirs[0], nil + } + if len(mods) > 0 { + var buf bytes.Buffer + fmt.Fprintf(&buf, "ambiguous import: found %s in multiple modules:", path) + for i, m := range mods { + fmt.Fprintf(&buf, "\n\t%s", m.Path) + if m.Version != "" { + fmt.Fprintf(&buf, " %s", m.Version) + } + fmt.Fprintf(&buf, " (%s)", dirs[i]) + } + return module.Version{}, "", errors.New(buf.String()) + } + + // Not on build list. + + // Look up module containing the package, for addition to the build list. + // Goal is to determine the module, download it to dir, and return m, dir, ErrMissing. + if cfg.BuildMod == "readonly" { + return module.Version{}, "", fmt.Errorf("import lookup disabled by -mod=%s", cfg.BuildMod) + } + + m, _, err = QueryPackage(path, "latest", Allowed) + if err != nil { + if _, ok := err.(*codehost.VCSError); ok { + return module.Version{}, "", err + } + return module.Version{}, "", &ImportMissingError{ImportPath: path} + } + return m, "", &ImportMissingError{ImportPath: path, Module: m} +} + +// maybeInModule reports whether, syntactically, +// a package with the given import path could be supplied +// by a module with the given module path (mpath). +func maybeInModule(path, mpath string) bool { + return mpath == path || + len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath +} + +var haveGoModCache, haveGoFilesCache par.Cache + +// dirInModule locates the directory that would hold the package named by the given path, +// if it were in the module with module path mpath and root mdir. +// If path is syntactically not within mpath, +// or if mdir is a local file tree (isLocal == true) and the directory +// that would hold path is in a sub-module (covered by a go.mod below mdir), +// dirInModule returns "", false. +// +// Otherwise, dirInModule returns the name of the directory where +// Go source files would be expected, along with a boolean indicating +// whether there are in fact Go source files in that directory. +func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool) { + // Determine where to expect the package. + if path == mpath { + dir = mdir + } else if mpath == "" { // vendor directory + dir = filepath.Join(mdir, path) + } else if len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath { + dir = filepath.Join(mdir, path[len(mpath)+1:]) + } else { + return "", false + } + + // Check that there aren't other modules in the way. + // This check is unnecessary inside the module cache + // and important to skip in the vendor directory, + // where all the module trees have been overlaid. + // So we only check local module trees + // (the main module, and any directory trees pointed at by replace directives). + if isLocal { + for d := dir; d != mdir && len(d) > len(mdir); { + haveGoMod := haveGoModCache.Do(d, func() interface{} { + _, err := os.Stat(filepath.Join(d, "go.mod")) + return err == nil + }).(bool) + + if haveGoMod { + return "", false + } + parent := filepath.Dir(d) + if parent == d { + // Break the loop, as otherwise we'd loop + // forever if d=="." and mdir=="". + break + } + d = parent + } + } + + // Now committed to returning dir (not ""). + + // Are there Go source files in the directory? + // We don't care about build tags, not even "+build ignore". + // We're just looking for a plausible directory. + haveGoFiles = haveGoFilesCache.Do(dir, func() interface{} { + f, err := os.Open(dir) + if err != nil { + return false + } + defer f.Close() + names, _ := f.Readdirnames(-1) + for _, name := range names { + if strings.HasSuffix(name, ".go") { + info, err := os.Stat(filepath.Join(dir, name)) + if err == nil && info.Mode().IsRegular() { + return true + } + } + } + return false + }).(bool) + + return dir, haveGoFiles +} diff --git a/src/cmd/go/internal/modload/import_test.go b/src/cmd/go/internal/modload/import_test.go new file mode 100644 index 0000000000..3f4ddab436 --- /dev/null +++ b/src/cmd/go/internal/modload/import_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "internal/testenv" + "regexp" + "strings" + "testing" +) + +var importTests = []struct { + path string + err string +}{ + { + path: "golang.org/x/net/context", + err: "missing module for import: golang.org/x/net@.* provides golang.org/x/net/context", + }, + { + path: "golang.org/x/net", + err: "cannot find module providing package golang.org/x/net", + }, + { + path: "golang.org/x/text", + err: "missing module for import: golang.org/x/text@.* provides golang.org/x/text", + }, + { + path: "github.com/rsc/quote/buggy", + err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote/buggy", + }, + { + path: "github.com/rsc/quote", + err: "missing module for import: github.com/rsc/quote@v1.5.2 provides github.com/rsc/quote", + }, + { + path: "golang.org/x/foo/bar", + err: "cannot find module providing package golang.org/x/foo/bar", + }, +} + +func TestImport(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + for _, tt := range importTests { + t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) { + // Note that there is no build list, so Import should always fail. + m, dir, err := Import(tt.path) + if err == nil { + t.Fatalf("Import(%q) = %v, %v, nil; expected error", tt.path, m, dir) + } + if !regexp.MustCompile(tt.err).MatchString(err.Error()) { + t.Fatalf("Import(%q): error %q, want error matching %#q", tt.path, err, tt.err) + } + }) + } +} diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go new file mode 100644 index 0000000000..2bab3eede1 --- /dev/null +++ b/src/cmd/go/internal/modload/init.go @@ -0,0 +1,601 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "bytes" + "cmd/go/internal/base" + "cmd/go/internal/cache" + "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/go/internal/modconv" + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/modfile" + "cmd/go/internal/module" + "cmd/go/internal/mvs" + "cmd/go/internal/search" + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" +) + +var ( + cwd string + MustUseModules = mustUseModules() + initialized bool + + ModRoot string + modFile *modfile.File + excluded map[module.Version]bool + Target module.Version + + gopath string + + CmdModInit bool // running 'go mod init' + CmdModModule string // module argument for 'go mod init' +) + +// ModFile returns the parsed go.mod file. +// +// Note that after calling ImportPaths or LoadBuildList, +// the require statements in the modfile.File are no longer +// the source of truth and will be ignored: edits made directly +// will be lost at the next call to WriteGoMod. +// To make permanent changes to the require statements +// in go.mod, edit it before calling ImportPaths or LoadBuildList. +func ModFile() *modfile.File { + return modFile +} + +func BinDir() string { + MustInit() + return filepath.Join(gopath, "bin") +} + +// mustUseModules reports whether we are invoked as vgo +// (as opposed to go). +// If so, we only support builds with go.mod files. +func mustUseModules() bool { + name := os.Args[0] + name = name[strings.LastIndex(name, "/")+1:] + name = name[strings.LastIndex(name, `\`)+1:] + return strings.HasPrefix(name, "vgo") +} + +var inGOPATH bool // running in GOPATH/src + +func Init() { + if initialized { + return + } + initialized = true + + env := os.Getenv("GO111MODULE") + switch env { + default: + base.Fatalf("go: unknown environment setting GO111MODULE=%s", env) + case "", "auto": + // leave MustUseModules alone + case "on": + MustUseModules = true + case "off": + if !MustUseModules { + return + } + } + + // Disable any prompting for passwords by Git. + // Only has an effect for 2.3.0 or later, but avoiding + // the prompt in earlier versions is just too hard. + // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep + // prompting. + // See golang.org/issue/9341 and golang.org/issue/12706. + if os.Getenv("GIT_TERMINAL_PROMPT") == "" { + os.Setenv("GIT_TERMINAL_PROMPT", "0") + } + + // Disable any ssh connection pooling by Git. + // If a Git subprocess forks a child into the background to cache a new connection, + // that child keeps stdout/stderr open. After the Git subprocess exits, + // os /exec expects to be able to read from the stdout/stderr pipe + // until EOF to get all the data that the Git subprocess wrote before exiting. + // The EOF doesn't come until the child exits too, because the child + // is holding the write end of the pipe. + // This is unfortunate, but it has come up at least twice + // (see golang.org/issue/13453 and golang.org/issue/16104) + // and confuses users when it does. + // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, + // assume they know what they are doing and don't step on it. + // But default to turning off ControlMaster. + if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { + os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no") + } + + var err error + cwd, err = os.Getwd() + if err != nil { + base.Fatalf("go: %v", err) + } + + inGOPATH = false + for _, gopath := range filepath.SplitList(cfg.BuildContext.GOPATH) { + if gopath == "" { + continue + } + if search.InDir(cwd, filepath.Join(gopath, "src")) != "" { + inGOPATH = true + break + } + } + + if inGOPATH && !MustUseModules { + // No automatic enabling in GOPATH. + if root, _ := FindModuleRoot(cwd, "", false); root != "" { + cfg.GoModInGOPATH = filepath.Join(root, "go.mod") + } + return + } + + if CmdModInit { + // Running 'go mod init': go.mod will be created in current directory. + ModRoot = cwd + } else { + ModRoot, _ = FindModuleRoot(cwd, "", MustUseModules) + if !MustUseModules { + if ModRoot == "" { + return + } + if search.InDir(ModRoot, os.TempDir()) == "." { + // If you create /tmp/go.mod for experimenting, + // then any tests that create work directories under /tmp + // will find it and get modules when they're not expecting them. + // It's a bit of a peculiar thing to disallow but quite mysterious + // when it happens. See golang.org/issue/26708. + ModRoot = "" + fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir()) + return + } + } + } + + cfg.ModulesEnabled = true + load.ModBinDir = BinDir + load.ModLookup = Lookup + load.ModPackageModuleInfo = PackageModuleInfo + load.ModImportPaths = ImportPaths + load.ModPackageBuildInfo = PackageBuildInfo + load.ModInfoProg = ModInfoProg + load.ModImportFromFiles = ImportFromFiles + load.ModDirImportPath = DirImportPath + + search.SetModRoot(ModRoot) +} + +func init() { + load.ModInit = Init + + // Set modfetch.PkgMod unconditionally, so that go clean -modcache can run even without modules enabled. + if list := filepath.SplitList(cfg.BuildContext.GOPATH); len(list) > 0 && list[0] != "" { + modfetch.PkgMod = filepath.Join(list[0], "pkg/mod") + } +} + +// Enabled reports whether modules are (or must be) enabled. +// If modules must be enabled but are not, Enabled returns true +// and then the first use of module information will call die +// (usually through InitMod and MustInit). +func Enabled() bool { + if !initialized { + panic("go: Enabled called before Init") + } + return ModRoot != "" || MustUseModules +} + +// MustInit calls Init if needed and checks that +// modules are enabled and the main module has been found. +// If not, MustInit calls base.Fatalf with an appropriate message. +func MustInit() { + if Init(); ModRoot == "" { + die() + } + if c := cache.Default(); c == nil { + // With modules, there are no install locations for packages + // other than the build cache. + base.Fatalf("go: cannot use modules with build cache disabled") + } +} + +// Failed reports whether module loading failed. +// If Failed returns true, then any use of module information will call die. +func Failed() bool { + Init() + return cfg.ModulesEnabled && ModRoot == "" +} + +func die() { + if os.Getenv("GO111MODULE") == "off" { + base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") + } + if inGOPATH && !MustUseModules { + base.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'") + } + base.Fatalf("go: cannot find main module; see 'go help modules'") +} + +func InitMod() { + MustInit() + if modFile != nil { + return + } + + list := filepath.SplitList(cfg.BuildContext.GOPATH) + if len(list) == 0 || list[0] == "" { + base.Fatalf("missing $GOPATH") + } + gopath = list[0] + if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil { + base.Fatalf("$GOPATH/go.mod exists but should not") + } + + oldSrcMod := filepath.Join(list[0], "src/mod") + pkgMod := filepath.Join(list[0], "pkg/mod") + infoOld, errOld := os.Stat(oldSrcMod) + _, errMod := os.Stat(pkgMod) + if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) { + os.Rename(oldSrcMod, pkgMod) + } + + modfetch.PkgMod = pkgMod + modfetch.GoSumFile = filepath.Join(ModRoot, "go.sum") + codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs") + + if CmdModInit { + // Running go mod init: do legacy module conversion + legacyModInit() + modFileToBuildList() + WriteGoMod() + return + } + + gomod := filepath.Join(ModRoot, "go.mod") + data, err := ioutil.ReadFile(gomod) + if err != nil { + if os.IsNotExist(err) { + legacyModInit() + modFileToBuildList() + WriteGoMod() + return + } + base.Fatalf("go: %v", err) + } + + f, err := modfile.Parse(gomod, data, fixVersion) + if err != nil { + // Errors returned by modfile.Parse begin with file:line. + base.Fatalf("go: errors parsing go.mod:\n%s\n", err) + } + modFile = f + + if len(f.Syntax.Stmt) == 0 || f.Module == nil { + // Empty mod file. Must add module path. + path, err := FindModulePath(ModRoot) + if err != nil { + base.Fatalf("go: %v", err) + } + f.AddModuleStmt(path) + } + + if len(f.Syntax.Stmt) == 1 && f.Module != nil { + // Entire file is just a module statement. + // Populate require if possible. + legacyModInit() + } + + excluded = make(map[module.Version]bool) + for _, x := range f.Exclude { + excluded[x.Mod] = true + } + modFileToBuildList() + WriteGoMod() +} + +// modFileToBuildList initializes buildList from the modFile. +func modFileToBuildList() { + Target = modFile.Module.Mod + list := []module.Version{Target} + for _, r := range modFile.Require { + list = append(list, r.Mod) + } + buildList = list +} + +// Allowed reports whether module m is allowed (not excluded) by the main module's go.mod. +func Allowed(m module.Version) bool { + return !excluded[m] +} + +func legacyModInit() { + if modFile == nil { + path, err := FindModulePath(ModRoot) + if err != nil { + base.Fatalf("go: %v", err) + } + fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", path) + modFile = new(modfile.File) + modFile.AddModuleStmt(path) + } + + for _, name := range altConfigs { + cfg := filepath.Join(ModRoot, name) + data, err := ioutil.ReadFile(cfg) + if err == nil { + convert := modconv.Converters[name] + if convert == nil { + return + } + fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(cfg)) + cfg = filepath.ToSlash(cfg) + if err := modconv.ConvertLegacyConfig(modFile, cfg, data); err != nil { + base.Fatalf("go: %v", err) + } + if len(modFile.Syntax.Stmt) == 1 { + // Add comment to avoid re-converting every time it runs. + modFile.AddComment("// go: no requirements found in " + name) + } + return + } + } +} + +var altConfigs = []string{ + "Gopkg.lock", + + "GLOCKFILE", + "Godeps/Godeps.json", + "dependencies.tsv", + "glide.lock", + "vendor.conf", + "vendor.yml", + "vendor/manifest", + "vendor/vendor.json", + + ".git/config", +} + +// Exported only for testing. +func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) { + dir = filepath.Clean(dir) + dir1 := dir + limit = filepath.Clean(limit) + + // Look for enclosing go.mod. + for { + if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !(runtime.GOOS == "plan9" && fi.IsDir()) { + return dir, "go.mod" + } + if dir == limit { + break + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + + // Failing that, look for enclosing alternate version config. + if legacyConfigOK { + dir = dir1 + for { + for _, name := range altConfigs { + if fi, err := os.Stat(filepath.Join(dir, name)); err == nil && !(runtime.GOOS == "plan9" && fi.IsDir()) { + return dir, name + } + } + if dir == limit { + break + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + } + + return "", "" +} + +// Exported only for testing. +func FindModulePath(dir string) (string, error) { + if CmdModModule != "" { + // Running go mod init x/y/z; return x/y/z. + return CmdModModule, nil + } + + // Cast about for import comments, + // first in top-level directory, then in subdirectories. + list, _ := ioutil.ReadDir(dir) + for _, info := range list { + if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") { + if com := findImportComment(filepath.Join(dir, info.Name())); com != "" { + return com, nil + } + } + } + for _, info1 := range list { + if info1.IsDir() { + files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name())) + for _, info2 := range files { + if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") { + if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" { + return path.Dir(com), nil + } + } + } + } + } + + // Look for Godeps.json declaring import path. + data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json")) + var cfg1 struct{ ImportPath string } + json.Unmarshal(data, &cfg1) + if cfg1.ImportPath != "" { + return cfg1.ImportPath, nil + } + + // Look for vendor.json declaring import path. + data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json")) + var cfg2 struct{ RootPath string } + json.Unmarshal(data, &cfg2) + if cfg2.RootPath != "" { + return cfg2.RootPath, nil + } + + // Look for path in GOPATH. + for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) { + if gpdir == "" { + continue + } + if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." { + return filepath.ToSlash(rel), nil + } + } + + // Look for .git/config with github origin as last resort. + data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config")) + if m := gitOriginRE.FindSubmatch(data); m != nil { + return "github.com/" + string(m[1]), nil + } + + return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir) +} + +var ( + gitOriginRE = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`) + importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`) +) + +func findImportComment(file string) string { + data, err := ioutil.ReadFile(file) + if err != nil { + return "" + } + m := importCommentRE.FindSubmatch(data) + if m == nil { + return "" + } + path, err := strconv.Unquote(string(m[1])) + if err != nil { + return "" + } + return path +} + +var allowWriteGoMod = true + +// DisallowWriteGoMod causes future calls to WriteGoMod to do nothing at all. +func DisallowWriteGoMod() { + allowWriteGoMod = false +} + +// AllowWriteGoMod undoes the effect of DisallowWriteGoMod: +// future calls to WriteGoMod will update go.mod if needed. +// Note that any past calls have been discarded, so typically +// a call to AlowWriteGoMod should be followed by a call to WriteGoMod. +func AllowWriteGoMod() { + allowWriteGoMod = true +} + +// MinReqs returns a Reqs with minimal dependencies of Target, +// as will be written to go.mod. +func MinReqs() mvs.Reqs { + var direct []string + for _, m := range buildList[1:] { + if loaded.direct[m.Path] { + direct = append(direct, m.Path) + } + } + min, err := mvs.Req(Target, buildList, direct, Reqs()) + if err != nil { + base.Fatalf("go: %v", err) + } + return &mvsReqs{buildList: append([]module.Version{Target}, min...)} +} + +// WriteGoMod writes the current build list back to go.mod. +func WriteGoMod() { + // If we're using -mod=vendor we basically ignored + // go.mod, so definitely don't try to write back our + // incomplete view of the world. + if !allowWriteGoMod || cfg.BuildMod == "vendor" { + return + } + + if loaded != nil { + reqs := MinReqs() + min, err := reqs.Required(Target) + if err != nil { + base.Fatalf("go: %v", err) + } + var list []*modfile.Require + for _, m := range min { + list = append(list, &modfile.Require{ + Mod: m, + Indirect: !loaded.direct[m.Path], + }) + } + modFile.SetRequire(list) + } + + file := filepath.Join(ModRoot, "go.mod") + old, _ := ioutil.ReadFile(file) + modFile.Cleanup() // clean file after edits + new, err := modFile.Format() + if err != nil { + base.Fatalf("go: %v", err) + } + if !bytes.Equal(old, new) { + if cfg.BuildMod == "readonly" { + base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly") + } + if err := ioutil.WriteFile(file, new, 0666); err != nil { + base.Fatalf("go: %v", err) + } + } + modfetch.WriteGoSum() +} + +func fixVersion(path, vers string) (string, error) { + // Special case: remove the old -gopkgin- hack. + if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") { + vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):] + } + + // fixVersion is called speculatively on every + // module, version pair from every go.mod file. + // Avoid the query if it looks OK. + _, pathMajor, ok := module.SplitPathVersion(path) + if !ok { + return "", fmt.Errorf("malformed module path: %s", path) + } + if vers != "" && module.CanonicalVersion(vers) == vers && module.MatchPathMajor(vers, pathMajor) { + return vers, nil + } + + info, err := Query(path, vers, nil) + if err != nil { + return "", err + } + return info.Version, nil +} diff --git a/src/cmd/go/internal/modload/init_plan9_test.go b/src/cmd/go/internal/modload/init_plan9_test.go new file mode 100644 index 0000000000..2df9d8af7d --- /dev/null +++ b/src/cmd/go/internal/modload/init_plan9_test.go @@ -0,0 +1,42 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestFindModuleRootIgnoreDir(t *testing.T) { + // In Plan 9, directories are automatically created in /n. + // For example, /n/go.mod always exist, but it's a directory. + // Test that we ignore directories when trying to find go.mod and other config files. + + dir, err := ioutil.TempDir("", "gotest") + if err != nil { + t.Fatalf("failed to create temporary directory: %v", err) + } + defer os.RemoveAll(dir) + if err := os.Mkdir(filepath.Join(dir, "go.mod"), os.ModeDir|0755); err != nil { + t.Fatalf("Mkdir failed: %v", err) + } + for _, name := range altConfigs { + if err := os.MkdirAll(filepath.Join(dir, name), os.ModeDir|0755); err != nil { + t.Fatalf("MkdirAll failed: %v", err) + } + } + p := filepath.Join(dir, "example") + if err := os.Mkdir(p, os.ModeDir|0755); err != nil { + t.Fatalf("Mkdir failed: %v", err) + } + if root, _ := FindModuleRoot(p, "", false); root != "" { + t.Errorf("FindModuleRoot(%q, \"\", false): %q, want empty string", p, root) + } + if root, _ := FindModuleRoot(p, "", true); root != "" { + t.Errorf("FindModuleRoot(%q, \"\", true): %q, want empty string", p, root) + } +} diff --git a/src/cmd/go/internal/modload/list.go b/src/cmd/go/internal/modload/list.go new file mode 100644 index 0000000000..69a832de1d --- /dev/null +++ b/src/cmd/go/internal/modload/list.go @@ -0,0 +1,109 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "fmt" + "os" + "strings" + + "cmd/go/internal/base" + "cmd/go/internal/modinfo" + "cmd/go/internal/module" + "cmd/go/internal/par" + "cmd/go/internal/search" +) + +func ListModules(args []string, listU, listVersions bool) []*modinfo.ModulePublic { + mods := listModules(args) + if listU || listVersions { + var work par.Work + for _, m := range mods { + work.Add(m) + if m.Replace != nil { + work.Add(m.Replace) + } + } + work.Do(10, func(item interface{}) { + m := item.(*modinfo.ModulePublic) + if listU { + addUpdate(m) + } + if listVersions { + addVersions(m) + } + }) + } + return mods +} + +func listModules(args []string) []*modinfo.ModulePublic { + LoadBuildList() + if len(args) == 0 { + return []*modinfo.ModulePublic{moduleInfo(buildList[0], true)} + } + + var mods []*modinfo.ModulePublic + matchedBuildList := make([]bool, len(buildList)) + for _, arg := range args { + if strings.Contains(arg, `\`) { + base.Fatalf("go: module paths never use backslash") + } + if search.IsRelativePath(arg) { + base.Fatalf("go: cannot use relative path %s to specify module", arg) + } + if i := strings.Index(arg, "@"); i >= 0 { + info, err := Query(arg[:i], arg[i+1:], nil) + if err != nil { + mods = append(mods, &modinfo.ModulePublic{ + Path: arg[:i], + Version: arg[i+1:], + Error: &modinfo.ModuleError{ + Err: err.Error(), + }, + }) + continue + } + mods = append(mods, moduleInfo(module.Version{Path: arg[:i], Version: info.Version}, false)) + continue + } + + // Module path or pattern. + var match func(string) bool + var literal bool + if arg == "all" { + match = func(string) bool { return true } + } else if strings.Contains(arg, "...") { + match = search.MatchPattern(arg) + } else { + match = func(p string) bool { return arg == p } + literal = true + } + matched := false + for i, m := range buildList { + if match(m.Path) { + matched = true + if !matchedBuildList[i] { + matchedBuildList[i] = true + mods = append(mods, moduleInfo(m, true)) + } + } + } + if !matched { + if literal { + mods = append(mods, &modinfo.ModulePublic{ + Path: arg, + Error: &modinfo.ModuleError{ + Err: fmt.Sprintf("module %q is not a known dependency", arg), + }, + }) + } else { + fmt.Fprintf(os.Stderr, "warning: pattern %q matched no module dependencies\n", arg) + } + } + } + + return mods +} diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go new file mode 100644 index 0000000000..6c1525da9a --- /dev/null +++ b/src/cmd/go/internal/modload/load.go @@ -0,0 +1,1067 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "bytes" + "errors" + "fmt" + "go/build" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "strings" + "sync" + + "cmd/go/internal/base" + "cmd/go/internal/cfg" + "cmd/go/internal/imports" + "cmd/go/internal/modfetch" + "cmd/go/internal/modfile" + "cmd/go/internal/module" + "cmd/go/internal/mvs" + "cmd/go/internal/par" + "cmd/go/internal/search" + "cmd/go/internal/semver" + "cmd/go/internal/str" +) + +// buildList is the list of modules to use for building packages. +// It is initialized by calling ImportPaths, ImportFromFiles, +// LoadALL, or LoadBuildList, each of which uses loaded.load. +// +// Ideally, exactly ONE of those functions would be called, +// and exactly once. Most of the time, that's true. +// During "go get" it may not be. TODO(rsc): Figure out if +// that restriction can be established, or else document why not. +// +var buildList []module.Version + +// loaded is the most recently-used package loader. +// It holds details about individual packages. +// +// Note that loaded.buildList is only valid during a load operation; +// afterward, it is copied back into the global buildList, +// which should be used instead. +var loaded *loader + +// ImportPaths returns the set of packages matching the args (patterns), +// adding modules to the build list as needed to satisfy new imports. +func ImportPaths(patterns []string) []*search.Match { + InitMod() + + var matches []*search.Match + for _, pattern := range search.CleanPatterns(patterns) { + m := &search.Match{ + Pattern: pattern, + Literal: !strings.Contains(pattern, "...") && !search.IsMetaPackage(pattern), + } + if m.Literal { + m.Pkgs = []string{pattern} + } + matches = append(matches, m) + } + + fsDirs := make([][]string, len(matches)) + loaded = newLoader() + updateMatches := func(iterating bool) { + for i, m := range matches { + switch { + case build.IsLocalImport(m.Pattern) || filepath.IsAbs(m.Pattern): + // Evaluate list of file system directories on first iteration. + if fsDirs[i] == nil { + var dirs []string + if m.Literal { + dirs = []string{m.Pattern} + } else { + dirs = search.MatchPackagesInFS(m.Pattern).Pkgs + } + fsDirs[i] = dirs + } + + // Make a copy of the directory list and translate to import paths. + // Note that whether a directory corresponds to an import path + // changes as the build list is updated, and a directory can change + // from not being in the build list to being in it and back as + // the exact version of a particular module increases during + // the loader iterations. + m.Pkgs = str.StringList(fsDirs[i]) + for i, pkg := range m.Pkgs { + dir := pkg + if !filepath.IsAbs(dir) { + dir = filepath.Join(cwd, pkg) + } else { + dir = filepath.Clean(dir) + } + + // Note: The checks for @ here are just to avoid misinterpreting + // the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar). + // It's not strictly necessary but helpful to keep the checks. + if dir == ModRoot { + pkg = Target.Path + } else if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) && !strings.Contains(dir[len(ModRoot):], "@") { + suffix := filepath.ToSlash(dir[len(ModRoot):]) + if strings.HasPrefix(suffix, "/vendor/") { + // TODO getmode vendor check + pkg = strings.TrimPrefix(suffix, "/vendor/") + } else { + pkg = Target.Path + suffix + } + } else if sub := search.InDir(dir, cfg.GOROOTsrc); sub != "" && !strings.Contains(sub, "@") { + pkg = filepath.ToSlash(sub) + } else if path := pathInModuleCache(dir); path != "" { + pkg = path + } else { + pkg = "" + if !iterating { + base.Errorf("go: directory %s outside available modules", base.ShortPath(dir)) + } + } + info, err := os.Stat(dir) + if err != nil || !info.IsDir() { + // If the directory does not exist, + // don't turn it into an import path + // that will trigger a lookup. + pkg = "" + if !iterating { + if err != nil { + base.Errorf("go: no such directory %v", m.Pattern) + } else { + base.Errorf("go: %s is not a directory", m.Pattern) + } + } + } + m.Pkgs[i] = pkg + } + + case strings.Contains(m.Pattern, "..."): + m.Pkgs = matchPackages(m.Pattern, loaded.tags, true, buildList) + + case m.Pattern == "all": + loaded.testAll = true + if iterating { + // Enumerate the packages in the main module. + // We'll load the dependencies as we find them. + m.Pkgs = matchPackages("...", loaded.tags, false, []module.Version{Target}) + } else { + // Starting with the packages in the main module, + // enumerate the full list of "all". + m.Pkgs = loaded.computePatternAll(m.Pkgs) + } + + case search.IsMetaPackage(m.Pattern): // std, cmd + if len(m.Pkgs) == 0 { + m.Pkgs = search.MatchPackages(m.Pattern).Pkgs + } + } + } + } + + loaded.load(func() []string { + var roots []string + updateMatches(true) + for _, m := range matches { + for _, pkg := range m.Pkgs { + if pkg != "" { + roots = append(roots, pkg) + } + } + } + return roots + }) + + // One last pass to finalize wildcards. + updateMatches(false) + + // A given module path may be used as itself or as a replacement for another + // module, but not both at the same time. Otherwise, the aliasing behavior is + // too subtle (see https://golang.org/issue/26607), and we don't want to + // commit to a specific behavior at this point. + firstPath := make(map[module.Version]string, len(buildList)) + for _, mod := range buildList { + src := mod + if rep := Replacement(mod); rep.Path != "" { + src = rep + } + if prev, ok := firstPath[src]; !ok { + firstPath[src] = mod.Path + } else if prev != mod.Path { + base.Errorf("go: %s@%s used for two different module paths (%s and %s)", src.Path, src.Version, prev, mod.Path) + } + } + base.ExitIfErrors() + WriteGoMod() + + search.WarnUnmatched(matches) + return matches +} + +// pathInModuleCache returns the import path of the directory dir, +// if dir is in the module cache copy of a module in our build list. +func pathInModuleCache(dir string) string { + for _, m := range buildList[1:] { + root, err := modfetch.DownloadDir(m) + if err != nil { + continue + } + if sub := search.InDir(dir, root); sub != "" { + sub = filepath.ToSlash(sub) + if !strings.Contains(sub, "/vendor/") && !strings.HasPrefix(sub, "vendor/") && !strings.Contains(sub, "@") { + return path.Join(m.Path, filepath.ToSlash(sub)) + } + } + } + return "" +} + +// warnPattern returns list, the result of matching pattern, +// but if list is empty then first it prints a warning about +// the pattern not matching any packages. +func warnPattern(pattern string, list []string) []string { + if len(list) == 0 { + fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) + } + return list +} + +// ImportFromFiles adds modules to the build list as needed +// to satisfy the imports in the named Go source files. +func ImportFromFiles(gofiles []string) { + InitMod() + + imports, testImports, err := imports.ScanFiles(gofiles, imports.Tags()) + if err != nil { + base.Fatalf("go: %v", err) + } + + loaded = newLoader() + loaded.load(func() []string { + var roots []string + roots = append(roots, imports...) + roots = append(roots, testImports...) + return roots + }) + WriteGoMod() +} + +// DirImportPath returns the effective import path for dir, +// provided it is within the main module, or else returns ".". +func DirImportPath(dir string) string { + if !filepath.IsAbs(dir) { + dir = filepath.Join(cwd, dir) + } else { + dir = filepath.Clean(dir) + } + + if dir == ModRoot { + return Target.Path + } + if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) { + suffix := filepath.ToSlash(dir[len(ModRoot):]) + if strings.HasPrefix(suffix, "/vendor/") { + return strings.TrimPrefix(suffix, "/vendor/") + } + return Target.Path + suffix + } + return "." +} + +// LoadBuildList loads and returns the build list from go.mod. +// The loading of the build list happens automatically in ImportPaths: +// LoadBuildList need only be called if ImportPaths is not +// (typically in commands that care about the module but +// no particular package). +func LoadBuildList() []module.Version { + InitMod() + ReloadBuildList() + WriteGoMod() + return buildList +} + +func ReloadBuildList() []module.Version { + loaded = newLoader() + loaded.load(func() []string { return nil }) + return buildList +} + +// LoadALL returns the set of all packages in the current module +// and their dependencies in any other modules, without filtering +// due to build tags, except "+build ignore". +// It adds modules to the build list as needed to satisfy new imports. +// This set is useful for deciding whether a particular import is needed +// anywhere in a module. +func LoadALL() []string { + return loadAll(true) +} + +// LoadVendor is like LoadALL but only follows test dependencies +// for tests in the main module. Tests in dependency modules are +// ignored completely. +// This set is useful for identifying the which packages to include in a vendor directory. +func LoadVendor() []string { + return loadAll(false) +} + +func loadAll(testAll bool) []string { + InitMod() + + loaded = newLoader() + loaded.isALL = true + loaded.tags = anyTags + loaded.testAll = testAll + if !testAll { + loaded.testRoots = true + } + all := TargetPackages() + loaded.load(func() []string { return all }) + WriteGoMod() + + var paths []string + for _, pkg := range loaded.pkgs { + if e, ok := pkg.err.(*ImportMissingError); ok && e.Module.Path == "" { + continue // Package doesn't actually exist. + } + paths = append(paths, pkg.path) + } + return paths +} + +// anyTags is a special tags map that satisfies nearly all build tag expressions. +// Only "ignore" and malformed build tag requirements are considered false. +var anyTags = map[string]bool{"*": true} + +// TargetPackages returns the list of packages in the target (top-level) module, +// under all build tag settings. +func TargetPackages() []string { + return matchPackages("...", anyTags, false, []module.Version{Target}) +} + +// BuildList returns the module build list, +// typically constructed by a previous call to +// LoadBuildList or ImportPaths. +// The caller must not modify the returned list. +func BuildList() []module.Version { + return buildList +} + +// SetBuildList sets the module build list. +// The caller is responsible for ensuring that the list is valid. +// SetBuildList does not retain a reference to the original list. +func SetBuildList(list []module.Version) { + buildList = append([]module.Version{}, list...) +} + +// ImportMap returns the actual package import path +// for an import path found in source code. +// If the given import path does not appear in the source code +// for the packages that have been loaded, ImportMap returns the empty string. +func ImportMap(path string) string { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + return "" + } + return pkg.path +} + +// PackageDir returns the directory containing the source code +// for the package named by the import path. +func PackageDir(path string) string { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + return "" + } + return pkg.dir +} + +// PackageModule returns the module providing the package named by the import path. +func PackageModule(path string) module.Version { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + return module.Version{} + } + return pkg.mod +} + +// ModuleUsedDirectly reports whether the main module directly imports +// some package in the module with the given path. +func ModuleUsedDirectly(path string) bool { + return loaded.direct[path] +} + +// Lookup returns the source directory, import path, and any loading error for +// the package at path. +// Lookup requires that one of the Load functions in this package has already +// been called. +func Lookup(path string) (dir, realPath string, err error) { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + // The loader should have found all the relevant paths. + // There are a few exceptions, though: + // - during go list without -test, the p.Resolve calls to process p.TestImports and p.XTestImports + // end up here to canonicalize the import paths. + // - during any load, non-loaded packages like "unsafe" end up here. + // - during any load, build-injected dependencies like "runtime/cgo" end up here. + // - because we ignore appengine/* in the module loader, + // the dependencies of any actual appengine/* library end up here. + dir := findStandardImportPath(path) + if dir != "" { + return dir, path, nil + } + return "", "", errMissing + } + return pkg.dir, pkg.path, pkg.err +} + +// A loader manages the process of loading information about +// the required packages for a particular build, +// checking that the packages are available in the module set, +// and updating the module set if needed. +// Loading is an iterative process: try to load all the needed packages, +// but if imports are missing, try to resolve those imports, and repeat. +// +// Although most of the loading state is maintained in the loader struct, +// one key piece - the build list - is a global, so that it can be modified +// separate from the loading operation, such as during "go get" +// upgrades/downgrades or in "go mod" operations. +// TODO(rsc): It might be nice to make the loader take and return +// a buildList rather than hard-coding use of the global. +type loader struct { + tags map[string]bool // tags for scanDir + testRoots bool // include tests for roots + isALL bool // created with LoadALL + testAll bool // include tests for all packages + + // reset on each iteration + roots []*loadPkg + pkgs []*loadPkg + work *par.Work // current work queue + pkgCache *par.Cache // map from string to *loadPkg + + // computed at end of iterations + direct map[string]bool // imported directly by main module + goVersion map[string]string // go version recorded in each module +} + +// LoadTests controls whether the loaders load tests of the root packages. +var LoadTests bool + +func newLoader() *loader { + ld := new(loader) + ld.tags = imports.Tags() + ld.testRoots = LoadTests + return ld +} + +func (ld *loader) reset() { + ld.roots = nil + ld.pkgs = nil + ld.work = new(par.Work) + ld.pkgCache = new(par.Cache) +} + +// A loadPkg records information about a single loaded package. +type loadPkg struct { + path string // import path + mod module.Version // module providing package + dir string // directory containing source code + imports []*loadPkg // packages imported by this one + err error // error loading package + stack *loadPkg // package importing this one in minimal import stack for this pkg + test *loadPkg // package with test imports, if we need test + testOf *loadPkg + testImports []string // test-only imports, saved for use by pkg.test. +} + +var errMissing = errors.New("cannot find package") + +// load attempts to load the build graph needed to process a set of root packages. +// The set of root packages is defined by the addRoots function, +// which must call add(path) with the import path of each root package. +func (ld *loader) load(roots func() []string) { + var err error + reqs := Reqs() + buildList, err = mvs.BuildList(Target, reqs) + if err != nil { + base.Fatalf("go: %v", err) + } + + added := make(map[string]bool) + for { + ld.reset() + if roots != nil { + // Note: the returned roots can change on each iteration, + // since the expansion of package patterns depends on the + // build list we're using. + for _, path := range roots() { + ld.work.Add(ld.pkg(path, true)) + } + } + ld.work.Do(10, ld.doPkg) + ld.buildStacks() + numAdded := 0 + haveMod := make(map[module.Version]bool) + for _, m := range buildList { + haveMod[m] = true + } + for _, pkg := range ld.pkgs { + if err, ok := pkg.err.(*ImportMissingError); ok && err.Module.Path != "" { + if added[pkg.path] { + base.Fatalf("go: %s: looping trying to add package", pkg.stackText()) + } + added[pkg.path] = true + numAdded++ + if !haveMod[err.Module] { + haveMod[err.Module] = true + buildList = append(buildList, err.Module) + } + continue + } + // Leave other errors for Import or load.Packages to report. + } + base.ExitIfErrors() + if numAdded == 0 { + break + } + + // Recompute buildList with all our additions. + reqs = Reqs() + buildList, err = mvs.BuildList(Target, reqs) + if err != nil { + base.Fatalf("go: %v", err) + } + } + base.ExitIfErrors() + + // Compute directly referenced dependency modules. + ld.direct = make(map[string]bool) + for _, pkg := range ld.pkgs { + if pkg.mod == Target { + for _, dep := range pkg.imports { + if dep.mod.Path != "" { + ld.direct[dep.mod.Path] = true + } + } + } + } + + // Add Go versions, computed during walk. + ld.goVersion = make(map[string]string) + for _, m := range buildList { + v, _ := reqs.(*mvsReqs).versions.Load(m) + ld.goVersion[m.Path], _ = v.(string) + } + + // Mix in direct markings (really, lack of indirect markings) + // from go.mod, unless we scanned the whole module + // and can therefore be sure we know better than go.mod. + if !ld.isALL && modFile != nil { + for _, r := range modFile.Require { + if !r.Indirect { + ld.direct[r.Mod.Path] = true + } + } + } +} + +// pkg returns the *loadPkg for path, creating and queuing it if needed. +// If the package should be tested, its test is created but not queued +// (the test is queued after processing pkg). +// If isRoot is true, the pkg is being queued as one of the roots of the work graph. +func (ld *loader) pkg(path string, isRoot bool) *loadPkg { + return ld.pkgCache.Do(path, func() interface{} { + pkg := &loadPkg{ + path: path, + } + if ld.testRoots && isRoot || ld.testAll { + test := &loadPkg{ + path: path, + testOf: pkg, + } + pkg.test = test + } + if isRoot { + ld.roots = append(ld.roots, pkg) + } + ld.work.Add(pkg) + return pkg + }).(*loadPkg) +} + +// doPkg processes a package on the work queue. +func (ld *loader) doPkg(item interface{}) { + // TODO: what about replacements? + pkg := item.(*loadPkg) + var imports []string + if pkg.testOf != nil { + pkg.dir = pkg.testOf.dir + pkg.mod = pkg.testOf.mod + imports = pkg.testOf.testImports + } else { + if strings.Contains(pkg.path, "@") { + // Leave for error during load. + return + } + if build.IsLocalImport(pkg.path) { + // Leave for error during load. + // (Module mode does not allow local imports.) + return + } + + pkg.mod, pkg.dir, pkg.err = Import(pkg.path) + if pkg.dir == "" { + return + } + var testImports []string + var err error + imports, testImports, err = scanDir(pkg.dir, ld.tags) + if err != nil { + pkg.err = err + return + } + if pkg.test != nil { + pkg.testImports = testImports + } + } + + for _, path := range imports { + pkg.imports = append(pkg.imports, ld.pkg(path, false)) + } + + // Now that pkg.dir, pkg.mod, pkg.testImports are set, we can queue pkg.test. + // TODO: All that's left is creating new imports. Why not just do it now? + if pkg.test != nil { + ld.work.Add(pkg.test) + } +} + +// computePatternAll returns the list of packages matching pattern "all", +// starting with a list of the import paths for the packages in the main module. +func (ld *loader) computePatternAll(paths []string) []string { + seen := make(map[*loadPkg]bool) + var all []string + var walk func(*loadPkg) + walk = func(pkg *loadPkg) { + if seen[pkg] { + return + } + seen[pkg] = true + if pkg.testOf == nil { + all = append(all, pkg.path) + } + for _, p := range pkg.imports { + walk(p) + } + if p := pkg.test; p != nil { + walk(p) + } + } + for _, path := range paths { + walk(ld.pkg(path, false)) + } + sort.Strings(all) + + return all +} + +// scanDir is like imports.ScanDir but elides known magic imports from the list, +// so that we do not go looking for packages that don't really exist. +// +// The standard magic import is "C", for cgo. +// +// The only other known magic imports are appengine and appengine/*. +// These are so old that they predate "go get" and did not use URL-like paths. +// Most code today now uses google.golang.org/appengine instead, +// but not all code has been so updated. When we mostly ignore build tags +// during "go vendor", we look into "// +build appengine" files and +// may see these legacy imports. We drop them so that the module +// search does not look for modules to try to satisfy them. +func scanDir(dir string, tags map[string]bool) (imports_, testImports []string, err error) { + imports_, testImports, err = imports.ScanDir(dir, tags) + + filter := func(x []string) []string { + w := 0 + for _, pkg := range x { + if pkg != "C" && pkg != "appengine" && !strings.HasPrefix(pkg, "appengine/") && + pkg != "appengine_internal" && !strings.HasPrefix(pkg, "appengine_internal/") { + x[w] = pkg + w++ + } + } + return x[:w] + } + + return filter(imports_), filter(testImports), err +} + +// buildStacks computes minimal import stacks for each package, +// for use in error messages. When it completes, packages that +// are part of the original root set have pkg.stack == nil, +// and other packages have pkg.stack pointing at the next +// package up the import stack in their minimal chain. +// As a side effect, buildStacks also constructs ld.pkgs, +// the list of all packages loaded. +func (ld *loader) buildStacks() { + if len(ld.pkgs) > 0 { + panic("buildStacks") + } + for _, pkg := range ld.roots { + pkg.stack = pkg // sentinel to avoid processing in next loop + ld.pkgs = append(ld.pkgs, pkg) + } + for i := 0; i < len(ld.pkgs); i++ { // not range: appending to ld.pkgs in loop + pkg := ld.pkgs[i] + for _, next := range pkg.imports { + if next.stack == nil { + next.stack = pkg + ld.pkgs = append(ld.pkgs, next) + } + } + if next := pkg.test; next != nil && next.stack == nil { + next.stack = pkg + ld.pkgs = append(ld.pkgs, next) + } + } + for _, pkg := range ld.roots { + pkg.stack = nil + } +} + +// stackText builds the import stack text to use when +// reporting an error in pkg. It has the general form +// +// import root -> +// import other -> +// import other2 -> +// import pkg +// +func (pkg *loadPkg) stackText() string { + var stack []*loadPkg + for p := pkg.stack; p != nil; p = p.stack { + stack = append(stack, p) + } + + var buf bytes.Buffer + for i := len(stack) - 1; i >= 0; i-- { + p := stack[i] + if p.testOf != nil { + fmt.Fprintf(&buf, "test ->\n\t") + } else { + fmt.Fprintf(&buf, "import %q ->\n\t", p.path) + } + } + fmt.Fprintf(&buf, "import %q", pkg.path) + return buf.String() +} + +// why returns the text to use in "go mod why" output about the given package. +// It is less ornate than the stackText but contains the same information. +func (pkg *loadPkg) why() string { + var buf strings.Builder + var stack []*loadPkg + for p := pkg; p != nil; p = p.stack { + stack = append(stack, p) + } + + for i := len(stack) - 1; i >= 0; i-- { + p := stack[i] + if p.testOf != nil { + fmt.Fprintf(&buf, "%s.test\n", p.testOf.path) + } else { + fmt.Fprintf(&buf, "%s\n", p.path) + } + } + return buf.String() +} + +// Why returns the "go mod why" output stanza for the given package, +// without the leading # comment. +// The package graph must have been loaded already, usually by LoadALL. +// If there is no reason for the package to be in the current build, +// Why returns an empty string. +func Why(path string) string { + pkg, ok := loaded.pkgCache.Get(path).(*loadPkg) + if !ok { + return "" + } + return pkg.why() +} + +// WhyDepth returns the number of steps in the Why listing. +// If there is no reason for the package to be in the current build, +// WhyDepth returns 0. +func WhyDepth(path string) int { + n := 0 + pkg, _ := loaded.pkgCache.Get(path).(*loadPkg) + for p := pkg; p != nil; p = p.stack { + n++ + } + return n +} + +// Replacement returns the replacement for mod, if any, from go.mod. +// If there is no replacement for mod, Replacement returns +// a module.Version with Path == "". +func Replacement(mod module.Version) module.Version { + if modFile == nil { + // Happens during testing. + return module.Version{} + } + + var found *modfile.Replace + for _, r := range modFile.Replace { + if r.Old.Path == mod.Path && (r.Old.Version == "" || r.Old.Version == mod.Version) { + found = r // keep going + } + } + if found == nil { + return module.Version{} + } + return found.New +} + +// mvsReqs implements mvs.Reqs for module semantic versions, +// with any exclusions or replacements applied internally. +type mvsReqs struct { + buildList []module.Version + cache par.Cache + versions sync.Map +} + +// Reqs returns the current module requirement graph. +// Future calls to SetBuildList do not affect the operation +// of the returned Reqs. +func Reqs() mvs.Reqs { + r := &mvsReqs{ + buildList: buildList, + } + return r +} + +func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) { + type cached struct { + list []module.Version + err error + } + + c := r.cache.Do(mod, func() interface{} { + list, err := r.required(mod) + if err != nil { + return cached{nil, err} + } + for i, mv := range list { + for excluded[mv] { + mv1, err := r.next(mv) + if err != nil { + return cached{nil, err} + } + if mv1.Version == "none" { + return cached{nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)} + } + mv = mv1 + } + list[i] = mv + } + + return cached{list, nil} + }).(cached) + + return c.list, c.err +} + +var vendorOnce sync.Once + +var ( + vendorList []module.Version + vendorMap map[string]module.Version +) + +// readVendorList reads the list of vendored modules from vendor/modules.txt. +func readVendorList() { + vendorOnce.Do(func() { + vendorList = nil + vendorMap = make(map[string]module.Version) + data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "vendor/modules.txt")) + var m module.Version + for _, line := range strings.Split(string(data), "\n") { + if strings.HasPrefix(line, "# ") { + f := strings.Fields(line) + m = module.Version{} + if len(f) == 3 && semver.IsValid(f[2]) { + m = module.Version{Path: f[1], Version: f[2]} + vendorList = append(vendorList, m) + } + } else if m.Path != "" { + f := strings.Fields(line) + if len(f) == 1 { + vendorMap[f[0]] = m + } + } + } + }) +} + +func (r *mvsReqs) modFileToList(f *modfile.File) []module.Version { + var list []module.Version + for _, r := range f.Require { + list = append(list, r.Mod) + } + return list +} + +func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) { + if mod == Target { + if modFile.Go != nil { + r.versions.LoadOrStore(mod, modFile.Go.Version) + } + var list []module.Version + return append(list, r.buildList[1:]...), nil + } + + if cfg.BuildMod == "vendor" { + // For every module other than the target, + // return the full list of modules from modules.txt. + readVendorList() + return vendorList, nil + } + + origPath := mod.Path + if repl := Replacement(mod); repl.Path != "" { + if repl.Version == "" { + // TODO: need to slip the new version into the tags list etc. + dir := repl.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot, dir) + } + gomod := filepath.Join(dir, "go.mod") + data, err := ioutil.ReadFile(gomod) + if err != nil { + base.Errorf("go: parsing %s: %v", base.ShortPath(gomod), err) + return nil, ErrRequire + } + f, err := modfile.ParseLax(gomod, data, nil) + if err != nil { + base.Errorf("go: parsing %s: %v", base.ShortPath(gomod), err) + return nil, ErrRequire + } + if f.Go != nil { + r.versions.LoadOrStore(mod, f.Go.Version) + } + return r.modFileToList(f), nil + } + mod = repl + } + + if mod.Version == "none" { + return nil, nil + } + + if !semver.IsValid(mod.Version) { + // Disallow the broader queries supported by fetch.Lookup. + base.Fatalf("go: internal error: %s@%s: unexpected invalid semantic version", mod.Path, mod.Version) + } + + data, err := modfetch.GoMod(mod.Path, mod.Version) + if err != nil { + base.Errorf("go: %s@%s: %v\n", mod.Path, mod.Version, err) + return nil, ErrRequire + } + f, err := modfile.ParseLax("go.mod", data, nil) + if err != nil { + base.Errorf("go: %s@%s: parsing go.mod: %v", mod.Path, mod.Version, err) + return nil, ErrRequire + } + + if f.Module == nil { + base.Errorf("go: %s@%s: parsing go.mod: missing module line", mod.Path, mod.Version) + return nil, ErrRequire + } + if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path { + base.Errorf("go: %s@%s: parsing go.mod: unexpected module path %q", mod.Path, mod.Version, mpath) + return nil, ErrRequire + } + if f.Go != nil { + r.versions.LoadOrStore(mod, f.Go.Version) + } + + return r.modFileToList(f), nil +} + +// ErrRequire is the sentinel error returned when Require encounters problems. +// It prints the problems directly to standard error, so that multiple errors +// can be displayed easily. +var ErrRequire = errors.New("error loading module requirements") + +func (*mvsReqs) Max(v1, v2 string) string { + if v1 != "" && semver.Compare(v1, v2) == -1 { + return v2 + } + return v1 +} + +// Upgrade is a no-op, here to implement mvs.Reqs. +// The upgrade logic for go get -u is in ../modget/get.go. +func (*mvsReqs) Upgrade(m module.Version) (module.Version, error) { + return m, nil +} + +func versions(path string) ([]string, error) { + // Note: modfetch.Lookup and repo.Versions are cached, + // so there's no need for us to add extra caching here. + repo, err := modfetch.Lookup(path) + if err != nil { + return nil, err + } + return repo.Versions("") +} + +// Previous returns the tagged version of m.Path immediately prior to +// m.Version, or version "none" if no prior version is tagged. +func (*mvsReqs) Previous(m module.Version) (module.Version, error) { + list, err := versions(m.Path) + if err != nil { + return module.Version{}, err + } + i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 }) + if i > 0 { + return module.Version{Path: m.Path, Version: list[i-1]}, nil + } + return module.Version{Path: m.Path, Version: "none"}, nil +} + +// next returns the next version of m.Path after m.Version. +// It is only used by the exclusion processing in the Required method, +// not called directly by MVS. +func (*mvsReqs) next(m module.Version) (module.Version, error) { + list, err := versions(m.Path) + if err != nil { + return module.Version{}, err + } + i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 }) + if i < len(list) { + return module.Version{Path: m.Path, Version: list[i]}, nil + } + return module.Version{Path: m.Path, Version: "none"}, nil +} + +func fetch(mod module.Version) (dir string, isLocal bool, err error) { + if mod == Target { + return ModRoot, true, nil + } + if r := Replacement(mod); r.Path != "" { + if r.Version == "" { + dir = r.Path + if !filepath.IsAbs(dir) { + dir = filepath.Join(ModRoot, dir) + } + return dir, true, nil + } + mod = r + } + + dir, err = modfetch.Download(mod) + return dir, false, err +} diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go new file mode 100644 index 0000000000..3b550f1db7 --- /dev/null +++ b/src/cmd/go/internal/modload/query.go @@ -0,0 +1,249 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" + "cmd/go/internal/semver" + "fmt" + pathpkg "path" + "strings" +) + +// Query looks up a revision of a given module given a version query string. +// The module must be a complete module path. +// The version must take one of the following forms: +// +// - the literal string "latest", denoting the latest available, allowed tagged version, +// with non-prereleases preferred over prereleases. +// If there are no tagged versions in the repo, latest returns the most recent commit. +// - v1, denoting the latest available tagged version v1.x.x. +// - v1.2, denoting the latest available tagged version v1.2.x. +// - v1.2.3, a semantic version string denoting that tagged version. +// - v1.2.3, >=v1.2.3, +// denoting the version closest to the target and satisfying the given operator, +// with non-prereleases preferred over prereleases. +// - a repository commit identifier, denoting that commit. +// +// If the allowed function is non-nil, Query excludes any versions for which allowed returns false. +// +// If path is the path of the main module and the query is "latest", +// Query returns Target.Version as the version. +func Query(path, query string, allowed func(module.Version) bool) (*modfetch.RevInfo, error) { + if allowed == nil { + allowed = func(module.Version) bool { return true } + } + + // Parse query to detect parse errors (and possibly handle query) + // before any network I/O. + badVersion := func(v string) (*modfetch.RevInfo, error) { + return nil, fmt.Errorf("invalid semantic version %q in range %q", v, query) + } + var ok func(module.Version) bool + var prefix string + var preferOlder bool + switch { + case query == "latest": + ok = allowed + + case strings.HasPrefix(query, "<="): + v := query[len("<="):] + if !semver.IsValid(v) { + return badVersion(v) + } + if isSemverPrefix(v) { + // Refuse to say whether <=v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3). + return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query) + } + ok = func(m module.Version) bool { + return semver.Compare(m.Version, v) <= 0 && allowed(m) + } + + case strings.HasPrefix(query, "<"): + v := query[len("<"):] + if !semver.IsValid(v) { + return badVersion(v) + } + ok = func(m module.Version) bool { + return semver.Compare(m.Version, v) < 0 && allowed(m) + } + + case strings.HasPrefix(query, ">="): + v := query[len(">="):] + if !semver.IsValid(v) { + return badVersion(v) + } + ok = func(m module.Version) bool { + return semver.Compare(m.Version, v) >= 0 && allowed(m) + } + preferOlder = true + + case strings.HasPrefix(query, ">"): + v := query[len(">"):] + if !semver.IsValid(v) { + return badVersion(v) + } + if isSemverPrefix(v) { + // Refuse to say whether >v1.2 allows v1.2.3 (remember, @v1.2 might mean v1.2.3). + return nil, fmt.Errorf("ambiguous semantic version %q in range %q", v, query) + } + ok = func(m module.Version) bool { + return semver.Compare(m.Version, v) > 0 && allowed(m) + } + preferOlder = true + + case semver.IsValid(query) && isSemverPrefix(query): + ok = func(m module.Version) bool { + return matchSemverPrefix(query, m.Version) && allowed(m) + } + prefix = query + "." + + case semver.IsValid(query): + vers := module.CanonicalVersion(query) + if !allowed(module.Version{Path: path, Version: vers}) { + return nil, fmt.Errorf("%s@%s excluded", path, vers) + } + return modfetch.Stat(path, vers) + + default: + // Direct lookup of semantic version or commit identifier. + info, err := modfetch.Stat(path, query) + if err != nil { + return nil, err + } + if !allowed(module.Version{Path: path, Version: info.Version}) { + return nil, fmt.Errorf("%s@%s excluded", path, info.Version) + } + return info, nil + } + + if path == Target.Path { + if query != "latest" { + return nil, fmt.Errorf("can't query specific version (%q) for the main module (%s)", query, path) + } + if !allowed(Target) { + return nil, fmt.Errorf("internal error: main module version is not allowed") + } + return &modfetch.RevInfo{Version: Target.Version}, nil + } + + // Load versions and execute query. + repo, err := modfetch.Lookup(path) + if err != nil { + return nil, err + } + versions, err := repo.Versions(prefix) + if err != nil { + return nil, err + } + + if preferOlder { + for _, v := range versions { + if semver.Prerelease(v) == "" && ok(module.Version{Path: path, Version: v}) { + return repo.Stat(v) + } + } + for _, v := range versions { + if semver.Prerelease(v) != "" && ok(module.Version{Path: path, Version: v}) { + return repo.Stat(v) + } + } + } else { + for i := len(versions) - 1; i >= 0; i-- { + v := versions[i] + if semver.Prerelease(v) == "" && ok(module.Version{Path: path, Version: v}) { + return repo.Stat(v) + } + } + for i := len(versions) - 1; i >= 0; i-- { + v := versions[i] + if semver.Prerelease(v) != "" && ok(module.Version{Path: path, Version: v}) { + return repo.Stat(v) + } + } + } + + if query == "latest" { + // Special case for "latest": if no tags match, use latest commit in repo, + // provided it is not excluded. + if info, err := repo.Latest(); err == nil && allowed(module.Version{Path: path, Version: info.Version}) { + return info, nil + } + } + + return nil, fmt.Errorf("no matching versions for query %q", query) +} + +// isSemverPrefix reports whether v is a semantic version prefix: v1 or v1.2 (not v1.2.3). +// The caller is assumed to have checked that semver.IsValid(v) is true. +func isSemverPrefix(v string) bool { + dots := 0 + for i := 0; i < len(v); i++ { + switch v[i] { + case '-', '+': + return false + case '.': + dots++ + if dots >= 2 { + return false + } + } + } + return true +} + +// matchSemverPrefix reports whether the shortened semantic version p +// matches the full-width (non-shortened) semantic version v. +func matchSemverPrefix(p, v string) bool { + return len(v) > len(p) && v[len(p)] == '.' && v[:len(p)] == p +} + +// QueryPackage looks up a revision of a module containing path. +// +// If multiple modules with revisions matching the query provide the requested +// package, QueryPackage picks the one with the longest module path. +// +// If the path is in the the main module and the query is "latest", +// QueryPackage returns Target as the version. +func QueryPackage(path, query string, allowed func(module.Version) bool) (module.Version, *modfetch.RevInfo, error) { + if _, ok := dirInModule(path, Target.Path, ModRoot, true); ok { + if query != "latest" { + return module.Version{}, nil, fmt.Errorf("can't query specific version (%q) for package %s in the main module (%s)", query, path, Target.Path) + } + if !allowed(Target) { + return module.Version{}, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed", path, Target.Path) + } + return Target, &modfetch.RevInfo{Version: Target.Version}, nil + } + + finalErr := errMissing + for p := path; p != "."; p = pathpkg.Dir(p) { + info, err := Query(p, query, allowed) + if err != nil { + if _, ok := err.(*codehost.VCSError); ok { + // A VCSError means we know where to find the code, + // we just can't. Abort search. + return module.Version{}, nil, err + } + if finalErr == errMissing { + finalErr = err + } + continue + } + m := module.Version{Path: p, Version: info.Version} + root, isLocal, err := fetch(m) + if err != nil { + return module.Version{}, nil, err + } + _, ok := dirInModule(path, m.Path, root, isLocal) + if ok { + return m, info, nil + } + } + + return module.Version{}, nil, finalErr +} diff --git a/src/cmd/go/internal/modload/query_test.go b/src/cmd/go/internal/modload/query_test.go new file mode 100644 index 0000000000..7f3ffabef7 --- /dev/null +++ b/src/cmd/go/internal/modload/query_test.go @@ -0,0 +1,151 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package modload + +import ( + "internal/testenv" + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + "strings" + "testing" + + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" +) + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +func testMain(m *testing.M) int { + dir, err := ioutil.TempDir("", "modload-test-") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) + modfetch.PkgMod = filepath.Join(dir, "pkg/mod") + codehost.WorkRoot = filepath.Join(dir, "codework") + return m.Run() +} + +var ( + queryRepo = "vcs-test.golang.org/git/querytest.git" + queryRepoV2 = queryRepo + "/v2" + queryRepoV3 = queryRepo + "/v3" + + // Empty version list (no semver tags), not actually empty. + emptyRepo = "vcs-test.golang.org/git/emptytest.git" +) + +var queryTests = []struct { + path string + query string + allow string + vers string + err string +}{ + /* + git init + echo module vcs-test.golang.org/git/querytest.git >go.mod + git add go.mod + git commit -m v1 go.mod + git tag start + for i in v0.0.0-pre1 v0.0.0 v0.0.1 v0.0.2 v0.0.3 v0.1.0 v0.1.1 v0.1.2 v0.3.0 v1.0.0 v1.1.0 v1.9.0 v1.9.9 v1.9.10-pre1; do + echo before $i >status + git add status + git commit -m "before $i" status + echo at $i >status + git commit -m "at $i" status + git tag $i + done + git tag favorite v0.0.3 + + git branch v2 start + git checkout v2 + echo module vcs-test.golang.org/git/querytest.git/v2 >go.mod + git commit -m v2 go.mod + for i in v2.0.0 v2.1.0 v2.2.0 v2.5.5; do + echo before $i >status + git add status + git commit -m "before $i" status + echo at $i >status + git commit -m "at $i" status + git tag $i + done + echo after v2.5.5 >status + git commit -m 'after v2.5.5' status + git checkout master + zip -r ../querytest.zip + gsutil cp ../querytest.zip gs://vcs-test/git/querytest.zip + curl 'https://vcs-test.golang.org/git/querytest?go-get=1' + */ + {path: queryRepo, query: "v0.0.0", vers: "v0.0.1"}, + {path: queryRepo, query: ">=v0.0.0", vers: "v0.0.0"}, + {path: queryRepo, query: "v0.0.1", vers: "v0.0.1"}, + {path: queryRepo, query: "v0.0.1+foo", vers: "v0.0.1"}, + {path: queryRepo, query: "v0.0.99", err: `unknown revision v0.0.99`}, + {path: queryRepo, query: "v0", vers: "v0.3.0"}, + {path: queryRepo, query: "v0.1", vers: "v0.1.2"}, + {path: queryRepo, query: "v0.2", err: `no matching versions for query "v0.2"`}, + {path: queryRepo, query: "v0.0", vers: "v0.0.3"}, + {path: queryRepo, query: "latest", vers: "v1.9.9"}, + {path: queryRepo, query: "latest", allow: "NOMATCH", err: `no matching versions for query "latest"`}, + {path: queryRepo, query: ">v1.9.9", vers: "v1.9.10-pre1"}, + {path: queryRepo, query: ">v1.10.0", err: `no matching versions for query ">v1.10.0"`}, + {path: queryRepo, query: ">=v1.10.0", err: `no matching versions for query ">=v1.10.0"`}, + {path: queryRepo, query: "6cf84eb", vers: "v0.0.2-0.20180704023347-6cf84ebaea54"}, + {path: queryRepo, query: "start", vers: "v0.0.0-20180704023101-5e9e31667ddf"}, + {path: queryRepo, query: "7a1b6bf", vers: "v0.1.0"}, + + {path: queryRepoV2, query: "v0.0.0", vers: "v2.0.0"}, + {path: queryRepoV2, query: ">=v0.0.0", vers: "v2.0.0"}, + {path: queryRepoV2, query: "v0.0.1+foo", vers: "v2.0.0-20180704023347-179bc86b1be3"}, + {path: queryRepoV2, query: "latest", vers: "v2.5.5"}, + + {path: queryRepoV3, query: "latest", vers: "v3.0.0-20180704024501-e0cf3de987e6"}, + + {path: emptyRepo, query: "latest", vers: "v0.0.0-20180704023549-7bb914627242"}, + {path: emptyRepo, query: ">v0.0.0", err: `no matching versions for query ">v0.0.0"`}, + {path: emptyRepo, query: " ? @ [ \ ] ^ _ ` { | } ~ + // We disallow some shell special characters: " ' * < > ? ` | + // (Note that some of those are disallowed by the Windows file system as well.) + // We also disallow path separators / : and \ (fileNameOK is only called on path element characters). + // We allow spaces (U+0020) in file names. + const allowed = "!#$%&()+,-.=@[]^_{}~ " + if '0' <= r && r <= '9' || 'A' <= r && r <= 'Z' || 'a' <= r && r <= 'z' { + return true + } + for i := 0; i < len(allowed); i++ { + if rune(allowed[i]) == r { + return true + } + } + return false + } + // It may be OK to add more ASCII punctuation here, but only carefully. + // For example Windows disallows < > \, and macOS disallows :, so we must not allow those. + return unicode.IsLetter(r) } // CheckPath checks that a module path is valid. func CheckPath(path string) error { - if !utf8.ValidString(path) { - return fmt.Errorf("malformed module path %q: invalid UTF-8", path) + if err := checkPath(path, false); err != nil { + return fmt.Errorf("malformed module path %q: %v", path, err) } - if path == "" { - return fmt.Errorf("malformed module path %q: empty string", path) - } - i := strings.Index(path, "/") if i < 0 { i = len(path) @@ -103,40 +134,139 @@ func CheckPath(path string) error { if !strings.Contains(path[:i], ".") { return fmt.Errorf("malformed module path %q: missing dot in first path element", path) } - if path[i-1] == '.' { - return fmt.Errorf("malformed module path %q: trailing dot in first path element", path) - } - if path[0] == '.' { - return fmt.Errorf("malformed module path %q: leading dot in first path element", path) - } if path[0] == '-' { return fmt.Errorf("malformed module path %q: leading dash in first path element", path) } - if strings.Contains(path, "..") { - return fmt.Errorf("malformed module path %q: double dot", path) - } - if strings.Contains(path, "//") { - return fmt.Errorf("malformed module path %q: double slash", path) - } for _, r := range path[:i] { if !firstPathOK(r) { return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r) } } - if path[len(path)-1] == '/' { - return fmt.Errorf("malformed module path %q: trailing slash", path) - } - for _, r := range path { - if !pathOK(r) { - return fmt.Errorf("malformed module path %q: invalid char %q", path, r) - } - } if _, _, ok := SplitPathVersion(path); !ok { - return fmt.Errorf("malformed module path %q: invalid version %s", path, path[strings.LastIndex(path, "/")+1:]) + return fmt.Errorf("malformed module path %q: invalid version", path) } return nil } +// CheckImportPath checks that an import path is valid. +func CheckImportPath(path string) error { + if err := checkPath(path, false); err != nil { + return fmt.Errorf("malformed import path %q: %v", path, err) + } + return nil +} + +// checkPath checks that a general path is valid. +// It returns an error describing why but not mentioning path. +// Because these checks apply to both module paths and import paths, +// the caller is expected to add the "malformed ___ path %q: " prefix. +// fileName indicates whether the final element of the path is a file name +// (as opposed to a directory name). +func checkPath(path string, fileName bool) error { + if !utf8.ValidString(path) { + return fmt.Errorf("invalid UTF-8") + } + if path == "" { + return fmt.Errorf("empty string") + } + if strings.Contains(path, "..") { + return fmt.Errorf("double dot") + } + if strings.Contains(path, "//") { + return fmt.Errorf("double slash") + } + if path[len(path)-1] == '/' { + return fmt.Errorf("trailing slash") + } + elemStart := 0 + for i, r := range path { + if r == '/' { + if err := checkElem(path[elemStart:i], fileName); err != nil { + return err + } + elemStart = i + 1 + } + } + if err := checkElem(path[elemStart:], fileName); err != nil { + return err + } + return nil +} + +// checkElem checks whether an individual path element is valid. +// fileName indicates whether the element is a file name (not a directory name). +func checkElem(elem string, fileName bool) error { + if elem == "" { + return fmt.Errorf("empty path element") + } + if strings.Count(elem, ".") == len(elem) { + return fmt.Errorf("invalid path element %q", elem) + } + if elem[0] == '.' && !fileName { + return fmt.Errorf("leading dot in path element") + } + if elem[len(elem)-1] == '.' { + return fmt.Errorf("trailing dot in path element") + } + charOK := pathOK + if fileName { + charOK = fileNameOK + } + for _, r := range elem { + if !charOK(r) { + return fmt.Errorf("invalid char %q", r) + } + } + + // Windows disallows a bunch of path elements, sadly. + // See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file + short := elem + if i := strings.Index(short, "."); i >= 0 { + short = short[:i] + } + for _, bad := range badWindowsNames { + if strings.EqualFold(bad, short) { + return fmt.Errorf("disallowed path element %q", elem) + } + } + return nil +} + +// CheckFilePath checks whether a slash-separated file path is valid. +func CheckFilePath(path string) error { + if err := checkPath(path, true); err != nil { + return fmt.Errorf("malformed file path %q: %v", path, err) + } + return nil +} + +// badWindowsNames are the reserved file path elements on Windows. +// See https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file +var badWindowsNames = []string{ + "CON", + "PRN", + "AUX", + "NUL", + "COM1", + "COM2", + "COM3", + "COM4", + "COM5", + "COM6", + "COM7", + "COM8", + "COM9", + "LPT1", + "LPT2", + "LPT3", + "LPT4", + "LPT5", + "LPT6", + "LPT7", + "LPT8", + "LPT9", +} + // SplitPathVersion returns prefix and major version such that prefix+pathMajor == path // and version is either empty or "/vN" for N >= 2. // As a special case, gopkg.in paths are recognized directly; @@ -170,6 +300,9 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { return path, "", false } i := len(path) + if strings.HasSuffix(path, "-unstable") { + i -= len("-unstable") + } for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') { i-- } @@ -187,9 +320,221 @@ func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) { // MatchPathMajor reports whether the semantic version v // matches the path major version pathMajor. func MatchPathMajor(v, pathMajor string) bool { + if strings.HasPrefix(pathMajor, ".v") && strings.HasSuffix(pathMajor, "-unstable") { + pathMajor = strings.TrimSuffix(pathMajor, "-unstable") + } + if strings.HasPrefix(v, "v0.0.0-") && pathMajor == ".v1" { + // Allow old bug in pseudo-versions that generated v0.0.0- pseudoversion for gopkg .v1. + // For example, gopkg.in/yaml.v2@v2.2.1's go.mod requires gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405. + return true + } m := semver.Major(v) if pathMajor == "" { - return m == "v0" || m == "v1" + return m == "v0" || m == "v1" || semver.Build(v) == "+incompatible" } return (pathMajor[0] == '/' || pathMajor[0] == '.') && m == pathMajor[1:] } + +// CanonicalVersion returns the canonical form of the version string v. +// It is the same as semver.Canonical(v) except that it preserves the special build suffix "+incompatible". +func CanonicalVersion(v string) string { + cv := semver.Canonical(v) + if semver.Build(v) == "+incompatible" { + cv += "+incompatible" + } + return cv +} + +// Sort sorts the list by Path, breaking ties by comparing Versions. +func Sort(list []Version) { + sort.Slice(list, func(i, j int) bool { + mi := list[i] + mj := list[j] + if mi.Path != mj.Path { + return mi.Path < mj.Path + } + // To help go.sum formatting, allow version/file. + // Compare semver prefix by semver rules, + // file by string order. + vi := mi.Version + vj := mj.Version + var fi, fj string + if k := strings.Index(vi, "/"); k >= 0 { + vi, fi = vi[:k], vi[k:] + } + if k := strings.Index(vj, "/"); k >= 0 { + vj, fj = vj[:k], vj[k:] + } + if vi != vj { + return semver.Compare(vi, vj) < 0 + } + return fi < fj + }) +} + +// Safe encodings +// +// Module paths appear as substrings of file system paths +// (in the download cache) and of web server URLs in the proxy protocol. +// In general we cannot rely on file systems to be case-sensitive, +// nor can we rely on web servers, since they read from file systems. +// That is, we cannot rely on the file system to keep rsc.io/QUOTE +// and rsc.io/quote separate. Windows and macOS don't. +// Instead, we must never require two different casings of a file path. +// Because we want the download cache to match the proxy protocol, +// and because we want the proxy protocol to be possible to serve +// from a tree of static files (which might be stored on a case-insensitive +// file system), the proxy protocol must never require two different casings +// of a URL path either. +// +// One possibility would be to make the safe encoding be the lowercase +// hexadecimal encoding of the actual path bytes. This would avoid ever +// needing different casings of a file path, but it would be fairly illegible +// to most programmers when those paths appeared in the file system +// (including in file paths in compiler errors and stack traces) +// in web server logs, and so on. Instead, we want a safe encoding that +// leaves most paths unaltered. +// +// The safe encoding is this: +// replace every uppercase letter with an exclamation mark +// followed by the letter's lowercase equivalent. +// +// For example, +// github.com/Azure/azure-sdk-for-go -> github.com/!azure/azure-sdk-for-go. +// github.com/GoogleCloudPlatform/cloudsql-proxy -> github.com/!google!cloud!platform/cloudsql-proxy +// github.com/Sirupsen/logrus -> github.com/!sirupsen/logrus. +// +// Import paths that avoid upper-case letters are left unchanged. +// Note that because import paths are ASCII-only and avoid various +// problematic punctuation (like : < and >), the safe encoding is also ASCII-only +// and avoids the same problematic punctuation. +// +// Import paths have never allowed exclamation marks, so there is no +// need to define how to encode a literal !. +// +// Although paths are disallowed from using Unicode (see pathOK above), +// the eventual plan is to allow Unicode letters as well, to assume that +// file systems and URLs are Unicode-safe (storing UTF-8), and apply +// the !-for-uppercase convention. Note however that not all runes that +// are different but case-fold equivalent are an upper/lower pair. +// For example, U+004B ('K'), U+006B ('k'), and U+212A ('K' for Kelvin) +// are considered to case-fold to each other. When we do add Unicode +// letters, we must not assume that upper/lower are the only case-equivalent pairs. +// Perhaps the Kelvin symbol would be disallowed entirely, for example. +// Or perhaps it would encode as "!!k", or perhaps as "(212A)". +// +// Also, it would be nice to allow Unicode marks as well as letters, +// but marks include combining marks, and then we must deal not +// only with case folding but also normalization: both U+00E9 ('é') +// and U+0065 U+0301 ('e' followed by combining acute accent) +// look the same on the page and are treated by some file systems +// as the same path. If we do allow Unicode marks in paths, there +// must be some kind of normalization to allow only one canonical +// encoding of any character used in an import path. + +// EncodePath returns the safe encoding of the given module path. +// It fails if the module path is invalid. +func EncodePath(path string) (encoding string, err error) { + if err := CheckPath(path); err != nil { + return "", err + } + + return encodeString(path) +} + +// EncodeVersion returns the safe encoding of the given module version. +// Versions are allowed to be in non-semver form but must be valid file names +// and not contain exclamation marks. +func EncodeVersion(v string) (encoding string, err error) { + if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { + return "", fmt.Errorf("disallowed version string %q", v) + } + return encodeString(v) +} + +func encodeString(s string) (encoding string, err error) { + haveUpper := false + for _, r := range s { + if r == '!' || r >= utf8.RuneSelf { + // This should be disallowed by CheckPath, but diagnose anyway. + // The correctness of the encoding loop below depends on it. + return "", fmt.Errorf("internal error: inconsistency in EncodePath") + } + if 'A' <= r && r <= 'Z' { + haveUpper = true + } + } + + if !haveUpper { + return s, nil + } + + var buf []byte + for _, r := range s { + if 'A' <= r && r <= 'Z' { + buf = append(buf, '!', byte(r+'a'-'A')) + } else { + buf = append(buf, byte(r)) + } + } + return string(buf), nil +} + +// DecodePath returns the module path of the given safe encoding. +// It fails if the encoding is invalid or encodes an invalid path. +func DecodePath(encoding string) (path string, err error) { + path, ok := decodeString(encoding) + if !ok { + return "", fmt.Errorf("invalid module path encoding %q", encoding) + } + if err := CheckPath(path); err != nil { + return "", fmt.Errorf("invalid module path encoding %q: %v", encoding, err) + } + return path, nil +} + +// DecodeVersion returns the version string for the given safe encoding. +// It fails if the encoding is invalid or encodes an invalid version. +// Versions are allowed to be in non-semver form but must be valid file names +// and not contain exclamation marks. +func DecodeVersion(encoding string) (v string, err error) { + v, ok := decodeString(encoding) + if !ok { + return "", fmt.Errorf("invalid version encoding %q", encoding) + } + if err := checkElem(v, true); err != nil { + return "", fmt.Errorf("disallowed version string %q", v) + } + return v, nil +} + +func decodeString(encoding string) (string, bool) { + var buf []byte + + bang := false + for _, r := range encoding { + if r >= utf8.RuneSelf { + return "", false + } + if bang { + bang = false + if r < 'a' || 'z' < r { + return "", false + } + buf = append(buf, byte(r+'A'-'a')) + continue + } + if r == '!' { + bang = true + continue + } + if 'A' <= r && r <= 'Z' { + return "", false + } + buf = append(buf, byte(r)) + } + if bang { + return "", false + } + return string(buf), true +} diff --git a/src/cmd/go/internal/module/module_test.go b/src/cmd/go/internal/module/module_test.go index 6142a9e048..f21d620d32 100644 --- a/src/cmd/go/internal/module/module_test.go +++ b/src/cmd/go/internal/module/module_test.go @@ -37,10 +37,21 @@ var checkTests = []struct { {"gopkg.in/yaml.v1", "v2.1.5", false}, {"gopkg.in/yaml.v1", "v3.0.0", false}, + // For gopkg.in, .v1 means v1 only (not v0). + // But early versions of vgo still generated v0 pseudo-versions for it. + // Even though now we'd generate those as v1 pseudo-versions, + // we accept the old pseudo-versions to avoid breaking existing go.mod files. + // For example gopkg.in/yaml.v2@v2.2.1's go.mod requires check.v1 at a v0 pseudo-version. + {"gopkg.in/check.v1", "v0.0.0", false}, + {"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true}, + {"gopkg.in/yaml.v2", "v1.0.0", false}, {"gopkg.in/yaml.v2", "v2.0.0", true}, {"gopkg.in/yaml.v2", "v2.1.5", true}, {"gopkg.in/yaml.v2", "v3.0.0", false}, + + {"rsc.io/quote", "v17.0.0", false}, + {"rsc.io/quote", "v17.0.0+incompatible", true}, } func TestCheck(t *testing.T) { @@ -55,92 +66,120 @@ func TestCheck(t *testing.T) { } var checkPathTests = []struct { - path string - ok bool + path string + ok bool + importOK bool + fileOK bool }{ - {"x.y/z", true}, - {"x.y", true}, + {"x.y/z", true, true, true}, + {"x.y", true, true, true}, - {"", false}, - {"x.y/\xFFz", false}, - {"/x.y/z", false}, - {"x./z", false}, - {".x/z", false}, - {"-x/z", false}, - {"x..y/z", false}, - {"x.y/z/../../w", false}, - {"x.y//z", false}, - {"x.y/z//w", false}, - {"x.y/z/", false}, + {"", false, false, false}, + {"x.y/\xFFz", false, false, false}, + {"/x.y/z", false, false, false}, + {"x./z", false, false, false}, + {".x/z", false, false, true}, + {"-x/z", false, true, true}, + {"x..y/z", false, false, false}, + {"x.y/z/../../w", false, false, false}, + {"x.y//z", false, false, false}, + {"x.y/z//w", false, false, false}, + {"x.y/z/", false, false, false}, - {"x.y/z/v0", false}, - {"x.y/z/v1", false}, - {"x.y/z/v2", true}, - {"x.y/z/v2.0", false}, + {"x.y/z/v0", false, true, true}, + {"x.y/z/v1", false, true, true}, + {"x.y/z/v2", true, true, true}, + {"x.y/z/v2.0", false, true, true}, + {"X.y/z", false, true, true}, - {"!x.y/z", false}, - {"_x.y/z", false}, - {"x.y!/z", false}, - {"x.y\"/z", false}, - {"x.y#/z", false}, - {"x.y$/z", false}, - {"x.y%/z", false}, - {"x.y&/z", false}, - {"x.y'/z", false}, - {"x.y(/z", false}, - {"x.y)/z", false}, - {"x.y*/z", false}, - {"x.y+/z", false}, - {"x.y,/z", false}, - {"x.y-/z", true}, - {"x.y./zt", false}, - {"x.y:/z", false}, - {"x.y;/z", false}, - {"x.y/z", false}, - {"x.y?/z", false}, - {"x.y@/z", false}, - {"x.y[/z", false}, - {"x.y\\/z", false}, - {"x.y]/z", false}, - {"x.y^/z", false}, - {"x.y_/z", false}, - {"x.y`/z", false}, - {"x.y{/z", false}, - {"x.y}/z", false}, - {"x.y~/z", false}, - {"x.y/z!", false}, - {"x.y/z\"", false}, - {"x.y/z#", false}, - {"x.y/z$", false}, - {"x.y/z%", false}, - {"x.y/z&", false}, - {"x.y/z'", false}, - {"x.y/z(", false}, - {"x.y/z)", false}, - {"x.y/z*", false}, - {"x.y/z+", true}, - {"x.y/z,", true}, - {"x.y/z-", true}, - {"x.y/z.t", true}, - {"x.y/z/t", true}, - {"x.y/z:", false}, - {"x.y/z;", false}, - {"x.y/z<", false}, - {"x.y/z=", false}, - {"x.y/z>", false}, - {"x.y/z?", false}, - {"x.y/z@", false}, - {"x.y/z[", false}, - {"x.y/z\\", false}, - {"x.y/z]", false}, - {"x.y/z^", false}, - {"x.y/z_", true}, - {"x.y/z`", false}, - {"x.y/z{", false}, - {"x.y/z}", false}, - {"x.y/z~", true}, + {"!x.y/z", false, false, true}, + {"_x.y/z", false, true, true}, + {"x.y!/z", false, false, true}, + {"x.y\"/z", false, false, false}, + {"x.y#/z", false, false, true}, + {"x.y$/z", false, false, true}, + {"x.y%/z", false, false, true}, + {"x.y&/z", false, false, true}, + {"x.y'/z", false, false, false}, + {"x.y(/z", false, false, true}, + {"x.y)/z", false, false, true}, + {"x.y*/z", false, false, false}, + {"x.y+/z", false, true, true}, + {"x.y,/z", false, false, true}, + {"x.y-/z", true, true, true}, + {"x.y./zt", false, false, false}, + {"x.y:/z", false, false, false}, + {"x.y;/z", false, false, false}, + {"x.y/z", false, false, false}, + {"x.y?/z", false, false, false}, + {"x.y@/z", false, false, true}, + {"x.y[/z", false, false, true}, + {"x.y\\/z", false, false, false}, + {"x.y]/z", false, false, true}, + {"x.y^/z", false, false, true}, + {"x.y_/z", false, true, true}, + {"x.y`/z", false, false, false}, + {"x.y{/z", false, false, true}, + {"x.y}/z", false, false, true}, + {"x.y~/z", false, true, true}, + {"x.y/z!", false, false, true}, + {"x.y/z\"", false, false, false}, + {"x.y/z#", false, false, true}, + {"x.y/z$", false, false, true}, + {"x.y/z%", false, false, true}, + {"x.y/z&", false, false, true}, + {"x.y/z'", false, false, false}, + {"x.y/z(", false, false, true}, + {"x.y/z)", false, false, true}, + {"x.y/z*", false, false, false}, + {"x.y/z+", true, true, true}, + {"x.y/z,", false, false, true}, + {"x.y/z-", true, true, true}, + {"x.y/z.t", true, true, true}, + {"x.y/z/t", true, true, true}, + {"x.y/z:", false, false, false}, + {"x.y/z;", false, false, false}, + {"x.y/z<", false, false, false}, + {"x.y/z=", false, false, true}, + {"x.y/z>", false, false, false}, + {"x.y/z?", false, false, false}, + {"x.y/z@", false, false, true}, + {"x.y/z[", false, false, true}, + {"x.y/z\\", false, false, false}, + {"x.y/z]", false, false, true}, + {"x.y/z^", false, false, true}, + {"x.y/z_", true, true, true}, + {"x.y/z`", false, false, false}, + {"x.y/z{", false, false, true}, + {"x.y/z}", false, false, true}, + {"x.y/z~", true, true, true}, + {"x.y/x.foo", true, true, true}, + {"x.y/aux.foo", false, false, false}, + {"x.y/prn", false, false, false}, + {"x.y/prn2", true, true, true}, + {"x.y/com", true, true, true}, + {"x.y/com1", false, false, false}, + {"x.y/com1.txt", false, false, false}, + {"x.y/calm1", true, true, true}, + {"github.com/!123/logrus", false, false, true}, + + // TODO: CL 41822 allowed Unicode letters in old "go get" + // without due consideration of the implications, and only on github.com (!). + // For now, we disallow non-ASCII characters in module mode, + // in both module paths and general import paths, + // until we can get the implications right. + // When we do, we'll enable them everywhere, not just for GitHub. + {"github.com/user/unicode/испытание", false, false, true}, + + {"../x", false, false, false}, + {"./y", false, false, false}, + {"x:y", false, false, false}, + {`\temp\foo`, false, false, false}, + {".gitignore", false, false, true}, + {".github/ISSUE_TEMPLATE", false, false, true}, + {"x☺y", false, false, false}, } func TestCheckPath(t *testing.T) { @@ -151,6 +190,20 @@ func TestCheckPath(t *testing.T) { } else if !tt.ok && err == nil { t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path) } + + err = CheckImportPath(tt.path) + if tt.importOK && err != nil { + t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err) + } else if !tt.importOK && err == nil { + t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path) + } + + err = CheckFilePath(tt.path) + if tt.fileOK && err != nil { + t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err) + } else if !tt.fileOK && err == nil { + t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path) + } } } @@ -182,3 +235,84 @@ func TestSplitPathVersion(t *testing.T) { } } } + +var encodeTests = []struct { + path string + enc string // empty means same as path +}{ + {path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-+/~_0123456789"}, + {path: "github.com/GoogleCloudPlatform/omega", enc: "github.com/!google!cloud!platform/omega"}, +} + +func TestEncodePath(t *testing.T) { + // Check invalid paths. + for _, tt := range checkPathTests { + if !tt.ok { + _, err := EncodePath(tt.path) + if err == nil { + t.Errorf("EncodePath(%q): succeeded, want error (invalid path)", tt.path) + } + } + } + + // Check encodings. + for _, tt := range encodeTests { + enc, err := EncodePath(tt.path) + if err != nil { + t.Errorf("EncodePath(%q): unexpected error: %v", tt.path, err) + continue + } + want := tt.enc + if want == "" { + want = tt.path + } + if enc != want { + t.Errorf("EncodePath(%q) = %q, want %q", tt.path, enc, want) + } + } +} + +var badDecode = []string{ + "github.com/GoogleCloudPlatform/omega", + "github.com/!google!cloud!platform!/omega", + "github.com/!0google!cloud!platform/omega", + "github.com/!_google!cloud!platform/omega", + "github.com/!!google!cloud!platform/omega", + "", +} + +func TestDecodePath(t *testing.T) { + // Check invalid decodings. + for _, bad := range badDecode { + _, err := DecodePath(bad) + if err == nil { + t.Errorf("DecodePath(%q): succeeded, want error (invalid decoding)", bad) + } + } + + // Check invalid paths (or maybe decodings). + for _, tt := range checkPathTests { + if !tt.ok { + path, err := DecodePath(tt.path) + if err == nil { + t.Errorf("DecodePath(%q) = %q, want error (invalid path)", tt.path, path) + } + } + } + + // Check encodings. + for _, tt := range encodeTests { + enc := tt.enc + if enc == "" { + enc = tt.path + } + path, err := DecodePath(enc) + if err != nil { + t.Errorf("DecodePath(%q): unexpected error: %v", enc, err) + continue + } + if path != tt.path { + t.Errorf("DecodePath(%q) = %q, want %q", enc, path, tt.path) + } + } +} diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go index 47670ff5a6..8ec9162dab 100644 --- a/src/cmd/go/internal/mvs/mvs.go +++ b/src/cmd/go/internal/mvs/mvs.go @@ -9,14 +9,53 @@ package mvs import ( "fmt" "sort" + "sync" + "cmd/go/internal/base" "cmd/go/internal/module" + "cmd/go/internal/par" ) +// A Reqs is the requirement graph on which Minimal Version Selection (MVS) operates. +// +// The version strings are opaque except for the special version "none" +// (see the documentation for module.Version). In particular, MVS does not +// assume that the version strings are semantic versions; instead, the Max method +// gives access to the comparison operation. +// +// It must be safe to call methods on a Reqs from multiple goroutines simultaneously. +// Because a Reqs may read the underlying graph from the network on demand, +// the MVS algorithms parallelize the traversal to overlap network delays. type Reqs interface { + // Required returns the module versions explicitly required by m itself. + // The caller must not modify the returned list. Required(m module.Version) ([]module.Version, error) + + // Max returns the maximum of v1 and v2 (it returns either v1 or v2). + // + // For all versions v, Max(v, "none") must be v, + // and for the tanget passed as the first argument to MVS functions, + // Max(target, v) must be target. + // + // Note that v1 < v2 can be written Max(v1, v2) != v1 + // and similarly v1 <= v2 can be written Max(v1, v2) == v2. Max(v1, v2 string) string - Latest(path string) (module.Version, error) + + // Upgrade returns the upgraded version of m, + // for use during an UpgradeAll operation. + // If m should be kept as is, Upgrade returns m. + // If m is not yet used in the build, then m.Version will be "none". + // More typically, m.Version will be the version required + // by some other module in the build. + // + // If no module version is available for the given path, + // Upgrade returns a non-nil error. + // TODO(rsc): Upgrade must be able to return errors, + // but should "no latest version" just return m instead? + Upgrade(m module.Version) (module.Version, error) + + // Previous returns the version of m.Path immediately prior to m.Version, + // or "none" if no such version is known. Previous(m module.Version) (module.Version, error) } @@ -30,61 +69,81 @@ func (e *MissingModuleError) Error() string { // BuildList returns the build list for the target module. func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) { - return buildList(target, reqs, nil, nil) + return buildList(target, reqs, nil) } -func buildList(target module.Version, reqs Reqs, uses map[module.Version][]module.Version, vers map[string]string) ([]module.Version, error) { +func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) module.Version) ([]module.Version, error) { + // Explore work graph in parallel in case reqs.Required + // does high-latency network operations. + var work par.Work + work.Add(target) var ( - min = map[string]string{target.Path: target.Version} - todo = []module.Version{target} - seen = map[module.Version]bool{target: true} + mu sync.Mutex + min = map[string]string{target.Path: target.Version} + firstErr error ) - for len(todo) > 0 { - m := todo[len(todo)-1] - todo = todo[:len(todo)-1] - required, _ := reqs.Required(m) - for _, r := range required { - if uses != nil { - uses[r] = append(uses[r], m) - } - if !seen[r] { - if v, ok := min[r.Path]; !ok { - min[r.Path] = r.Version - } else if max := reqs.Max(v, r.Version); max != v { - min[r.Path] = max - } - todo = append(todo, r) - seen[r] = true - } + work.Do(10, func(item interface{}) { + m := item.(module.Version) + required, err := reqs.Required(m) + + mu.Lock() + if err != nil && firstErr == nil { + firstErr = err } + if firstErr != nil { + mu.Unlock() + return + } + if v, ok := min[m.Path]; !ok || reqs.Max(v, m.Version) != v { + min[m.Path] = m.Version + } + mu.Unlock() + + for _, r := range required { + if r.Path == "" { + base.Errorf("Required(%v) returned zero module in list", m) + continue + } + work.Add(r) + } + + if upgrade != nil { + u := upgrade(m) + if u.Path == "" { + base.Errorf("Upgrade(%v) returned zero module", m) + return + } + work.Add(u) + } + }) + + if firstErr != nil { + return nil, firstErr + } + if v := min[target.Path]; v != target.Version { + panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) // TODO: Don't panic. } - if min[target.Path] != target.Version { - panic("unbuildable") // TODO - } - - if vers == nil { - vers = make(map[string]string) - } list := []module.Version{target} + listed := map[string]bool{target.Path: true} for i := 0; i < len(list); i++ { m := list[i] required, err := reqs.Required(m) if err != nil { - // TODO: Check error is decent. return nil, err } for _, r := range required { v := min[r.Path] - if reqs.Max(v, r.Version) != v { - panic("mistake") // TODO + if r.Path != target.Path && reqs.Max(v, r.Version) != v { + panic(fmt.Sprintf("mistake: version %q does not satisfy requirement %+v", v, r)) // TODO: Don't panic. } - if _, ok := vers[r.Path]; !ok { - vers[r.Path] = v + if !listed[r.Path] { list = append(list, module.Version{Path: r.Path, Version: v}) + listed[r.Path] = true } } } + tail := list[1:] sort.Slice(tail, func(i, j int) bool { return tail[i].Path < tail[j].Path @@ -93,8 +152,13 @@ func buildList(target module.Version, reqs Reqs, uses map[module.Version][]modul } // Req returns the minimal requirement list for the target module -// that result in the given build list. -func Req(target module.Version, list []module.Version, reqs Reqs) ([]module.Version, error) { +// that results in the given build list, with the constraint that all +// module paths listed in base must appear in the returned list. +func Req(target module.Version, list []module.Version, base []string, reqs Reqs) ([]module.Version, error) { + // Note: Not running in parallel because we assume + // that list came from a previous operation that paged + // in all the requirements, so there's no I/O to overlap now. + // Compute postorder, cache requirements. var postorder []module.Version reqCache := map[module.Version][]module.Version{} @@ -138,13 +202,20 @@ func Req(target module.Version, list []module.Version, reqs Reqs) ([]module.Vers } max := map[string]string{} for _, m := range list { - if max[m.Path] == "" { - max[m.Path] = m.Version + if v, ok := max[m.Path]; ok { + max[m.Path] = reqs.Max(m.Version, v) } else { - max[m.Path] = reqs.Max(m.Version, max[m.Path]) + max[m.Path] = m.Version } } + // First walk the base modules that must be listed. var min []module.Version + for _, path := range base { + m := module.Version{Path: path, Version: max[path]} + min = append(min, m) + walk(m) + } + // Now the reverse postorder to bring in anything else. for i := len(postorder) - 1; i >= 0; i-- { m := postorder[i] if max[m.Path] != m.Version { @@ -165,33 +236,18 @@ func Req(target module.Version, list []module.Version, reqs Reqs) ([]module.Vers // UpgradeAll returns a build list for the target module // in which every module is upgraded to its latest version. func UpgradeAll(target module.Version, reqs Reqs) ([]module.Version, error) { - have := map[string]bool{target.Path: true} - list := []module.Version{target} - for i := 0; i < len(list); i++ { - m := list[i] - required, err := reqs.Required(m) + return buildList(target, reqs, func(m module.Version) module.Version { + if m.Path == target.Path { + return target + } + + latest, err := reqs.Upgrade(m) if err != nil { panic(err) // TODO } - for _, r := range required { - latest, err := reqs.Latest(r.Path) - if err != nil { - panic(err) // TODO - } - if reqs.Max(latest.Version, r.Version) != latest.Version { - panic("mistake") // TODO - } - if !have[r.Path] { - have[r.Path] = true - list = append(list, module.Version{Path: r.Path, Version: latest.Version}) - } - } - } - tail := list[1:] - sort.Slice(tail, func(i, j int) bool { - return tail[i].Path < tail[j].Path + m.Version = latest.Version + return m }) - return list, nil } // Upgrade returns a build list for the target module @@ -211,6 +267,10 @@ func Upgrade(target module.Version, reqs Reqs, upgrade ...module.Version) ([]mod // Downgrade returns a build list for the target module // in which the given additional modules are downgraded. +// +// The versions to be downgraded may be unreachable from reqs.Latest and +// reqs.Previous, but the methods of reqs must otherwise handle such versions +// correctly. func Downgrade(target module.Version, reqs Reqs, downgrade ...module.Version) ([]module.Version, error) { list, err := reqs.Required(target) if err != nil { diff --git a/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go index 0fd55e4e45..2a27dfb288 100644 --- a/src/cmd/go/internal/mvs/mvs_test.go +++ b/src/cmd/go/internal/mvs/mvs_test.go @@ -156,6 +156,47 @@ D1: E2 E1: D2 build A: A B C D2 E2 +# Upgrade from B1 to B2 should drop the transitive dep on D. +name: drop +A: B1 C1 +B1: D1 +B2: +C2: +D2: +build A: A B1 C1 D1 +upgrade* A: A B2 C2 + +name: simplify +A: B1 C1 +B1: C2 +C1: D1 +C2: +build A: A B1 C2 + +name: up1 +A: B1 C1 +B1: +B2: +B3: +B4: +B5.hidden: +C2: +C3: +build A: A B1 C1 +upgrade* A: A B4 C3 + +name: up2 +A: B5.hidden C1 +B1: +B2: +B3: +B4: +B5.hidden: +C2: +C3: +build A: A B5.hidden C1 +upgrade* A: A B5.hidden C3 + name: down1 A: B2 B1: C1 @@ -199,6 +240,48 @@ B3: B2.hidden: C2: downgrade A B2.hidden: A B2.hidden C2 + +# Cycles involving the target. + +# The target must be the newest version of itself. +name: cycle1 +A: B1 +B1: A1 +B2: A2 +B3: A3 +build A: A B1 +upgrade A B2: A B2 +upgrade* A: A B3 + +# Requirements of older versions of the target +# must not be carried over. +name: cycle2 +A: B1 +A1: C1 +A2: D1 +B1: A1 +B2: A2 +C1: A2 +C2: +D2: +build A: A B1 +upgrade* A: A B2 + +# Requirement minimization. + +name: req1 +A: B1 C1 D1 E1 F1 +B1: C1 E1 F1 +req A: B1 D1 +req A C: B1 C1 D1 + +name: req2 +A: G1 H1 +G1: H1 +H1: G1 +req A: G1 +req A G: G1 +req A H: H1 ` func Test(t *testing.T) { @@ -281,19 +364,19 @@ func Test(t *testing.T) { continue case "upgradereq": if len(kf) < 2 { - t.Fatalf("upgrade takes at least one arguments: %q", line) + t.Fatalf("upgrade takes at least one argument: %q", line) } fns = append(fns, func(t *testing.T) { list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...) if err == nil { - list, err = Req(m(kf[1]), list, reqs) + list, err = Req(m(kf[1]), list, nil, reqs) } checkList(t, key, list, err, val) }) continue case "upgrade": if len(kf) < 2 { - t.Fatalf("upgrade takes at least one arguments: %q", line) + t.Fatalf("upgrade takes at least one argument: %q", line) } fns = append(fns, func(t *testing.T) { list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...) @@ -302,13 +385,26 @@ func Test(t *testing.T) { continue case "downgrade": if len(kf) < 2 { - t.Fatalf("downgrade takes at least one arguments: %q", line) + t.Fatalf("downgrade takes at least one argument: %q", line) } fns = append(fns, func(t *testing.T) { list, err := Downgrade(m(kf[1]), reqs, ms(kf[1:])...) checkList(t, key, list, err, val) }) continue + case "req": + if len(kf) < 2 { + t.Fatalf("req takes at least one argument: %q", line) + } + fns = append(fns, func(t *testing.T) { + list, err := BuildList(m(kf[1]), reqs) + if err != nil { + t.Fatal(err) + } + list, err = Req(m(kf[1]), list, kf[2:], reqs) + checkList(t, key, list, err, val) + }) + continue } if len(kf) == 1 && 'A' <= key[0] && key[0] <= 'Z' { var rs []module.Version @@ -330,10 +426,10 @@ func Test(t *testing.T) { type reqsMap map[module.Version][]module.Version func (r reqsMap) Max(v1, v2 string) string { - if v1 == "none" { + if v1 == "none" || v2 == "" { return v2 } - if v2 == "none" { + if v2 == "none" || v1 == "" { return v1 } if v1 < v2 { @@ -342,17 +438,17 @@ func (r reqsMap) Max(v1, v2 string) string { return v1 } -func (r reqsMap) Latest(path string) (module.Version, error) { - var m module.Version +func (r reqsMap) Upgrade(m module.Version) (module.Version, error) { + var u module.Version for k := range r { - if k.Path == path && m.Version < k.Version { - m = k + if k.Path == m.Path && u.Version < k.Version && !strings.HasSuffix(k.Version, ".hidden") { + u = k } } - if m.Path == "" { - return module.Version{}, &MissingModuleError{module.Version{Path: path, Version: ""}} + if u.Path == "" { + return module.Version{}, &MissingModuleError{module.Version{Path: m.Path, Version: ""}} } - return m, nil + return u, nil } func (r reqsMap) Previous(m module.Version) (module.Version, error) { diff --git a/src/cmd/go/internal/par/work.go b/src/cmd/go/internal/par/work.go new file mode 100644 index 0000000000..a568c86f60 --- /dev/null +++ b/src/cmd/go/internal/par/work.go @@ -0,0 +1,149 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package par implements parallel execution helpers. +package par + +import ( + "math/rand" + "sync" + "sync/atomic" +) + +// Work manages a set of work items to be executed in parallel, at most once each. +// The items in the set must all be valid map keys. +type Work struct { + f func(interface{}) // function to run for each item + running int // total number of runners + + mu sync.Mutex + added map[interface{}]bool // items added to set + todo []interface{} // items yet to be run + wait sync.Cond // wait when todo is empty + waiting int // number of runners waiting for todo +} + +func (w *Work) init() { + if w.added == nil { + w.added = make(map[interface{}]bool) + } +} + +// Add adds item to the work set, if it hasn't already been added. +func (w *Work) Add(item interface{}) { + w.mu.Lock() + w.init() + if !w.added[item] { + w.added[item] = true + w.todo = append(w.todo, item) + if w.waiting > 0 { + w.wait.Signal() + } + } + w.mu.Unlock() +} + +// Do runs f in parallel on items from the work set, +// with at most n invocations of f running at a time. +// It returns when everything added to the work set has been processed. +// At least one item should have been added to the work set +// before calling Do (or else Do returns immediately), +// but it is allowed for f(item) to add new items to the set. +// Do should only be used once on a given Work. +func (w *Work) Do(n int, f func(item interface{})) { + if n < 1 { + panic("par.Work.Do: n < 1") + } + if w.running >= 1 { + panic("par.Work.Do: already called Do") + } + + w.running = n + w.f = f + w.wait.L = &w.mu + + for i := 0; i < n-1; i++ { + go w.runner() + } + w.runner() +} + +// runner executes work in w until both nothing is left to do +// and all the runners are waiting for work. +// (Then all the runners return.) +func (w *Work) runner() { + for { + // Wait for something to do. + w.mu.Lock() + for len(w.todo) == 0 { + w.waiting++ + if w.waiting == w.running { + // All done. + w.wait.Broadcast() + w.mu.Unlock() + return + } + w.wait.Wait() + w.waiting-- + } + + // Pick something to do at random, + // to eliminate pathological contention + // in case items added at about the same time + // are most likely to contend. + i := rand.Intn(len(w.todo)) + item := w.todo[i] + w.todo[i] = w.todo[len(w.todo)-1] + w.todo = w.todo[:len(w.todo)-1] + w.mu.Unlock() + + w.f(item) + } +} + +// Cache runs an action once per key and caches the result. +type Cache struct { + m sync.Map +} + +type cacheEntry struct { + done uint32 + mu sync.Mutex + result interface{} +} + +// Do calls the function f if and only if Do is being called for the first time with this key. +// No call to Do with a given key returns until the one call to f returns. +// Do returns the value returned by the one call to f. +func (c *Cache) Do(key interface{}, f func() interface{}) interface{} { + entryIface, ok := c.m.Load(key) + if !ok { + entryIface, _ = c.m.LoadOrStore(key, new(cacheEntry)) + } + e := entryIface.(*cacheEntry) + if atomic.LoadUint32(&e.done) == 0 { + e.mu.Lock() + if atomic.LoadUint32(&e.done) == 0 { + e.result = f() + atomic.StoreUint32(&e.done, 1) + } + e.mu.Unlock() + } + return e.result +} + +// Get returns the cached result associated with key. +// It returns nil if there is no such result. +// If the result for key is being computed, Get does not wait for the computation to finish. +func (c *Cache) Get(key interface{}) interface{} { + entryIface, ok := c.m.Load(key) + if !ok { + return nil + } + e := entryIface.(*cacheEntry) + if atomic.LoadUint32(&e.done) == 0 { + return nil + } + return e.result +} diff --git a/src/cmd/go/internal/par/work_test.go b/src/cmd/go/internal/par/work_test.go new file mode 100644 index 0000000000..f104bc4106 --- /dev/null +++ b/src/cmd/go/internal/par/work_test.go @@ -0,0 +1,77 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package par + +import ( + "sync/atomic" + "testing" + "time" +) + +func TestWork(t *testing.T) { + var w Work + + const N = 10000 + n := int32(0) + w.Add(N) + w.Do(100, func(x interface{}) { + atomic.AddInt32(&n, 1) + i := x.(int) + if i >= 2 { + w.Add(i - 1) + w.Add(i - 2) + } + w.Add(i >> 1) + w.Add((i >> 1) ^ 1) + }) + if n != N+1 { + t.Fatalf("ran %d items, expected %d", n, N+1) + } +} + +func TestWorkParallel(t *testing.T) { + for tries := 0; tries < 10; tries++ { + var w Work + const N = 100 + for i := 0; i < N; i++ { + w.Add(i) + } + start := time.Now() + var n int32 + w.Do(N, func(x interface{}) { + time.Sleep(1 * time.Millisecond) + atomic.AddInt32(&n, +1) + }) + if n != N { + t.Fatalf("par.Work.Do did not do all the work") + } + if time.Since(start) < N/2*time.Millisecond { + return + } + } + t.Fatalf("par.Work.Do does not seem to be parallel") +} + +func TestCache(t *testing.T) { + var cache Cache + + n := 1 + v := cache.Do(1, func() interface{} { n++; return n }) + if v != 2 { + t.Fatalf("cache.Do(1) did not run f") + } + v = cache.Do(1, func() interface{} { n++; return n }) + if v != 2 { + t.Fatalf("cache.Do(1) ran f again!") + } + v = cache.Do(2, func() interface{} { n++; return n }) + if v != 3 { + t.Fatalf("cache.Do(2) did not run f") + } + v = cache.Do(1, func() interface{} { n++; return n }) + if v != 2 { + t.Fatalf("cache.Do(1) did not returned saved value from original cache.Do(1)") + } +} diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go index 8460d1fac6..303e6842e7 100644 --- a/src/cmd/go/internal/run/run.go +++ b/src/cmd/go/internal/run/run.go @@ -18,7 +18,7 @@ import ( ) var CmdRun = &base.Command{ - UsageLine: "run [build flags] [-exec xprog] package [arguments...]", + UsageLine: "go run [build flags] [-exec xprog] package [arguments...]", Short: "compile and run Go program", Long: ` Run compiles and runs the named main Go package. diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go index 42a6be0520..60ae73696b 100644 --- a/src/cmd/go/internal/search/search.go +++ b/src/cmd/go/internal/search/search.go @@ -17,32 +17,22 @@ import ( "strings" ) -// AllPackages returns all the packages that can be found +// A Match represents the result of matching a single package pattern. +type Match struct { + Pattern string // the pattern itself + Literal bool // whether it is a literal (no wildcards) + Pkgs []string // matching packages (dirs or import paths) +} + +// MatchPackages returns all the packages that can be found // under the $GOPATH directories and $GOROOT matching pattern. // The pattern is either "all" (all packages), "std" (standard packages), // "cmd" (standard commands), or a path including "...". -func AllPackages(pattern string) []string { - pkgs := MatchPackages(pattern) - if len(pkgs) == 0 { - fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) +func MatchPackages(pattern string) *Match { + m := &Match{ + Pattern: pattern, + Literal: false, } - return pkgs -} - -// AllPackagesInFS is like allPackages but is passed a pattern -// beginning ./ or ../, meaning it should scan the tree rooted -// at the given directory. There are ... in the pattern too. -func AllPackagesInFS(pattern string) []string { - pkgs := MatchPackagesInFS(pattern) - if len(pkgs) == 0 { - fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) - } - return pkgs -} - -// MatchPackages returns a list of package paths matching pattern -// (see go help packages for pattern syntax). -func MatchPackages(pattern string) []string { match := func(string) bool { return true } treeCanMatch := func(string) bool { return true } if !IsMetaPackage(pattern) { @@ -56,7 +46,6 @@ func MatchPackages(pattern string) []string { if !cfg.BuildContext.CgoEnabled { have["runtime/cgo"] = true // ignore during walk } - var pkgs []string for _, src := range cfg.BuildContext.SrcDirs() { if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc { @@ -123,11 +112,11 @@ func MatchPackages(pattern string) []string { return nil } - pkgs = append(pkgs, name) + m.Pkgs = append(m.Pkgs, name) return nil }) } - return pkgs + return m } var modRoot string @@ -136,10 +125,16 @@ func SetModRoot(dir string) { modRoot = dir } -// MatchPackagesInFS returns a list of package paths matching pattern, -// which must begin with ./ or ../ -// (see go help packages for pattern syntax). -func MatchPackagesInFS(pattern string) []string { +// MatchPackagesInFS is like allPackages but is passed a pattern +// beginning ./ or ../, meaning it should scan the tree rooted +// at the given directory. There are ... in the pattern too. +// (See go help packages for pattern syntax.) +func MatchPackagesInFS(pattern string) *Match { + m := &Match{ + Pattern: pattern, + Literal: false, + } + // Find directory to begin the scan. // Could be smarter but this one optimization // is enough for now, since ... is usually at the @@ -168,11 +163,11 @@ func MatchPackagesInFS(pattern string) []string { } } - var pkgs []string filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { if err != nil || !fi.IsDir() { return nil } + top := false if path == dir { // filepath.Walk starts at dir and recurses. For the recursive case, // the path is the result of filepath.Join, which calls filepath.Clean. @@ -182,6 +177,7 @@ func MatchPackagesInFS(pattern string) []string { // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io // package, because prepending the prefix "./" to the unclean path would // result in "././io", and match("././io") returns false. + top = true path = filepath.Clean(path) } @@ -192,6 +188,13 @@ func MatchPackagesInFS(pattern string) []string { return filepath.SkipDir } + if !top && cfg.ModulesEnabled { + // Ignore other modules found in subdirectories. + if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil { + return filepath.SkipDir + } + } + name := prefix + filepath.ToSlash(path) if !match(name) { return nil @@ -209,10 +212,10 @@ func MatchPackagesInFS(pattern string) []string { } return nil } - pkgs = append(pkgs, name) + m.Pkgs = append(m.Pkgs, name) return nil }) - return pkgs + return m } // TreeCanMatchPattern(pattern)(name) reports whether @@ -299,36 +302,53 @@ func replaceVendor(x, repl string) string { return strings.Join(elem, "/") } -// ImportPaths returns the import paths to use for the given command line. -func ImportPaths(args []string) []string { - args = CleanImportPaths(args) - var out []string - for _, a := range args { +// WarnUnmatched warns about patterns that didn't match any packages. +func WarnUnmatched(matches []*Match) { + for _, m := range matches { + if len(m.Pkgs) == 0 { + fmt.Fprintf(os.Stderr, "go: warning: %q matched no packages\n", m.Pattern) + } + } +} + +// ImportPaths returns the matching paths to use for the given command line. +// It calls ImportPathsQuiet and then WarnUnmatched. +func ImportPaths(patterns []string) []*Match { + matches := ImportPathsQuiet(patterns) + WarnUnmatched(matches) + return matches +} + +// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches. +func ImportPathsQuiet(patterns []string) []*Match { + var out []*Match + for _, a := range CleanPatterns(patterns) { if IsMetaPackage(a) { - out = append(out, AllPackages(a)...) + out = append(out, MatchPackages(a)) continue } if strings.Contains(a, "...") { if build.IsLocalImport(a) { - out = append(out, AllPackagesInFS(a)...) + out = append(out, MatchPackagesInFS(a)) } else { - out = append(out, AllPackages(a)...) + out = append(out, MatchPackages(a)) } continue } - out = append(out, a) + out = append(out, &Match{Pattern: a, Literal: true, Pkgs: []string{a}}) } return out } -// CleanImportPaths returns the import paths to use for the given -// command line, but it does no wildcard expansion. -func CleanImportPaths(args []string) []string { - if len(args) == 0 { +// CleanPatterns returns the patterns to use for the given +// command line. It canonicalizes the patterns but does not +// evaluate any matches. +func CleanPatterns(patterns []string) []string { + if len(patterns) == 0 { return []string{"."} } var out []string - for _, a := range args { + for _, a := range patterns { // Arguments are supposed to be import paths, but // as a courtesy to Windows developers, rewrite \ to / // in command-line arguments. Handles .\... and so on. @@ -350,22 +370,6 @@ func CleanImportPaths(args []string) []string { return out } -// ImportPathsNoDotExpansion returns the import paths to use for the given -// command line, but it does no ... expansion. -// TODO(vgo): Delete once old go get is gone. -func ImportPathsNoDotExpansion(args []string) []string { - args = CleanImportPaths(args) - var out []string - for _, a := range args { - if IsMetaPackage(a) { - out = append(out, AllPackages(a)...) - continue - } - out = append(out, a) - } - return out -} - // IsMetaPackage checks if name is a reserved package name that expands to multiple packages. func IsMetaPackage(name string) bool { return name == "std" || name == "cmd" || name == "all" @@ -421,3 +425,81 @@ func IsStandardImportPath(path string) bool { elem := path[:i] return !strings.Contains(elem, ".") } + +// IsRelativePath reports whether pattern should be interpreted as a directory +// path relative to the current directory, as opposed to a pattern matching +// import paths. +func IsRelativePath(pattern string) bool { + return strings.HasPrefix(pattern, "./") || strings.HasPrefix(pattern, "../") || pattern == "." || pattern == ".." +} + +// InDir checks whether path is in the file tree rooted at dir. +// If so, InDir returns an equivalent path relative to dir. +// If not, InDir returns an empty string. +// InDir makes some effort to succeed even in the presence of symbolic links. +// TODO(rsc): Replace internal/test.inDir with a call to this function for Go 1.12. +func InDir(path, dir string) string { + if rel := inDirLex(path, dir); rel != "" { + return rel + } + xpath, err := filepath.EvalSymlinks(path) + if err != nil || xpath == path { + xpath = "" + } else { + if rel := inDirLex(xpath, dir); rel != "" { + return rel + } + } + + xdir, err := filepath.EvalSymlinks(dir) + if err == nil && xdir != dir { + if rel := inDirLex(path, xdir); rel != "" { + return rel + } + if xpath != "" { + if rel := inDirLex(xpath, xdir); rel != "" { + return rel + } + } + } + return "" +} + +// inDirLex is like inDir but only checks the lexical form of the file names. +// It does not consider symbolic links. +// TODO(rsc): This is a copy of str.HasFilePathPrefix, modified to +// return the suffix. Most uses of str.HasFilePathPrefix should probably +// be calling InDir instead. +func inDirLex(path, dir string) string { + pv := strings.ToUpper(filepath.VolumeName(path)) + dv := strings.ToUpper(filepath.VolumeName(dir)) + path = path[len(pv):] + dir = dir[len(dv):] + switch { + default: + return "" + case pv != dv: + return "" + case len(path) == len(dir): + if path == dir { + return "." + } + return "" + case dir == "": + return path + case len(path) > len(dir): + if dir[len(dir)-1] == filepath.Separator { + if path[:len(dir)] == dir { + return path[len(dir):] + } + return "" + } + if path[len(dir)] == filepath.Separator && path[:len(dir)] == dir { + if len(path) == len(dir)+1 { + return "." + } + return path[len(dir)+1:] + } + return "" + } +} diff --git a/src/cmd/go/internal/semver/semver.go b/src/cmd/go/internal/semver/semver.go index ecc5300c8c..4af7118e55 100644 --- a/src/cmd/go/internal/semver/semver.go +++ b/src/cmd/go/internal/semver/semver.go @@ -69,6 +69,43 @@ func Major(v string) string { return v[:1+len(pv.major)] } +// MajorMinor returns the major.minor version prefix of the semantic version v. +// For example, MajorMinor("v2.1.0") == "v2.1". +// If v is an invalid semantic version string, MajorMinor returns the empty string. +func MajorMinor(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + i := 1 + len(pv.major) + if j := i + 1 + len(pv.minor); j <= len(v) && v[i] == '.' && v[i+1:j] == pv.minor { + return v[:j] + } + return v[:i] + "." + pv.minor +} + +// Prerelease returns the prerelease suffix of the semantic version v. +// For example, Prerelease("v2.1.0-pre+meta") == "-pre". +// If v is an invalid semantic version string, Prerelease returns the empty string. +func Prerelease(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.prerelease +} + +// Build returns the build suffix of the semantic version v. +// For example, Build("v2.1.0+meta") == "+meta". +// If v is an invalid semantic version string, Build returns the empty string. +func Build(v string) string { + pv, ok := parse(v) + if !ok { + return "" + } + return pv.build +} + // Compare returns an integer comparing two versions according to // according to semantic version precedence. // The result will be 0 if v == w, -1 if v < w, or +1 if v > w. diff --git a/src/cmd/go/internal/semver/semver_test.go b/src/cmd/go/internal/semver/semver_test.go index 7a697f6800..96b64a5807 100644 --- a/src/cmd/go/internal/semver/semver_test.go +++ b/src/cmd/go/internal/semver/semver_test.go @@ -14,6 +14,7 @@ var tests = []struct { out string }{ {"bad", ""}, + {"v1-alpha.beta.gamma", ""}, {"v1-pre", ""}, {"v1+meta", ""}, {"v1-pre+meta", ""}, @@ -42,6 +43,7 @@ var tests = []struct { {"v1.2.3-zzz", "v1.2.3-zzz"}, {"v1.2.3", "v1.2.3"}, {"v1.2.3+meta", "v1.2.3"}, + {"v1.2.3+meta-pre", "v1.2.3"}, } func TestIsValid(t *testing.T) { @@ -75,6 +77,63 @@ func TestMajor(t *testing.T) { } } +func TestMajorMinor(t *testing.T) { + for _, tt := range tests { + out := MajorMinor(tt.in) + var want string + if tt.out != "" { + want = tt.in + if i := strings.Index(want, "+"); i >= 0 { + want = want[:i] + } + if i := strings.Index(want, "-"); i >= 0 { + want = want[:i] + } + switch strings.Count(want, ".") { + case 0: + want += ".0" + case 1: + // ok + case 2: + want = want[:strings.LastIndex(want, ".")] + } + } + if out != want { + t.Errorf("MajorMinor(%q) = %q, want %q", tt.in, out, want) + } + } +} + +func TestPrerelease(t *testing.T) { + for _, tt := range tests { + pre := Prerelease(tt.in) + var want string + if tt.out != "" { + if i := strings.Index(tt.out, "-"); i >= 0 { + want = tt.out[i:] + } + } + if pre != want { + t.Errorf("Prerelease(%q) = %q, want %q", tt.in, pre, want) + } + } +} + +func TestBuild(t *testing.T) { + for _, tt := range tests { + build := Build(tt.in) + var want string + if tt.out != "" { + if i := strings.Index(tt.in, "+"); i >= 0 { + want = tt.in[i:] + } + } + if build != want { + t.Errorf("Build(%q) = %q, want %q", tt.in, build, want) + } + } +} + func TestCompare(t *testing.T) { for i, ti := range tests { for j, tj := range tests { diff --git a/src/cmd/go/internal/str/path.go b/src/cmd/go/internal/str/path.go index 84ca9d581e..a9b4d759a6 100644 --- a/src/cmd/go/internal/str/path.go +++ b/src/cmd/go/internal/str/path.go @@ -9,8 +9,25 @@ import ( "strings" ) -// HasFilePathPrefix reports whether the filesystem path s begins with the -// elements in prefix. +// HasPath reports whether the slash-separated path s +// begins with the elements in prefix. +func HasPathPrefix(s, prefix string) bool { + if len(s) == len(prefix) { + return s == prefix + } + if prefix == "" { + return true + } + if len(s) > len(prefix) { + if prefix[len(prefix)-1] == '/' || s[len(prefix)] == '/' { + return s[:len(prefix)] == prefix + } + } + return false +} + +// HasFilePathPrefix reports whether the filesystem path s +// begins with the elements in prefix. func HasFilePathPrefix(s, prefix string) bool { sv := strings.ToUpper(filepath.VolumeName(s)) pv := strings.ToUpper(filepath.VolumeName(prefix)) @@ -23,8 +40,10 @@ func HasFilePathPrefix(s, prefix string) bool { return false case len(s) == len(prefix): return s == prefix + case prefix == "": + return true case len(s) > len(prefix): - if prefix != "" && prefix[len(prefix)-1] == filepath.Separator { + if prefix[len(prefix)-1] == filepath.Separator { return strings.HasPrefix(s, prefix) } return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index aff5ff2c9d..3295e8ffe2 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -27,6 +27,7 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/load" + "cmd/go/internal/modload" "cmd/go/internal/str" "cmd/go/internal/work" "cmd/internal/test2json" @@ -37,7 +38,7 @@ func init() { CmdTest.Run = runTest } -const testUsage = "test [build/test flags] [packages] [build/test flags & test binary flags]" +const testUsage = "go test [build/test flags] [packages] [build/test flags & test binary flags]" var CmdTest = &base.Command{ CustomFlags: true, @@ -168,7 +169,7 @@ flags are also accessible by 'go test'. // Usage prints the usage message for 'go test -h' and exits. func Usage() { - os.Stderr.WriteString(testUsage + "\n\n" + + os.Stderr.WriteString("usage: " + testUsage + "\n\n" + strings.TrimSpace(testFlag1) + "\n\n\t" + strings.TrimSpace(testFlag2) + "\n") os.Exit(2) @@ -527,6 +528,8 @@ var testVetFlags = []string{ } func runTest(cmd *base.Command, args []string) { + modload.LoadTests = true + pkgArgs, testArgs = testFlags(args) work.FindExecCmd() // initialize cached result @@ -650,7 +653,7 @@ func runTest(cmd *base.Command, args []string) { } // Select for coverage all dependencies matching the testCoverPaths patterns. - for _, p := range load.PackageList(pkgs) { + for _, p := range load.TestPackageList(pkgs) { haveMatch := false for i := range testCoverPaths { if match[i](p) { @@ -698,7 +701,7 @@ func runTest(cmd *base.Command, args []string) { coverFiles = append(coverFiles, p.GoFiles...) coverFiles = append(coverFiles, p.CgoFiles...) coverFiles = append(coverFiles, p.TestGoFiles...) - p.Internal.CoverVars = declareCoverVars(p.ImportPath, coverFiles...) + p.Internal.CoverVars = declareCoverVars(p, coverFiles...) if testCover && testCoverMode == "atomic" { ensureImport(p, "sync/atomic") } @@ -716,13 +719,12 @@ func runTest(cmd *base.Command, args []string) { if err != nil { str := err.Error() str = strings.TrimPrefix(str, "\n") - failed := fmt.Sprintf("FAIL\t%s [setup failed]\n", p.ImportPath) - if p.ImportPath != "" { - base.Errorf("# %s\n%s\n%s", p.ImportPath, str, failed) + base.Errorf("# %s\n%s", p.ImportPath, str) } else { - base.Errorf("%s\n%s", str, failed) + base.Errorf("%s", str) } + fmt.Printf("FAIL\t%s [setup failed]\n", p.ImportPath) continue } builds = append(builds, buildTest) @@ -781,6 +783,14 @@ var windowsBadWords = []string{ } func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, printAction *work.Action, err error) { + if len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 { + build := b.CompileAction(work.ModeBuild, work.ModeBuild, p) + run := &work.Action{Mode: "test run", Package: p, Deps: []*work.Action{build}} + addTestVet(b, p, run, nil) + print := &work.Action{Mode: "test print", Func: builderNoTest, Package: p, Deps: []*work.Action{run}} + return build, run, print, nil + } + // Build Package structs describing: // pmain - pkg.test binary // ptest - package + test files @@ -885,8 +895,10 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin } runAction = installAction // make sure runAction != nil even if not running test } + var vetRunAction *work.Action if testC { printAction = &work.Action{Mode: "test print (nop)", Package: p, Deps: []*work.Action{runAction}} // nop + vetRunAction = printAction } else { // run test c := new(runCache) @@ -899,12 +911,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin TryCache: c.tryCache, Objdir: testDir, } - if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { - addTestVet(b, ptest, runAction, installAction) - } - if pxtest != nil { - addTestVet(b, pxtest, runAction, installAction) - } + vetRunAction = runAction cleanAction = &work.Action{ Mode: "test clean", Func: builderCleanTest, @@ -921,6 +928,14 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin IgnoreFail: true, // print even if test failed } } + + if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 { + addTestVet(b, ptest, vetRunAction, installAction) + } + if pxtest != nil { + addTestVet(b, pxtest, vetRunAction, installAction) + } + if installAction != nil { if runAction != installAction { installAction.Deps = append(installAction.Deps, runAction) @@ -958,7 +973,7 @@ func isTestFile(file string) bool { // declareCoverVars attaches the required cover variables names // to the files, to be used when annotating the files. -func declareCoverVars(importPath string, files ...string) map[string]*load.CoverVar { +func declareCoverVars(p *load.Package, files ...string) map[string]*load.CoverVar { coverVars := make(map[string]*load.CoverVar) coverIndex := 0 // We create the cover counters as new top-level variables in the package. @@ -967,14 +982,25 @@ func declareCoverVars(importPath string, files ...string) map[string]*load.Cover // so we append 12 hex digits from the SHA-256 of the import path. // The point is only to avoid accidents, not to defeat users determined to // break things. - sum := sha256.Sum256([]byte(importPath)) + sum := sha256.Sum256([]byte(p.ImportPath)) h := fmt.Sprintf("%x", sum[:6]) for _, file := range files { if isTestFile(file) { continue } + // For a package that is "local" (imported via ./ import or command line, outside GOPATH), + // we record the full path to the file name. + // Otherwise we record the import path, then a forward slash, then the file name. + // This makes profiles within GOPATH file system-independent. + // These names appear in the cmd/cover HTML interface. + var longFile string + if p.Internal.Local { + longFile = filepath.Join(p.Dir, file) + } else { + longFile = path.Join(p.ImportPath, file) + } coverVars[file] = &load.CoverVar{ - File: filepath.Join(importPath, file), + File: longFile, Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), } coverIndex++ @@ -1168,17 +1194,13 @@ func (c *runCache) builderRunTest(b *work.Builder, a *work.Action) error { if err == nil { norun := "" - res := "ok" if !testShowPass && !testJSON { buf.Reset() } - if len(a.Package.TestGoFiles)+len(a.Package.XTestGoFiles) == 0 { - res = "? " - norun = " [no test files]" - } else if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { + if bytes.HasPrefix(out, noTestsToRun[1:]) || bytes.Contains(out, noTestsToRun) { norun = " [no tests to run]" } - fmt.Fprintf(cmd.Stdout, "%s \t%s\t%s%s%s\n", res, a.Package.ImportPath, t, coveragePercentage(out), norun) + fmt.Fprintf(cmd.Stdout, "ok \t%s\t%s%s%s\n", a.Package.ImportPath, t, coveragePercentage(out), norun) c.saveOutput(a) } else { base.SetExitStatus(1) @@ -1592,3 +1614,15 @@ func builderPrintTest(b *work.Builder, a *work.Action) error { } return nil } + +// builderNoTest is the action for testing a package with no test files. +func builderNoTest(b *work.Builder, a *work.Action) error { + var stdout io.Writer = os.Stdout + if testJSON { + json := test2json.NewConverter(lockedStdout{}, a.Package.ImportPath, test2json.Timestamp) + defer json.Close() + stdout = json + } + fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", a.Package.ImportPath) + return nil +} diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go index 8a686b7125..73f8c69d9e 100644 --- a/src/cmd/go/internal/test/testflag.go +++ b/src/cmd/go/internal/test/testflag.go @@ -63,6 +63,7 @@ var testFlagDefn = []*cmdflag.Defn{ // add build flags to testFlagDefn func init() { + cmdflag.AddKnownFlags("test", testFlagDefn) var cmd base.Command work.AddBuildFlags(&cmd) cmd.Flag.VisitAll(func(f *flag.Flag) { @@ -87,6 +88,7 @@ func init() { // go test fmt -custom-flag-for-fmt-test // go test -x math func testFlags(args []string) (packageNames, passToTest []string) { + args = str.StringList(cmdflag.FindGOFLAGS(testFlagDefn), args) inPkg := false var explicitArgs []string for i := 0; i < len(args); i++ { diff --git a/src/cmd/go/internal/tool/tool.go b/src/cmd/go/internal/tool/tool.go index 4c7d0897e0..edcf93513d 100644 --- a/src/cmd/go/internal/tool/tool.go +++ b/src/cmd/go/internal/tool/tool.go @@ -18,7 +18,7 @@ import ( var CmdTool = &base.Command{ Run: runTool, - UsageLine: "tool [-n] command [args...]", + UsageLine: "go tool [-n] command [args...]", Short: "run specified go tool", Long: ` Tool runs the go tool command identified by the arguments. diff --git a/src/cmd/go/internal/txtar/archive.go b/src/cmd/go/internal/txtar/archive.go new file mode 100644 index 0000000000..c384f33bdf --- /dev/null +++ b/src/cmd/go/internal/txtar/archive.go @@ -0,0 +1,140 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package txtar implements a trivial text-based file archive format. +// +// The goals for the format are: +// +// - be trivial enough to create and edit by hand. +// - be able to store trees of text files describing go command test cases. +// - diff nicely in git history and code reviews. +// +// Non-goals include being a completely general archive format, +// storing binary data, storing file modes, storing special files like +// symbolic links, and so on. +// +// Txtar format +// +// A txtar archive is zero or more comment lines and then a sequence of file entries. +// Each file entry begins with a file marker line of the form "-- FILENAME --" +// and is followed by zero or more file content lines making up the file data. +// The comment or file content ends at the next file marker line. +// The file marker line must begin with the three-byte sequence "-- " +// and end with the three-byte sequence " --", but the enclosed +// file name can be surrounding by additional white space, +// all of which is stripped. +// +// If the txtar file is missing a trailing newline on the final line, +// parsers should consider a final newline to be present anyway. +// +// There are no possible syntax errors in a txtar archive. +package txtar + +import ( + "bytes" + "fmt" + "io/ioutil" + "strings" +) + +// An Archive is a collection of files. +type Archive struct { + Comment []byte + Files []File +} + +// A File is a single file in an archive. +type File struct { + Name string // name of file ("foo/bar.txt") + Data []byte // text content of file +} + +// Format returns the serialized form of an Archive. +// It is assumed that the Archive data structure is well-formed: +// a.Comment and all a.File[i].Data contain no file marker lines, +// and all a.File[i].Name is non-empty. +func Format(a *Archive) []byte { + var buf bytes.Buffer + buf.Write(fixNL(a.Comment)) + for _, f := range a.Files { + fmt.Fprintf(&buf, "-- %s --\n", f.Name) + buf.Write(fixNL(f.Data)) + } + return buf.Bytes() +} + +// ParseFile parses the named file as an archive. +func ParseFile(file string) (*Archive, error) { + data, err := ioutil.ReadFile(file) + if err != nil { + return nil, err + } + return Parse(data), nil +} + +// Parse parses the serialized form of an Archive. +// The returned Archive holds slices of data. +func Parse(data []byte) *Archive { + a := new(Archive) + var name string + a.Comment, name, data = findFileMarker(data) + for name != "" { + f := File{name, nil} + f.Data, name, data = findFileMarker(data) + a.Files = append(a.Files, f) + } + return a +} + +var ( + newlineMarker = []byte("\n-- ") + marker = []byte("-- ") + markerEnd = []byte(" --") +) + +// findFileMarker finds the next file marker in data, +// extracts the file name, and returns the data before the marker, +// the file name, and the data after the marker. +// If there is no next marker, findFileMarker returns before = fixNL(data), name = "", after = nil. +func findFileMarker(data []byte) (before []byte, name string, after []byte) { + var i int + for { + if name, after = isMarker(data[i:]); name != "" { + return data[:i], name, after + } + j := bytes.Index(data[i:], newlineMarker) + if j < 0 { + return fixNL(data), "", nil + } + i += j + 1 // positioned at start of new possible marker + } +} + +// isMarker checks whether data begins with a file marker line. +// If so, it returns the name from the line and the data after the line. +// Otherwise it returns name == "" with an unspecified after. +func isMarker(data []byte) (name string, after []byte) { + if !bytes.HasPrefix(data, marker) { + return "", nil + } + if i := bytes.IndexByte(data, '\n'); i >= 0 { + data, after = data[:i], data[i+1:] + } + if !bytes.HasSuffix(data, markerEnd) { + return "", nil + } + return strings.TrimSpace(string(data[len(marker) : len(data)-len(markerEnd)])), after +} + +// If data is empty or ends in \n, fixNL returns data. +// Otherwise fixNL returns a new slice consisting of data with a final \n added. +func fixNL(data []byte) []byte { + if len(data) == 0 || data[len(data)-1] == '\n' { + return data + } + d := make([]byte, len(data)+1) + copy(d, data) + d[len(data)] = '\n' + return d +} diff --git a/src/cmd/go/internal/txtar/archive_test.go b/src/cmd/go/internal/txtar/archive_test.go new file mode 100644 index 0000000000..3f734f6762 --- /dev/null +++ b/src/cmd/go/internal/txtar/archive_test.go @@ -0,0 +1,67 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package txtar + +import ( + "bytes" + "fmt" + "reflect" + "testing" +) + +var tests = []struct { + name string + text string + parsed *Archive +}{ + { + name: "basic", + text: `comment1 +comment2 +-- file1 -- +File 1 text. +-- foo --- +More file 1 text. +-- file 2 -- +File 2 text. +-- empty -- +-- noNL -- +hello world`, + parsed: &Archive{ + Comment: []byte("comment1\ncomment2\n"), + Files: []File{ + {"file1", []byte("File 1 text.\n-- foo ---\nMore file 1 text.\n")}, + {"file 2", []byte("File 2 text.\n")}, + {"empty", []byte{}}, + {"noNL", []byte("hello world\n")}, + }, + }, + }, +} + +func Test(t *testing.T) { + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := Parse([]byte(tt.text)) + if !reflect.DeepEqual(a, tt.parsed) { + t.Fatalf("Parse: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed)) + } + text := Format(a) + a = Parse(text) + if !reflect.DeepEqual(a, tt.parsed) { + t.Fatalf("Parse after Format: wrong output:\nhave:\n%s\nwant:\n%s", shortArchive(a), shortArchive(tt.parsed)) + } + }) + } +} + +func shortArchive(a *Archive) string { + var buf bytes.Buffer + fmt.Fprintf(&buf, "comment: %q\n", a.Comment) + for _, f := range a.Files { + fmt.Fprintf(&buf, "file %q: %q\n", f.Name, f.Data) + } + return buf.String() +} diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go index c3f7d73ff1..9344a28dc3 100644 --- a/src/cmd/go/internal/version/version.go +++ b/src/cmd/go/internal/version/version.go @@ -14,7 +14,7 @@ import ( var CmdVersion = &base.Command{ Run: runVersion, - UsageLine: "version", + UsageLine: "go version", Short: "print Go version", Long: `Version prints the Go version, as reported by runtime.Version.`, } diff --git a/src/cmd/go/internal/vet/vet.go b/src/cmd/go/internal/vet/vet.go index 9cb2aaa656..b64bf3f8e8 100644 --- a/src/cmd/go/internal/vet/vet.go +++ b/src/cmd/go/internal/vet/vet.go @@ -8,6 +8,7 @@ package vet import ( "cmd/go/internal/base" "cmd/go/internal/load" + "cmd/go/internal/modload" "cmd/go/internal/work" "path/filepath" ) @@ -15,7 +16,7 @@ import ( var CmdVet = &base.Command{ Run: runVet, CustomFlags: true, - UsageLine: "vet [-n] [-x] [build flags] [vet flags] [packages]", + UsageLine: "go vet [-n] [-x] [build flags] [vet flags] [packages]", Short: "report likely mistakes in packages", Long: ` Vet runs the Go vet command on the packages named by the import paths. @@ -35,6 +36,8 @@ See also: go fmt, go fix. } func runVet(cmd *base.Command, args []string) { + modload.LoadTests = true + vetFlags, pkgArgs := vetFlags(args) work.BuildInit() diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go index bdfe033018..50eac425ec 100644 --- a/src/cmd/go/internal/vet/vetflag.go +++ b/src/cmd/go/internal/vet/vetflag.go @@ -12,6 +12,7 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cmdflag" + "cmd/go/internal/str" "cmd/go/internal/work" ) @@ -26,39 +27,40 @@ var vetFlagDefn = []*cmdflag.Defn{ // to vet. We handle them in vetFlags. // local. - {Name: "all", BoolVar: new(bool)}, - {Name: "asmdecl", BoolVar: new(bool)}, - {Name: "assign", BoolVar: new(bool)}, - {Name: "atomic", BoolVar: new(bool)}, - {Name: "bool", BoolVar: new(bool)}, - {Name: "buildtags", BoolVar: new(bool)}, - {Name: "cgocall", BoolVar: new(bool)}, - {Name: "composites", BoolVar: new(bool)}, - {Name: "copylocks", BoolVar: new(bool)}, - {Name: "httpresponse", BoolVar: new(bool)}, - {Name: "lostcancel", BoolVar: new(bool)}, - {Name: "methods", BoolVar: new(bool)}, - {Name: "nilfunc", BoolVar: new(bool)}, - {Name: "printf", BoolVar: new(bool)}, - {Name: "printfuncs"}, - {Name: "rangeloops", BoolVar: new(bool)}, - {Name: "shadow", BoolVar: new(bool)}, - {Name: "shadowstrict", BoolVar: new(bool)}, - {Name: "shift", BoolVar: new(bool)}, - {Name: "source", BoolVar: new(bool)}, - {Name: "structtags", BoolVar: new(bool)}, - {Name: "tests", BoolVar: new(bool)}, - {Name: "unreachable", BoolVar: new(bool)}, - {Name: "unsafeptr", BoolVar: new(bool)}, - {Name: "unusedfuncs"}, - {Name: "unusedresult", BoolVar: new(bool)}, - {Name: "unusedstringmethods"}, + {Name: "all", BoolVar: new(bool), PassToTest: true}, + {Name: "asmdecl", BoolVar: new(bool), PassToTest: true}, + {Name: "assign", BoolVar: new(bool), PassToTest: true}, + {Name: "atomic", BoolVar: new(bool), PassToTest: true}, + {Name: "bool", BoolVar: new(bool), PassToTest: true}, + {Name: "buildtags", BoolVar: new(bool), PassToTest: true}, + {Name: "cgocall", BoolVar: new(bool), PassToTest: true}, + {Name: "composites", BoolVar: new(bool), PassToTest: true}, + {Name: "copylocks", BoolVar: new(bool), PassToTest: true}, + {Name: "httpresponse", BoolVar: new(bool), PassToTest: true}, + {Name: "lostcancel", BoolVar: new(bool), PassToTest: true}, + {Name: "methods", BoolVar: new(bool), PassToTest: true}, + {Name: "nilfunc", BoolVar: new(bool), PassToTest: true}, + {Name: "printf", BoolVar: new(bool), PassToTest: true}, + {Name: "printfuncs", PassToTest: true}, + {Name: "rangeloops", BoolVar: new(bool), PassToTest: true}, + {Name: "shadow", BoolVar: new(bool), PassToTest: true}, + {Name: "shadowstrict", BoolVar: new(bool), PassToTest: true}, + {Name: "shift", BoolVar: new(bool), PassToTest: true}, + {Name: "source", BoolVar: new(bool), PassToTest: true}, + {Name: "structtags", BoolVar: new(bool), PassToTest: true}, + {Name: "tests", BoolVar: new(bool), PassToTest: true}, + {Name: "unreachable", BoolVar: new(bool), PassToTest: true}, + {Name: "unsafeptr", BoolVar: new(bool), PassToTest: true}, + {Name: "unusedfuncs", PassToTest: true}, + {Name: "unusedresult", BoolVar: new(bool), PassToTest: true}, + {Name: "unusedstringmethods", PassToTest: true}, } var vetTool string // add build flags to vetFlagDefn. func init() { + cmdflag.AddKnownFlags("vet", vetFlagDefn) var cmd base.Command work.AddBuildFlags(&cmd) cmd.Flag.StringVar(&vetTool, "vettool", "", "path to vet tool binary") // for cmd/vet tests; undocumented for now @@ -73,6 +75,7 @@ func init() { // vetFlags processes the command line, splitting it at the first non-flag // into the list of flags and list of packages. func vetFlags(args []string) (passToVet, packageNames []string) { + args = str.StringList(cmdflag.FindGOFLAGS(vetFlagDefn), args) for i := 0; i < len(args); i++ { if !strings.HasPrefix(args[i], "-") { return args[:i], args[i:] @@ -88,9 +91,17 @@ func vetFlags(args []string) (passToVet, packageNames []string) { if err := f.Value.Set(value); err != nil { base.Fatalf("invalid flag argument for -%s: %v", f.Name, err) } - switch f.Name { - // Flags known to the build but not to vet, so must be dropped. - case "a", "x", "n", "vettool", "compiler": + keep := f.PassToTest + if !keep { + // A build flag, probably one we don't want to pass to vet. + // Can whitelist. + switch f.Name { + case "tags", "v": + keep = true + } + } + if !keep { + // Flags known to the build but not to vet, so must be dropped. if extraWord { args = append(args[:i], args[i+2:]...) extraWord = false diff --git a/src/cmd/go/internal/vgo/build.go b/src/cmd/go/internal/vgo/build.go deleted file mode 100644 index ba103099aa..0000000000 --- a/src/cmd/go/internal/vgo/build.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "bytes" - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/modinfo" - "cmd/go/internal/module" - "cmd/go/internal/search" - "encoding/hex" - "fmt" - "os" - "path/filepath" -) - -var ( - infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6") - infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2") -) - -func isStandardImportPath(path string) bool { - if search.IsStandardImportPath(path) { - if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src", path)); err == nil { - return true - } - if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src/vendor", path)); err == nil { - return true - } - } - return false -} - -func PackageModuleInfo(path string) *modinfo.ModulePublic { - var info modinfo.ModulePublic - if isStandardImportPath(path) || !Enabled() { - return nil - } - target := findModule(path, path) - info.Top = target.Path == buildList[0].Path - info.Path = target.Path - info.Version = target.Version - return &info -} - -func PackageBuildInfo(path string, deps []string) string { - if isStandardImportPath(path) || !Enabled() { - return "" - } - target := findModule(path, path) - mdeps := make(map[module.Version]bool) - for _, dep := range deps { - if !isStandardImportPath(dep) { - mdeps[findModule(path, dep)] = true - } - } - var mods []module.Version - delete(mdeps, target) - for mod := range mdeps { - mods = append(mods, mod) - } - sortModules(mods) - - var buf bytes.Buffer - fmt.Fprintf(&buf, "path\t%s\n", path) - tv := target.Version - if tv == "" { - tv = "(devel)" - } - fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, findModHash(target)) - for _, mod := range mods { - mv := mod.Version - if mv == "" { - mv = "(devel)" - } - r := replaced(mod) - h := "" - if r == nil { - h = "\t" + findModHash(mod) - } - fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h) - if r := replaced(mod); r != nil { - fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.New.Path, r.New.Version, findModHash(r.New)) - } - } - return buf.String() -} - -func findModule(target, path string) module.Version { - if path == "." { - return buildList[0] - } - for _, mod := range buildList { - if importPathInModule(path, mod.Path) { - return mod - } - } - base.Fatalf("build %v: cannot find module for path %v", target, path) - panic("unreachable") -} - -func ModInfoProg(info string) []byte { - return []byte(fmt.Sprintf(` - package main - import _ "unsafe" - //go:linkname __debug_modinfo__ runtime/debug.modinfo - var __debug_modinfo__ string - func init() { - __debug_modinfo__ = %q - } - `, string(infoStart)+info+string(infoEnd))) -} diff --git a/src/cmd/go/internal/vgo/fetch.go b/src/cmd/go/internal/vgo/fetch.go deleted file mode 100644 index c28353ccfa..0000000000 --- a/src/cmd/go/internal/vgo/fetch.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "archive/zip" - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - - "cmd/go/internal/base" - "cmd/go/internal/dirhash" - "cmd/go/internal/modfetch" - "cmd/go/internal/module" - "cmd/go/internal/semver" -) - -// fetch returns the directory in the local download cache -// holding the root of mod's source tree. -// It downloads the module if needed. -func fetch(mod module.Version) (dir string, err error) { - if r := replaced(mod); r != nil { - if r.New.Version == "" { - dir = r.New.Path - if !filepath.IsAbs(dir) { - dir = filepath.Join(ModRoot, dir) - } - return dir, nil - } - mod = r.New - } - - modpath := mod.Path + "@" + mod.Version - dir = filepath.Join(srcV, modpath) - if files, _ := ioutil.ReadDir(dir); len(files) == 0 { - zipfile := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".zip") - if _, err := os.Stat(zipfile); err == nil { - // Use it. - // This should only happen if the v/cache directory is preinitialized - // or if src/v/modpath was removed but not src/v/cache. - fmt.Fprintf(os.Stderr, "vgo: extracting %s %s\n", mod.Path, mod.Version) - } else { - if err := os.MkdirAll(filepath.Join(srcV, "cache", mod.Path, "@v"), 0777); err != nil { - return "", err - } - fmt.Fprintf(os.Stderr, "vgo: downloading %s %s\n", mod.Path, mod.Version) - if err := downloadZip(mod, zipfile); err != nil { - return "", err - } - } - if err := modfetch.Unzip(dir, zipfile, modpath, 0); err != nil { - fmt.Fprintf(os.Stderr, "-> %s\n", err) - return "", err - } - } - checkModHash(mod) - return dir, nil -} - -func downloadZip(mod module.Version, target string) error { - repo, err := modfetch.Lookup(mod.Path) - if err != nil { - return err - } - tmpfile, err := repo.Zip(mod.Version, os.TempDir()) - if err != nil { - return err - } - defer os.Remove(tmpfile) - - // Double-check zip file looks OK. - z, err := zip.OpenReader(tmpfile) - if err != nil { - z.Close() - return err - } - prefix := mod.Path + "@" + mod.Version - for _, f := range z.File { - if !strings.HasPrefix(f.Name, prefix) { - z.Close() - return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name) - } - } - z.Close() - - hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash) - if err != nil { - return err - } - r, err := os.Open(tmpfile) - if err != nil { - return err - } - defer r.Close() - w, err := os.Create(target) - if err != nil { - return err - } - if _, err := io.Copy(w, r); err != nil { - w.Close() - return fmt.Errorf("copying: %v", err) - } - if err := w.Close(); err != nil { - return err - } - return ioutil.WriteFile(target+"hash", []byte(hash), 0666) -} - -var useModHash = false -var modHash map[module.Version][]string - -func initModHash() { - if modHash != nil { - return - } - modHash = make(map[module.Version][]string) - file := filepath.Join(ModRoot, "go.modverify") - data, err := ioutil.ReadFile(file) - if err != nil && os.IsNotExist(err) { - return - } - if err != nil { - base.Fatalf("vgo: %v", err) - } - useModHash = true - lineno := 0 - for len(data) > 0 { - var line []byte - lineno++ - i := bytes.IndexByte(data, '\n') - if i < 0 { - line, data = data, nil - } else { - line, data = data[:i], data[i+1:] - } - f := strings.Fields(string(line)) - if len(f) == 0 { - // blank line; skip it - continue - } - if len(f) != 3 { - base.Fatalf("vgo: malformed go.modverify:\n%s:%d: wrong number of fields %v", file, lineno, len(f)) - } - mod := module.Version{Path: f[0], Version: f[1]} - modHash[mod] = append(modHash[mod], f[2]) - } -} - -func checkModHash(mod module.Version) { - initModHash() - if !useModHash { - return - } - - data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash")) - if err != nil { - base.Fatalf("vgo: verifying %s %s: %v", mod.Path, mod.Version, err) - } - h := strings.TrimSpace(string(data)) - if !strings.HasPrefix(h, "h1:") { - base.Fatalf("vgo: verifying %s %s: unexpected ziphash: %q", mod.Path, mod.Version, h) - } - - for _, vh := range modHash[mod] { - if h == vh { - return - } - if strings.HasPrefix(vh, "h1:") { - base.Fatalf("vgo: verifying %s %s: module hash mismatch\n\tdownloaded: %v\n\tgo.modverify: %v", mod.Path, mod.Version, h, vh) - } - } - if len(modHash[mod]) > 0 { - fmt.Fprintf(os.Stderr, "warning: verifying %s %s: unknown hashes in go.modverify: %v; adding %v", mod.Path, mod.Version, strings.Join(modHash[mod], ", "), h) - } - modHash[mod] = append(modHash[mod], h) -} - -func findModHash(mod module.Version) string { - data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash")) - if err != nil { - return "" - } - return strings.TrimSpace(string(data)) -} - -func writeModHash() { - if !useModHash { - return - } - - var mods []module.Version - for m := range modHash { - mods = append(mods, m) - } - sortModules(mods) - var buf bytes.Buffer - for _, m := range mods { - list := modHash[m] - sort.Strings(list) - for _, h := range list { - fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h) - } - } - - file := filepath.Join(ModRoot, "go.modverify") - data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "go.modverify")) - if bytes.Equal(data, buf.Bytes()) { - return - } - - if err := ioutil.WriteFile(file, buf.Bytes(), 0666); err != nil { - base.Fatalf("vgo: writing go.modverify: %v", err) - } -} - -func sortModules(mods []module.Version) { - sort.Slice(mods, func(i, j int) bool { - mi := mods[i] - mj := mods[j] - if mi.Path != mj.Path { - return mi.Path < mj.Path - } - return semver.Compare(mi.Version, mj.Version) < 0 - }) -} diff --git a/src/cmd/go/internal/vgo/get.go b/src/cmd/go/internal/vgo/get.go deleted file mode 100644 index 9fd8497f9d..0000000000 --- a/src/cmd/go/internal/vgo/get.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "strings" - - "cmd/go/internal/base" - "cmd/go/internal/modfetch" - "cmd/go/internal/module" - "cmd/go/internal/mvs" - "cmd/go/internal/semver" -) - -var CmdGet = &base.Command{ - UsageLine: "get [build flags] [packages]", - Short: "download and install versioned modules and dependencies", - Long: ` -Get downloads the latest versions of modules containing the named packages, -along with the versions of the dependencies required by those modules -(not necessarily the latest ones). - -It then installs the named packages, like 'go install'. - -The -u flag causes get to download the latest version of dependencies as well. - -Each package being updated can be suffixed with @version to specify -the desired version. Specifying a version older than the one currently -in use causes a downgrade, which may in turn downgrade other -modules using that one, to keep everything consistent. - -TODO: Make this documentation better once the semantic dust settles. - `, -} - -var getU = CmdGet.Flag.Bool("u", false, "") - -func init() { - CmdGet.Run = runGet // break init loop -} - -func runGet(cmd *base.Command, args []string) { - if *getU && len(args) > 0 { - base.Fatalf("vgo get: -u not supported with argument list") - } - if !*getU && len(args) == 0 { - base.Fatalf("vgo get: need arguments or -u") - } - - if *getU { - isGetU = true - ImportPaths([]string{"."}) - return - } - - Init() - InitMod() - var upgrade []module.Version - var downgrade []module.Version - var newPkgs []string - for _, pkg := range args { - var path, vers string - /* OLD CODE - if n := strings.Count(pkg, "(") + strings.Count(pkg, ")"); n > 0 { - i := strings.Index(pkg, "(") - j := strings.Index(pkg, ")") - if n != 2 || i < 0 || j <= i+1 || j != len(pkg)-1 && pkg[j+1] != '/' { - base.Errorf("vgo get: invalid module version syntax: %s", pkg) - continue - } - path, vers = pkg[:i], pkg[i+1:j] - pkg = pkg[:i] + pkg[j+1:] - */ - if i := strings.Index(pkg, "@"); i >= 0 { - path, pkg, vers = pkg[:i], pkg[:i], pkg[i+1:] - if strings.Contains(vers, "@") { - base.Errorf("vgo get: invalid module version syntax: %s", pkg) - continue - } - } else { - path = pkg - vers = "latest" - } - if vers == "none" { - downgrade = append(downgrade, module.Version{Path: path, Version: ""}) - } else { - info, err := modfetch.Query(path, vers, allowed) - if err != nil { - base.Errorf("vgo get %v: %v", pkg, err) - continue - } - upgrade = append(upgrade, module.Version{Path: path, Version: info.Version}) - newPkgs = append(newPkgs, pkg) - } - } - args = newPkgs - - // Upgrade. - var err error - buildList, err = mvs.Upgrade(Target, newReqs(), upgrade...) - if err != nil { - base.Fatalf("vgo get: %v", err) - } - - importPaths([]string{"."}) - - // Downgrade anything that went too far. - version := make(map[string]string) - for _, mod := range buildList { - version[mod.Path] = mod.Version - } - for _, mod := range upgrade { - if semver.Compare(mod.Version, version[mod.Path]) < 0 { - downgrade = append(downgrade, mod) - } - } - - if len(downgrade) > 0 { - buildList, err = mvs.Downgrade(Target, newReqs(buildList[1:]...), downgrade...) - if err != nil { - base.Fatalf("vgo get: %v", err) - } - - // TODO: Check that everything we need to import is still available. - /* - local := v.matchPackages("all", v.Reqs[:1]) - for _, path := range local { - dir, err := v.importDir(path) - if err != nil { - return err // TODO - } - imports, testImports, err := imports.ScanDir(dir, v.Tags) - for _, path := range imports { - xxx - } - for _, path := range testImports { - xxx - } - } - */ - } - writeGoMod() - - if len(args) > 0 { - InstallHook(args) - } -} - -// Call into "go install". Set by internal/work, which imports us. -var InstallHook func([]string) diff --git a/src/cmd/go/internal/vgo/init.go b/src/cmd/go/internal/vgo/init.go deleted file mode 100644 index b307b6b1fe..0000000000 --- a/src/cmd/go/internal/vgo/init.go +++ /dev/null @@ -1,411 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "bytes" - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/modconv" - "cmd/go/internal/modfetch" - "cmd/go/internal/modfetch/codehost" - "cmd/go/internal/modfile" - "cmd/go/internal/module" - "cmd/go/internal/mvs" - "cmd/go/internal/search" - "cmd/go/internal/semver" - "encoding/json" - "flag" - "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "regexp" - "strconv" - "strings" -) - -var ( - cwd string - enabled = MustBeVgo - MustBeVgo = mustBeVgo() - initialized bool - - ModRoot string - modFile *modfile.File - excluded map[module.Version]bool - Target module.Version - - gopath string - srcV string -) - -func BinDir() string { - if !Enabled() { - panic("vgo.Bin") - } - return filepath.Join(gopath, "bin") -} - -func init() { - flag.BoolVar(&MustBeVgo, "vgo", MustBeVgo, "require use of modules") -} - -// mustBeVgo reports whether we are invoked as vgo -// (as opposed to go). -// If so, we only support builds with go.mod files. -func mustBeVgo() bool { - name := os.Args[0] - name = name[strings.LastIndex(name, "/")+1:] - name = name[strings.LastIndex(name, `\`)+1:] - return strings.HasPrefix(name, "vgo") -} - -func Init() { - if initialized { - return - } - initialized = true - - // If this is testgo - the test binary during cmd/go tests - then - // do not let it look for a go.mod. Only use vgo support if the - // global -vgo flag has been passed on the command line. - if base := filepath.Base(os.Args[0]); (base == "testgo" || base == "testgo.exe") && !MustBeVgo { - return - } - - // Disable any prompting for passwords by Git. - // Only has an effect for 2.3.0 or later, but avoiding - // the prompt in earlier versions is just too hard. - // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep - // prompting. - // See golang.org/issue/9341 and golang.org/issue/12706. - if os.Getenv("GIT_TERMINAL_PROMPT") == "" { - os.Setenv("GIT_TERMINAL_PROMPT", "0") - } - - // Disable any ssh connection pooling by Git. - // If a Git subprocess forks a child into the background to cache a new connection, - // that child keeps stdout/stderr open. After the Git subprocess exits, - // os /exec expects to be able to read from the stdout/stderr pipe - // until EOF to get all the data that the Git subprocess wrote before exiting. - // The EOF doesn't come until the child exits too, because the child - // is holding the write end of the pipe. - // This is unfortunate, but it has come up at least twice - // (see golang.org/issue/13453 and golang.org/issue/16104) - // and confuses users when it does. - // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, - // assume they know what they are doing and don't step on it. - // But default to turning off ControlMaster. - if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { - os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no") - } - - var err error - cwd, err = os.Getwd() - if err != nil { - base.Fatalf("go: %v", err) - } - - root, _ := FindModuleRoot(cwd, "", MustBeVgo) - if root == "" { - // If invoked as vgo, insist on a mod file. - if MustBeVgo { - base.Fatalf("cannot determine module root; please create a go.mod file there") - } - return - } - enabled = true - ModRoot = root - search.SetModRoot(root) -} - -func Enabled() bool { - return false // COMPLETELY OFF FOR NOW - /* - if !initialized { - panic("vgo: Enabled called before Init") - } - return enabled - */ -} - -func InitMod() { - if Init(); !Enabled() || modFile != nil { - return - } - - list := filepath.SplitList(cfg.BuildContext.GOPATH) - if len(list) == 0 || list[0] == "" { - base.Fatalf("missing $GOPATH") - } - gopath = list[0] - if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil { - base.Fatalf("$GOPATH/go.mod exists but should not") - } - srcV = filepath.Join(list[0], "src/v") - codehost.WorkRoot = filepath.Join(srcV, "cache/vcswork") - - gomod := filepath.Join(ModRoot, "go.mod") - data, err := ioutil.ReadFile(gomod) - if err != nil { - legacyModInit() - return - } - - f, err := modfile.Parse(gomod, data, fixVersion) - if err != nil { - // Errors returned by modfile.Parse begin with file:line. - base.Fatalf("vgo: errors parsing go.mod:\n%s\n", err) - } - modFile = f - - if len(f.Syntax.Stmt) == 0 || f.Module == nil { - // Empty mod file. Must add module path. - path, err := FindModulePath(ModRoot) - if err != nil { - base.Fatalf("vgo: %v", err) - } - f.AddModuleStmt(path) - } - - if len(f.Syntax.Stmt) == 1 && f.Module != nil { - // Entire file is just a module statement. - // Populate require if possible. - legacyModInit() - } - - excluded = make(map[module.Version]bool) - for _, x := range f.Exclude { - excluded[x.Mod] = true - } - Target = f.Module.Mod - writeGoMod() -} - -func allowed(m module.Version) bool { - return !excluded[m] -} - -func legacyModInit() { - if modFile == nil { - path, err := FindModulePath(ModRoot) - if err != nil { - base.Fatalf("vgo: %v", err) - } - fmt.Fprintf(os.Stderr, "vgo: creating new go.mod: module %s\n", path) - modFile = new(modfile.File) - modFile.AddModuleStmt(path) - } - - Target = modFile.Module.Mod - for _, name := range altConfigs { - cfg := filepath.Join(ModRoot, name) - data, err := ioutil.ReadFile(cfg) - if err == nil { - convert := modconv.Converters[name] - if convert == nil { - return - } - fmt.Fprintf(os.Stderr, "vgo: copying requirements from %s\n", cfg) - cfg = filepath.ToSlash(cfg) - if err := modfetch.ConvertLegacyConfig(modFile, cfg, data); err != nil { - base.Fatalf("vgo: %v", err) - } - if len(modFile.Syntax.Stmt) == 1 { - // Add comment to prevent vgo from re-converting every time it runs. - modFile.AddComment("// vgo: no requirements found in " + name) - } - return - } - } -} - -var altConfigs = []string{ - "Gopkg.lock", - - "GLOCKFILE", - "Godeps/Godeps.json", - "dependencies.tsv", - "glide.lock", - "vendor.conf", - "vendor.yml", - "vendor/manifest", - "vendor/vendor.json", - - ".git/config", -} - -// Exported only for testing. -func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) { - dir = filepath.Clean(dir) - dir1 := dir - limit = filepath.Clean(limit) - - // Look for enclosing go.mod. - for { - if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil { - return dir, "go.mod" - } - if dir == limit { - break - } - d := filepath.Dir(dir) - if d == dir { - break - } - dir = d - } - - // Failing that, look for enclosing alternate version config. - if legacyConfigOK { - dir = dir1 - for { - for _, name := range altConfigs { - if _, err := os.Stat(filepath.Join(dir, name)); err == nil { - return dir, name - } - } - if dir == limit { - break - } - d := filepath.Dir(dir) - if d == dir { - break - } - dir = d - } - } - - return "", "" -} - -// Exported only for testing. -func FindModulePath(dir string) (string, error) { - for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) { - src := filepath.Join(gpdir, "src") + string(filepath.Separator) - if strings.HasPrefix(dir, src) { - return filepath.ToSlash(dir[len(src):]), nil - } - } - - // Cast about for import comments, - // first in top-level directory, then in subdirectories. - list, _ := ioutil.ReadDir(dir) - for _, info := range list { - if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") { - if com := findImportComment(filepath.Join(dir, info.Name())); com != "" { - return com, nil - } - } - } - for _, info1 := range list { - if info1.IsDir() { - files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name())) - for _, info2 := range files { - if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") { - if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" { - return path.Dir(com), nil - } - } - } - } - } - - // Look for Godeps.json declaring import path. - data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json")) - var cfg struct{ ImportPath string } - json.Unmarshal(data, &cfg) - if cfg.ImportPath != "" { - return cfg.ImportPath, nil - } - - // Look for vendor.json declaring import path. - data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json")) - var cfg2 struct{ RootPath string } - json.Unmarshal(data, &cfg2) - if cfg2.RootPath != "" { - return cfg2.RootPath, nil - } - - // Look for .git/config with github origin as last resort. - data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config")) - if m := gitOriginRE.FindSubmatch(data); m != nil { - return "github.com/" + string(m[1]), nil - } - - return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir) -} - -var ( - gitOriginRE = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`) - importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`) -) - -func findImportComment(file string) string { - data, err := ioutil.ReadFile(file) - if err != nil { - return "" - } - m := importCommentRE.FindSubmatch(data) - if m == nil { - return "" - } - path, err := strconv.Unquote(string(m[1])) - if err != nil { - return "" - } - return path -} - -func writeGoMod() { - writeModHash() - - if buildList != nil { - min, err := mvs.Req(Target, buildList, newReqs()) - if err != nil { - base.Fatalf("vgo: %v", err) - } - modFile.SetRequire(min) - } - - file := filepath.Join(ModRoot, "go.mod") - old, _ := ioutil.ReadFile(file) - new, err := modFile.Format() - if err != nil { - base.Fatalf("vgo: %v", err) - } - if bytes.Equal(old, new) { - return - } - if err := ioutil.WriteFile(file, new, 0666); err != nil { - base.Fatalf("vgo: %v", err) - } -} - -func fixVersion(path, vers string) (string, error) { - // Special case: remove the old -gopkgin- hack. - if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") { - vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):] - } - - // fixVersion is called speculatively on every - // module, version pair from every go.mod file. - // Avoid the query if it looks OK. - _, pathMajor, ok := module.SplitPathVersion(path) - if !ok { - return "", fmt.Errorf("malformed module path: %s", path) - } - if semver.IsValid(vers) && vers == semver.Canonical(vers) && module.MatchPathMajor(vers, pathMajor) { - return vers, nil - } - - info, err := modfetch.Query(path, vers, nil) - if err != nil { - return "", err - } - return info.Version, nil -} diff --git a/src/cmd/go/internal/vgo/list.go b/src/cmd/go/internal/vgo/list.go deleted file mode 100644 index c6656c292d..0000000000 --- a/src/cmd/go/internal/vgo/list.go +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "bufio" - "fmt" - "io" - "os" - "regexp" - "unicode/utf8" - - "cmd/go/internal/base" - "cmd/go/internal/modfetch" - "cmd/go/internal/module" -) - -func ListT(pkgs []string) { - if Init(); !Enabled() { - base.Fatalf("go list: cannot use -t outside module") - } - InitMod() - - if len(pkgs) == 0 { - base.Fatalf("vgo list -t: need list of modules") - } - - for _, pkg := range pkgs { - repo, err := modfetch.Lookup(pkg) - if err != nil { - base.Errorf("vgo list -t: %v", err) - continue - } - path := repo.ModulePath() - fmt.Printf("%s\n", path) - tags, err := repo.Versions("") - if err != nil { - base.Errorf("vgo list -t: %v", err) - continue - } - for _, t := range tags { - if excluded[module.Version{Path: path, Version: t}] { - t += " # excluded" - } - fmt.Printf("\t%s\n", t) - } - } -} - -func ListM() { - if Init(); !Enabled() { - base.Fatalf("go list: cannot use -m outside module") - } - InitMod() - iterate(func(*loader) {}) - printListM(os.Stdout) -} - -func printListM(w io.Writer) { - var rows [][]string - rows = append(rows, []string{"MODULE", "VERSION"}) - for _, mod := range buildList { - v := mod.Version - if v == "" { - v = "-" - } - rows = append(rows, []string{mod.Path, v}) - if r := replaced(mod); r != nil { - rows = append(rows, []string{" => " + r.New.Path, r.New.Version}) - } - } - printTable(w, rows) -} - -func ListMU() { - if Init(); !Enabled() { - base.Fatalf("go list: cannot use -m outside module") - } - InitMod() - - quietLookup = true // do not chatter in v.Lookup - iterate(func(*loader) {}) - - var rows [][]string - rows = append(rows, []string{"MODULE", "VERSION", "LATEST"}) - for _, mod := range buildList { - var latest string - v := mod.Version - if v == "" { - v = "-" - latest = "-" - } else { - info, err := modfetch.Query(mod.Path, "latest", allowed) - if err != nil { - latest = "ERR: " + err.Error() - } else { - latest = info.Version - if !isPseudoVersion(latest) && !info.Time.IsZero() { - latest += info.Time.Local().Format(" (2006-01-02 15:04)") - } - } - if !isPseudoVersion(mod.Version) { - if info, err := modfetch.Query(mod.Path, mod.Version, nil); err == nil && !info.Time.IsZero() { - v += info.Time.Local().Format(" (2006-01-02 15:04)") - } - } - } - if latest == v { - latest = "-" - } - rows = append(rows, []string{mod.Path, v, latest}) - } - printTable(os.Stdout, rows) -} - -var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.0\.0-[0-9]{14}-[A-Za-z0-9]+$`) - -func isPseudoVersion(v string) bool { - return pseudoVersionRE.MatchString(v) -} - -func printTable(w io.Writer, rows [][]string) { - var max []int - for _, row := range rows { - for i, c := range row { - n := utf8.RuneCountInString(c) - if i >= len(max) { - max = append(max, n) - } else if max[i] < n { - max[i] = n - } - } - } - - b := bufio.NewWriter(w) - for _, row := range rows { - for len(row) > 0 && row[len(row)-1] == "" { - row = row[:len(row)-1] - } - for i, c := range row { - b.WriteString(c) - if i+1 < len(row) { - for j := utf8.RuneCountInString(c); j < max[i]+2; j++ { - b.WriteRune(' ') - } - } - } - b.WriteRune('\n') - } - b.Flush() -} diff --git a/src/cmd/go/internal/vgo/load.go b/src/cmd/go/internal/vgo/load.go deleted file mode 100644 index 3ebba06787..0000000000 --- a/src/cmd/go/internal/vgo/load.go +++ /dev/null @@ -1,575 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "bytes" - "encoding/json" - "fmt" - "go/build" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/imports" - "cmd/go/internal/modconv" - "cmd/go/internal/modfetch" - "cmd/go/internal/modfile" - "cmd/go/internal/module" - "cmd/go/internal/mvs" - "cmd/go/internal/search" - "cmd/go/internal/semver" -) - -type importLevel int - -const ( - levelNone importLevel = 0 - levelBuild importLevel = 1 - levelTest importLevel = 2 - levelTestRecursive importLevel = 3 -) - -var ( - buildList []module.Version - tags map[string]bool - importmap map[string]string - pkgdir map[string]string - pkgmod map[string]module.Version - isGetU bool -) - -func AddImports(gofiles []string) { - if Init(); !Enabled() { - return - } - InitMod() - - imports, testImports, err := imports.ScanFiles(gofiles, tags) - if err != nil { - base.Fatalf("vgo: %v", err) - } - - iterate(func(ld *loader) { - ld.importList(imports, levelBuild) - ld.importList(testImports, levelBuild) - }) - writeGoMod() -} - -func ImportPaths(args []string) []string { - if Init(); !Enabled() { - return search.ImportPaths(args) - } - InitMod() - - paths := importPaths(args) - writeGoMod() - return paths -} - -func importPaths(args []string) []string { - level := levelBuild - switch cfg.CmdName { - case "test", "vet": - level = levelTest - } - cleaned := search.CleanImportPaths(args) - iterate(func(ld *loader) { - args = expandImportPaths(cleaned) - for i, pkg := range args { - if pkg == "." || pkg == ".." || strings.HasPrefix(pkg, "./") || strings.HasPrefix(pkg, "../") { - dir := filepath.Join(cwd, pkg) - if dir == ModRoot { - pkg = Target.Path - } else if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) { - pkg = Target.Path + filepath.ToSlash(dir[len(ModRoot):]) - } else { - base.Errorf("vgo: package %s outside module root", pkg) - continue - } - args[i] = pkg - } - ld.importPkg(pkg, level) - } - }) - return args -} - -func Lookup(parentPath, path string) (dir, realPath string, err error) { - realPath = importmap[path] - if realPath == "" { - if isStandardImportPath(path) { - dir := filepath.Join(cfg.GOROOT, "src", path) - if _, err := os.Stat(dir); err == nil { - return dir, path, nil - } - } - return "", "", fmt.Errorf("no such package in module") - } - return pkgdir[realPath], realPath, nil -} - -func iterate(doImports func(*loader)) { - var err error - mvsOp := mvs.BuildList - if isGetU { - mvsOp = mvs.UpgradeAll - } - buildList, err = mvsOp(Target, newReqs()) - if err != nil { - base.Fatalf("vgo: %v", err) - } - - var ld *loader - for { - ld = newLoader() - doImports(ld) - if len(ld.missing) == 0 { - break - } - for _, m := range ld.missing { - findMissing(m) - } - base.ExitIfErrors() - buildList, err = mvsOp(Target, newReqs()) - if err != nil { - base.Fatalf("vgo: %v", err) - } - } - base.ExitIfErrors() - - importmap = ld.importmap - pkgdir = ld.pkgdir - pkgmod = ld.pkgmod -} - -type loader struct { - imported map[string]importLevel - importmap map[string]string - pkgdir map[string]string - pkgmod map[string]module.Version - tags map[string]bool - missing []missing - imports []string - stack []string -} - -type missing struct { - path string - stack string -} - -func newLoader() *loader { - ld := &loader{ - imported: make(map[string]importLevel), - importmap: make(map[string]string), - pkgdir: make(map[string]string), - pkgmod: make(map[string]module.Version), - tags: imports.Tags(), - } - ld.imported["C"] = 100 - return ld -} - -func (ld *loader) stackText() string { - var buf bytes.Buffer - for _, p := range ld.stack[:len(ld.stack)-1] { - fmt.Fprintf(&buf, "import %q ->\n\t", p) - } - fmt.Fprintf(&buf, "import %q", ld.stack[len(ld.stack)-1]) - return buf.String() -} - -func (ld *loader) importList(pkgs []string, level importLevel) { - for _, pkg := range pkgs { - ld.importPkg(pkg, level) - } -} - -func (ld *loader) importPkg(path string, level importLevel) { - if ld.imported[path] >= level { - return - } - - ld.stack = append(ld.stack, path) - defer func() { - ld.stack = ld.stack[:len(ld.stack)-1] - }() - - // Any rewritings go here. - realPath := path - - ld.imported[path] = level - ld.importmap[path] = realPath - if realPath != path && ld.imported[realPath] >= level { - // Already handled. - return - } - - dir := ld.importDir(realPath) - if dir == "" { - return - } - - ld.pkgdir[realPath] = dir - - imports, testImports, err := imports.ScanDir(dir, ld.tags) - if err != nil { - base.Errorf("vgo: %s [%s]: %v", ld.stackText(), dir, err) - return - } - nextLevel := level - if level == levelTest { - nextLevel = levelBuild - } - for _, pkg := range imports { - ld.importPkg(pkg, nextLevel) - } - if level >= levelTest { - for _, pkg := range testImports { - ld.importPkg(pkg, nextLevel) - } - } -} - -func (ld *loader) importDir(path string) string { - if importPathInModule(path, Target.Path) { - dir := ModRoot - if len(path) > len(Target.Path) { - dir = filepath.Join(dir, path[len(Target.Path)+1:]) - } - ld.pkgmod[path] = Target - return dir - } - - i := strings.Index(path, "/") - if i < 0 || !strings.Contains(path[:i], ".") { - if strings.HasPrefix(path, "golang_org/") { - return filepath.Join(cfg.GOROOT, "src/vendor", path) - } - dir := filepath.Join(cfg.GOROOT, "src", path) - if _, err := os.Stat(dir); err == nil { - return dir - } - } - - var mod1 module.Version - var dir1 string - for _, mod := range buildList { - if !importPathInModule(path, mod.Path) { - continue - } - dir, err := fetch(mod) - if err != nil { - base.Errorf("vgo: %s: %v", ld.stackText(), err) - return "" - } - if len(path) > len(mod.Path) { - dir = filepath.Join(dir, path[len(mod.Path)+1:]) - } - if dir1 != "" { - base.Errorf("vgo: %s: found in both %v %v and %v %v", ld.stackText(), - mod1.Path, mod1.Version, mod.Path, mod.Version) - return "" - } - dir1 = dir - mod1 = mod - } - if dir1 != "" { - ld.pkgmod[path] = mod1 - return dir1 - } - ld.missing = append(ld.missing, missing{path, ld.stackText()}) - return "" -} - -func replaced(mod module.Version) *modfile.Replace { - var found *modfile.Replace - for _, r := range modFile.Replace { - if r.Old == mod { - found = r // keep going - } - } - return found -} - -func importPathInModule(path, mpath string) bool { - return mpath == path || - len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath -} - -var found = make(map[string]bool) - -func findMissing(m missing) { - for _, mod := range buildList { - if importPathInModule(m.path, mod.Path) { - // Leave for ordinary build to complain about the missing import. - return - } - } - if build.IsLocalImport(m.path) { - base.Errorf("vgo: relative import is not supported: %s", m.path) - return - } - fmt.Fprintf(os.Stderr, "vgo: resolving import %q\n", m.path) - repo, info, err := modfetch.Import(m.path, allowed) - if err != nil { - base.Errorf("vgo: %s: %v", m.stack, err) - return - } - root := repo.ModulePath() - fmt.Fprintf(os.Stderr, "vgo: finding %s (latest)\n", root) - if found[root] { - base.Fatalf("internal error: findmissing loop on %s", root) - } - found[root] = true - fmt.Fprintf(os.Stderr, "vgo: adding %s %s\n", root, info.Version) - buildList = append(buildList, module.Version{Path: root, Version: info.Version}) - modFile.AddRequire(root, info.Version) -} - -type mvsReqs struct { - extra []module.Version -} - -func newReqs(extra ...module.Version) *mvsReqs { - r := &mvsReqs{ - extra: extra, - } - return r -} - -func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) { - list, err := r.required(mod) - if err != nil { - return nil, err - } - if *getU { - for i := range list { - list[i].Version = "none" - } - return list, nil - } - for i, mv := range list { - for excluded[mv] { - mv1, err := r.Next(mv) - if err != nil { - return nil, err - } - if mv1.Version == "" { - return nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version) - } - mv = mv1 - } - list[i] = mv - } - return list, nil -} - -var vgoVersion = []byte(modconv.Prefix) - -func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) { - if mod == Target { - var list []module.Version - if buildList != nil { - list = append(list, buildList[1:]...) - return list, nil - } - for _, r := range modFile.Require { - list = append(list, r.Mod) - } - list = append(list, r.extra...) - return list, nil - } - - origPath := mod.Path - if repl := replaced(mod); repl != nil { - if repl.New.Version == "" { - // TODO: need to slip the new version into the tags list etc. - dir := repl.New.Path - if !filepath.IsAbs(dir) { - dir = filepath.Join(ModRoot, dir) - } - gomod := filepath.Join(dir, "go.mod") - data, err := ioutil.ReadFile(gomod) - if err != nil { - return nil, err - } - f, err := modfile.Parse(gomod, data, nil) - if err != nil { - return nil, err - } - var list []module.Version - for _, r := range f.Require { - list = append(list, r.Mod) - } - return list, nil - } - mod = repl.New - } - - if mod.Version == "none" { - return nil, nil - } - - if !semver.IsValid(mod.Version) { - // Disallow the broader queries supported by fetch.Lookup. - panic(fmt.Errorf("invalid semantic version %q for %s", mod.Version, mod.Path)) - // TODO return nil, fmt.Errorf("invalid semantic version %q", mod.Version) - } - - gomod := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".mod") - infofile := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".info") - var f *modfile.File - if data, err := ioutil.ReadFile(gomod); err == nil { - // If go.mod has a //vgo comment at the start, - // it was auto-converted from a legacy lock file. - // The auto-conversion details may have bugs and - // may be fixed in newer versions of vgo. - // We ignore cached go.mod files if they do not match - // our own vgoVersion. - if !bytes.HasPrefix(data, vgoVersion[:len("//vgo")]) || bytes.HasPrefix(data, vgoVersion) { - f, err := modfile.Parse(gomod, data, nil) - if err != nil { - return nil, err - } - var list []module.Version - for _, r := range f.Require { - list = append(list, r.Mod) - } - return list, nil - } - f, err = modfile.Parse("go.mod", data, nil) - if err != nil { - return nil, fmt.Errorf("parsing downloaded go.mod: %v", err) - } - } else { - if !quietLookup { - fmt.Fprintf(os.Stderr, "vgo: finding %s %s\n", mod.Path, mod.Version) - } - repo, err := modfetch.Lookup(mod.Path) - if err != nil { - base.Errorf("vgo: %s: %v\n", mod.Path, err) - return nil, err - } - info, err := repo.Stat(mod.Version) - if err != nil { - base.Errorf("vgo: %s %s: %v\n", mod.Path, mod.Version, err) - return nil, err - } - data, err := repo.GoMod(info.Version) - if err != nil { - base.Errorf("vgo: %s %s: %v\n", mod.Path, mod.Version, err) - return nil, err - } - - f, err = modfile.Parse("go.mod", data, nil) - if err != nil { - return nil, fmt.Errorf("parsing downloaded go.mod: %v", err) - } - - dir := filepath.Dir(gomod) - if err := os.MkdirAll(dir, 0777); err != nil { - return nil, fmt.Errorf("caching go.mod: %v", err) - } - js, err := json.Marshal(info) - if err != nil { - return nil, fmt.Errorf("internal error: json failure: %v", err) - } - if err := ioutil.WriteFile(infofile, js, 0666); err != nil { - return nil, fmt.Errorf("caching info: %v", err) - } - if err := ioutil.WriteFile(gomod, data, 0666); err != nil { - return nil, fmt.Errorf("caching go.mod: %v", err) - } - } - if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path { - return nil, fmt.Errorf("downloaded %q and got module %q", mod.Path, mpath) - } - - var list []module.Version - for _, req := range f.Require { - list = append(list, req.Mod) - } - if false { - fmt.Fprintf(os.Stderr, "REQLIST %v:\n", mod) - for _, req := range list { - fmt.Fprintf(os.Stderr, "\t%v\n", req) - } - } - return list, nil -} - -var quietLookup bool - -func (*mvsReqs) Max(v1, v2 string) string { - if semver.Compare(v1, v2) == -1 { - return v2 - } - return v1 -} - -func (*mvsReqs) Latest(path string) (module.Version, error) { - // Note that query "latest" is not the same as - // using repo.Latest. - // The query only falls back to untagged versions - // if nothing is tagged. The Latest method - // only ever returns untagged versions, - // which is not what we want. - fmt.Fprintf(os.Stderr, "vgo: finding %s latest\n", path) - info, err := modfetch.Query(path, "latest", allowed) - if err != nil { - return module.Version{}, err - } - return module.Version{Path: path, Version: info.Version}, nil -} - -var versionCache = make(map[string][]string) - -func versions(path string) ([]string, error) { - list, ok := versionCache[path] - if !ok { - var err error - repo, err := modfetch.Lookup(path) - if err != nil { - return nil, err - } - list, err = repo.Versions("") - if err != nil { - return nil, err - } - versionCache[path] = list - } - return list, nil -} - -func (*mvsReqs) Previous(m module.Version) (module.Version, error) { - list, err := versions(m.Path) - if err != nil { - return module.Version{}, err - } - i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 }) - if i > 0 { - return module.Version{Path: m.Path, Version: list[i-1]}, nil - } - return module.Version{Path: m.Path, Version: "none"}, nil -} - -func (*mvsReqs) Next(m module.Version) (module.Version, error) { - list, err := versions(m.Path) - if err != nil { - return module.Version{}, err - } - i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 }) - if i < len(list) { - return module.Version{Path: m.Path, Version: list[i]}, nil - } - return module.Version{Path: m.Path, Version: "none"}, nil -} diff --git a/src/cmd/go/internal/vgo/search.go b/src/cmd/go/internal/vgo/search.go deleted file mode 100644 index c3f7ab13bf..0000000000 --- a/src/cmd/go/internal/vgo/search.go +++ /dev/null @@ -1,196 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "fmt" - "go/build" - "os" - "path/filepath" - "sort" - "strings" - - "cmd/go/internal/base" - "cmd/go/internal/cfg" - "cmd/go/internal/imports" - "cmd/go/internal/module" - "cmd/go/internal/search" -) - -func expandImportPaths(args []string) []string { - var out []string - for _, a := range args { - // TODO(rsc): Move a == "ALL" test into search.IsMetaPackage - // once we officially lock in all the module work (tentatively, Go 1.12). - if search.IsMetaPackage(a) || a == "ALL" { - switch a { - default: - fmt.Fprintf(os.Stderr, "vgo: warning: %q matches no packages when using modules\n", a) - case "all", "ALL": - out = append(out, AllPackages(a)...) - } - continue - } - if strings.Contains(a, "...") { - if build.IsLocalImport(a) { - out = append(out, search.AllPackagesInFS(a)...) - } else { - out = append(out, AllPackages(a)...) - } - continue - } - out = append(out, a) - } - return out -} - -// AllPackages returns all the packages that can be found -// under the $GOPATH directories and $GOROOT matching pattern. -// The pattern is either "all" (all packages), "std" (standard packages), -// "cmd" (standard commands), or a path including "...". -func AllPackages(pattern string) []string { - pkgs := MatchPackages(pattern) - if len(pkgs) == 0 { - fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern) - } - return pkgs -} - -// MatchPackages returns a list of package paths matching pattern -// (see go help packages for pattern syntax). -func MatchPackages(pattern string) []string { - if pattern == "std" || pattern == "cmd" { - return nil - } - if pattern == "all" { - return MatchAll() - } - if pattern == "ALL" { - return MatchALL() - } - - return matchPackages(pattern, buildList) -} - -func matchPackages(pattern string, buildList []module.Version) []string { - match := func(string) bool { return true } - treeCanMatch := func(string) bool { return true } - if !search.IsMetaPackage(pattern) && pattern != "ALL" { - match = search.MatchPattern(pattern) - treeCanMatch = search.TreeCanMatchPattern(pattern) - } - - have := map[string]bool{ - "builtin": true, // ignore pseudo-package that exists only for documentation - } - if !cfg.BuildContext.CgoEnabled { - have["runtime/cgo"] = true // ignore during walk - } - var pkgs []string - - for _, mod := range buildList { - if !treeCanMatch(mod.Path) { - continue - } - var root string - if mod.Version == "" { - root = ModRoot - } else { - var err error - root, err = fetch(mod) - if err != nil { - base.Errorf("vgo: %v", err) - continue - } - } - root = filepath.Clean(root) - - filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { - if err != nil { - return nil - } - - want := true - // Avoid .foo, _foo, and testdata directory trees. - _, elem := filepath.Split(path) - if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" { - want = false - } - - name := mod.Path + filepath.ToSlash(path[len(root):]) - if !treeCanMatch(name) { - want = false - } - - if !fi.IsDir() { - if fi.Mode()&os.ModeSymlink != 0 && want { - if target, err := os.Stat(path); err == nil && target.IsDir() { - fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path) - } - } - return nil - } - - if !want { - return filepath.SkipDir - } - if path != root { - if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil { - return filepath.SkipDir - } - } - - if !have[name] { - have[name] = true - if match(name) { - if _, _, err := imports.ScanDir(path, imports.Tags()); err != imports.ErrNoGo { - pkgs = append(pkgs, name) - } - } - } - - if elem == "vendor" { - return filepath.SkipDir - } - return nil - }) - } - return pkgs -} - -// MatchAll returns a list of the packages matching the pattern "all". -// We redefine "all" to mean start with the packages in the current module -// and then follow imports into other modules to add packages imported -// (directly or indirectly) as part of builds in this module. -// It does not include packages in other modules that are not needed -// by builds of this module. -func MatchAll() []string { - return matchAll(imports.Tags()) -} - -// MatchALL returns a list of the packages matching the pattern "ALL". -// The pattern "ALL" is like "all" but looks at all source files, -// even ones that would be ignored by current build tag settings. -// That's useful for identifying which packages to include in a vendor directory. -func MatchALL() []string { - return matchAll(map[string]bool{"*": true}) -} - -// matchAll is the common implementation of MatchAll and MatchALL, -// which differ only in the set of tags to apply to select files. -func matchAll(tags map[string]bool) []string { - local := matchPackages("all", buildList[:1]) - ld := newLoader() - ld.tags = tags - ld.importList(local, levelTestRecursive) - var all []string - for _, pkg := range ld.importmap { - if !isStandardImportPath(pkg) { - all = append(all, pkg) - } - } - sort.Strings(all) - return all -} diff --git a/src/cmd/go/internal/vgo/vendor.go b/src/cmd/go/internal/vgo/vendor.go deleted file mode 100644 index acba4afbbc..0000000000 --- a/src/cmd/go/internal/vgo/vendor.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2018 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package vgo - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "path/filepath" - "strings" - - "cmd/go/internal/base" - "cmd/go/internal/module" -) - -var CmdVendor = &base.Command{ - UsageLine: "vendor [-v]", - Short: "vendor dependencies of current module", - Long: ` -Vendor resets the module's vendor directory to include all -packages needed to build and test all packages in the module -and their dependencies. - -The -v flag causes vendor to print to standard error the -module paths of the modules processed and the import paths -of the packages copied. - `, -} - -var vendorV = CmdVendor.Flag.Bool("v", false, "") - -func init() { - CmdVendor.Run = runVendor // break init cycle -} - -func runVendor(cmd *base.Command, args []string) { - if Init(); !Enabled() { - base.Fatalf("vgo vendor: cannot use -m outside module") - } - if len(args) != 0 { - base.Fatalf("vgo vendor: vendor takes no arguments") - } - InitMod() - pkgs := ImportPaths([]string{"ALL"}) - - vdir := filepath.Join(ModRoot, "vendor") - if err := os.RemoveAll(vdir); err != nil { - base.Fatalf("vgo vendor: %v", err) - } - - modpkgs := make(map[module.Version][]string) - for _, pkg := range pkgs { - m := pkgmod[pkg] - if m == Target { - continue - } - modpkgs[m] = append(modpkgs[m], pkg) - } - - var buf bytes.Buffer - for _, m := range buildList[1:] { - if pkgs := modpkgs[m]; len(pkgs) > 0 { - repl := "" - if r := replaced(m); r != nil { - repl = " => " + r.New.Path - if r.New.Version != "" { - repl += " " + r.New.Version - } - } - fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl) - if *vendorV { - fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl) - } - for _, pkg := range pkgs { - fmt.Fprintf(&buf, "%s\n", pkg) - if *vendorV { - fmt.Fprintf(os.Stderr, "%s\n", pkg) - } - vendorPkg(vdir, pkg) - } - } - } - if err := ioutil.WriteFile(filepath.Join(vdir, "vgo.list"), buf.Bytes(), 0666); err != nil { - base.Fatalf("vgo vendor: %v", err) - } -} - -func vendorPkg(vdir, pkg string) { - realPath := importmap[pkg] - if realPath != pkg && importmap[realPath] != "" { - fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg) - } - - dst := filepath.Join(vdir, pkg) - src := pkgdir[realPath] - if src == "" { - fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath) - } - copyDir(dst, src, false) -} - -func copyDir(dst, src string, recursive bool) { - files, err := ioutil.ReadDir(src) - if err != nil { - base.Fatalf("vgo vendor: %v", err) - } - if err := os.MkdirAll(dst, 0777); err != nil { - base.Fatalf("vgo vendor: %v", err) - } - for _, file := range files { - if file.IsDir() { - if recursive || file.Name() == "testdata" { - copyDir(filepath.Join(dst, file.Name()), filepath.Join(src, file.Name()), true) - } - continue - } - if !file.Mode().IsRegular() { - continue - } - r, err := os.Open(filepath.Join(src, file.Name())) - if err != nil { - base.Fatalf("vgo vendor: %v", err) - } - w, err := os.Create(filepath.Join(dst, file.Name())) - if err != nil { - base.Fatalf("vgo vendor: %v", err) - } - if _, err := io.Copy(w, r); err != nil { - base.Fatalf("vgo vendor: %v", err) - } - r.Close() - if err := w.Close(); err != nil { - base.Fatalf("vgo vendor: %v", err) - } - } -} - -// hasPathPrefix reports whether the path s begins with the -// elements in prefix. -func hasPathPrefix(s, prefix string) bool { - switch { - default: - return false - case len(s) == len(prefix): - return s == prefix - case len(s) > len(prefix): - if prefix != "" && prefix[len(prefix)-1] == '/' { - return strings.HasPrefix(s, prefix) - } - return s[len(prefix)] == '/' && s[:len(prefix)] == prefix - } -} diff --git a/src/cmd/go/internal/web2/web.go b/src/cmd/go/internal/web2/web.go index d11ee6bb2b..f3900379e1 100644 --- a/src/cmd/go/internal/web2/web.go +++ b/src/cmd/go/internal/web2/web.go @@ -280,7 +280,7 @@ func Get(url string, options ...Option) error { return err } -var githubMessage = `vgo: 403 response from api.github.com +var githubMessage = `go: 403 response from api.github.com GitHub applies fairly small rate limits to unauthenticated users, and you appear to be hitting them. To authenticate, please visit diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go index 8edf55ffa1..1f91046eb1 100644 --- a/src/cmd/go/internal/work/action.go +++ b/src/cmd/go/internal/work/action.go @@ -36,10 +36,10 @@ type Builder struct { flagCache map[[2]string]bool // a cache of supported compiler flags Print func(args ...interface{}) (int, error) - IsCmdList bool // running as part of go list; set p.Stale and additional fields below - NeedError bool // list needs p.Error - NeedExport bool // list needs p.Export - NeedCgoFiles bool // list needs p.CgoFiles to cgo-generated files, not originals + IsCmdList bool // running as part of go list; set p.Stale and additional fields below + NeedError bool // list needs p.Error + NeedExport bool // list needs p.Export + NeedCompiledGoFiles bool // list needs p.CompiledGoFIles objdirSeq int // counter for NewObjdir pkgSeq int @@ -213,7 +213,6 @@ const ( ) func (b *Builder) Init() { - var err error b.Print = func(a ...interface{}) (int, error) { return fmt.Fprint(os.Stderr, a...) } @@ -225,14 +224,19 @@ func (b *Builder) Init() { if cfg.BuildN { b.WorkDir = "$WORK" } else { - b.WorkDir, err = ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build") + tmp, err := ioutil.TempDir(os.Getenv("GOTMPDIR"), "go-build") if err != nil { - base.Fatalf("%s", err) + base.Fatalf("go: creating work dir: %v", err) } - if !filepath.IsAbs(b.WorkDir) { - os.RemoveAll(b.WorkDir) - base.Fatalf("cmd/go: relative tmpdir not supported") + if !filepath.IsAbs(tmp) { + abs, err := filepath.Abs(tmp) + if err != nil { + os.RemoveAll(tmp) + base.Fatalf("go: creating work dir: %v", err) + } + tmp = abs } + b.WorkDir = tmp if cfg.BuildX || cfg.BuildWork { fmt.Fprintf(os.Stderr, "WORK=%s\n", b.WorkDir) } @@ -327,8 +331,8 @@ func (b *Builder) AutoAction(mode, depMode BuildMode, p *load.Package) *Action { // depMode is the action (build or install) to use when building dependencies. // To turn package main into an executable, call b.Link instead. func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Action { - if mode != ModeBuild && p.Internal.Local && p.Target == "" { - // Imported via local path. No permanent target. + if mode != ModeBuild && (p.Internal.Local || p.Module != nil) && p.Target == "" { + // Imported via local path or using modules. No permanent target. mode = ModeBuild } if mode != ModeBuild && p.Name == "main" { @@ -403,7 +407,16 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { stk.Pop() aFmt := b.CompileAction(ModeBuild, depMode, p1) - deps := []*Action{a1, aFmt} + var deps []*Action + if a1.buggyInstall { + // (*Builder).vet expects deps[0] to be the package + // and deps[1] to be "fmt". If we see buggyInstall + // here then a1 is an install of a shared library, + // and the real package is a1.Deps[0]. + deps = []*Action{a1.Deps[0], aFmt, a1} + } else { + deps = []*Action{a1, aFmt} + } for _, p1 := range load.PackageList(p.Internal.Imports) { deps = append(deps, b.vetAction(mode, depMode, p1)) } @@ -420,7 +433,7 @@ func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action { // Built-in packages like unsafe. return a } - a1.needVet = true + deps[0].needVet = true a.Func = (*Builder).vet return a }) diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 35ff25027e..ed41ce5d07 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -22,7 +22,7 @@ import ( ) var CmdBuild = &base.Command{ - UsageLine: "build [-o output] [-i] [build flags] [packages]", + UsageLine: "go build [-o output] [-i] [build flags] [packages]", Short: "compile packages and dependencies", Long: ` Build compiles the packages named by the import paths, @@ -98,6 +98,9 @@ and test commands: -linkshared link against shared libraries previously created with -buildmode=shared. + -mod mode + module download mode to use: readonly, release, or vendor. + See 'go help modules' for more. -pkgdir dir install and load all packages from dir instead of the usual locations. For example, when building with a non-standard configuration, @@ -218,6 +221,7 @@ func AddBuildFlags(cmd *base.Command) { cmd.Flag.StringVar(&cfg.BuildBuildmode, "buildmode", "default", "") cmd.Flag.Var(&load.BuildGcflags, "gcflags", "") cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "") + cmd.Flag.StringVar(&cfg.BuildMod, "mod", "", "") cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") cmd.Flag.Var(&load.BuildLdflags, "ldflags", "") cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") @@ -305,7 +309,7 @@ func runBuild(cmd *base.Command, args []string) { depMode = ModeInstall } - pkgs = pkgsFilter(load.Packages(args)) + pkgs = omitTestOnly(pkgsFilter(load.Packages(args))) // Special case -o /dev/null by not writing at all. if cfg.BuildO == os.DevNull { @@ -338,7 +342,7 @@ func runBuild(cmd *base.Command, args []string) { } var CmdInstall = &base.Command{ - UsageLine: "install [-i] [build flags] [packages]", + UsageLine: "go install [-i] [build flags] [packages]", Short: "compile and install packages and dependencies", Long: ` Install compiles and installs the packages named by the import paths. @@ -410,19 +414,44 @@ func libname(args []string, pkgs []*load.Package) (string, error) { func runInstall(cmd *base.Command, args []string) { BuildInit() - InstallPackages(args, false) + InstallPackages(args, load.PackagesForBuild(args)) } -func InstallPackages(args []string, forGet bool) { +// omitTestOnly returns pkgs with test-only packages removed. +func omitTestOnly(pkgs []*load.Package) []*load.Package { + var list []*load.Package + for _, p := range pkgs { + if len(p.GoFiles)+len(p.CgoFiles) == 0 && !p.Internal.CmdlinePkgLiteral { + // Package has no source files, + // perhaps due to build tags or perhaps due to only having *_test.go files. + // Also, it is only being processed as the result of a wildcard match + // like ./..., not because it was listed as a literal path on the command line. + // Ignore it. + continue + } + list = append(list, p) + } + return list +} + +func InstallPackages(patterns []string, pkgs []*load.Package) { if cfg.GOBIN != "" && !filepath.IsAbs(cfg.GOBIN) { base.Fatalf("cannot install, GOBIN must be an absolute path") } - pkgs := pkgsFilter(load.PackagesForBuild(args)) - + pkgs = omitTestOnly(pkgsFilter(pkgs)) for _, p := range pkgs { - if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") { + if p.Target == "" { switch { + case p.Standard && p.ImportPath == "unsafe": + // unsafe is a built-in package, has no target + case p.Name != "main" && p.Internal.Local && p.ConflictDir == "": + // Non-executables outside GOPATH need not have a target: + // we can use the cache to hold the built package archive for use in future builds. + // The ones inside GOPATH should have a target (in GOPATH/pkg) + // or else something is wrong and worth reporting (like a ConflictDir). + case p.Name != "main" && p.Module != nil: + // Non-executables have no target (except the cache) when building with modules. case p.Internal.GobinSubdir: base.Errorf("go %s: cannot install cross-compiled binaries when GOBIN is set", cfg.CmdName) case p.Internal.CmdlineFiles: @@ -446,11 +475,6 @@ func InstallPackages(args []string, forGet bool) { a := &Action{Mode: "go install"} var tools []*Action for _, p := range pkgs { - // During 'go get', don't attempt (and fail) to install packages with only tests. - // TODO(rsc): It's not clear why 'go get' should be different from 'go install' here. See #20760. - if forGet && len(p.GoFiles)+len(p.CgoFiles) == 0 && len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { - continue - } // If p is a tool, delay the installation until the end of the build. // This avoids installing assemblers/compilers that are being executed // by other steps in the build. @@ -476,7 +500,7 @@ func InstallPackages(args []string, forGet bool) { // tools above did not apply, and a is just a simple Action // with a list of Deps, one per package named in pkgs, // the same as in runBuild. - a = b.buildmodeShared(ModeInstall, ModeInstall, args, pkgs, a) + a = b.buildmodeShared(ModeInstall, ModeInstall, patterns, pkgs, a) } b.Do(a) @@ -491,7 +515,7 @@ func InstallPackages(args []string, forGet bool) { // One way to view this behavior is that it is as if 'go install' first // runs 'go build' and the moves the generated file to the install dir. // See issue 9645. - if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { + if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { // Compute file 'go build' would have created. // If it exists and is an executable file, remove it. _, targ := filepath.Split(pkgs[0].ImportPath) diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go index 9a2528b914..f6b79711f9 100644 --- a/src/cmd/go/internal/work/buildid.go +++ b/src/cmd/go/internal/work/buildid.go @@ -18,6 +18,7 @@ import ( "cmd/go/internal/load" "cmd/go/internal/str" "cmd/internal/buildid" + "cmd/internal/objabi" ) // Build IDs @@ -206,6 +207,11 @@ func (b *Builder) toolID(name string) string { id = f[2] } + // For the compiler, add any experiments. + if name == "compile" { + id += " " + objabi.Expstring() + } + b.id.Lock() b.toolIDCache[name] = id b.id.Unlock() @@ -463,6 +469,14 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID a.buildID = id[1] + buildIDSeparator + id[2] linkID := hashToString(b.linkActionID(a.triggers[0])) if id[0] == linkID { + // Best effort attempt to display output from the compile and link steps. + // If it doesn't work, it doesn't work: reusing the cached binary is more + // important than reprinting diagnostic information. + if c := cache.Default(); c != nil { + showStdout(b, c, a.actionID, "stdout") // compile output + showStdout(b, c, a.actionID, "link-stdout") // link output + } + // Poison a.Target to catch uses later in the build. a.Target = "DO NOT USE - main build pseudo-cache Target" a.built = "DO NOT USE - main build pseudo-cache built" @@ -480,6 +494,15 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID // We avoid the nested build ID problem in the previous special case // by recording the test results in the cache under the action ID half. if !cfg.BuildA && len(a.triggers) == 1 && a.triggers[0].TryCache != nil && a.triggers[0].TryCache(b, a.triggers[0]) { + // Best effort attempt to display output from the compile and link steps. + // If it doesn't work, it doesn't work: reusing the test result is more + // important than reprinting diagnostic information. + if c := cache.Default(); c != nil { + showStdout(b, c, a.Deps[0].actionID, "stdout") // compile output + showStdout(b, c, a.Deps[0].actionID, "link-stdout") // link output + } + + // Poison a.Target to catch uses later in the build. a.Target = "DO NOT USE - pseudo-cache Target" a.built = "DO NOT USE - pseudo-cache built" return true @@ -520,15 +543,7 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID if !cfg.BuildA { if file, _, err := c.GetFile(actionHash); err == nil { if buildID, err := buildid.ReadFile(file); err == nil { - if stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")); err == nil { - if len(stdout) > 0 { - if cfg.BuildX || cfg.BuildN { - b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) - } - if !cfg.BuildN { - b.Print(string(stdout)) - } - } + if err := showStdout(b, c, a.actionID, "stdout"); err == nil { a.built = file a.Target = "DO NOT USE - using cache" a.buildID = buildID @@ -549,6 +564,23 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID return false } +func showStdout(b *Builder, c *cache.Cache, actionID cache.ActionID, key string) error { + stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(actionID, key)) + if err != nil { + return err + } + + if len(stdout) > 0 { + if cfg.BuildX || cfg.BuildN { + b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID)))) + } + if !cfg.BuildN { + b.Print(string(stdout)) + } + } + return nil +} + // flushOutput flushes the output being queued in a. func (b *Builder) flushOutput(a *Action) { b.Print(string(a.output)) @@ -573,6 +605,26 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { } } + // Cache output from compile/link, even if we don't do the rest. + if c := cache.Default(); c != nil { + switch a.Mode { + case "build": + c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) + case "link": + // Even though we don't cache the binary, cache the linker text output. + // We might notice that an installed binary is up-to-date but still + // want to pretend to have run the linker. + // Store it under the main package's action ID + // to make it easier to find when that's all we have. + for _, a1 := range a.Deps { + if p1 := a1.Package; p1 != nil && p1.Name == "main" { + c.PutBytes(cache.Subkey(a1.actionID, "link-stdout"), a.output) + break + } + } + } + } + // Find occurrences of old ID and compute new content-based ID. r, err := os.Open(target) if err != nil { @@ -640,7 +692,6 @@ func (b *Builder) updateBuildID(a *Action, target string, rewrite bool) error { } a.Package.Export = c.OutputFile(outputID) } - c.PutBytes(cache.Subkey(a.actionID, "stdout"), a.output) } } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 5c4dc88821..01414a3d57 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -30,15 +30,8 @@ import ( "cmd/go/internal/cfg" "cmd/go/internal/load" "cmd/go/internal/str" - "cmd/go/internal/vgo" ) -func init() { - vgo.InstallHook = func(args []string) { - CmdInstall.Run(CmdInstall, args) - } -} - // actionList returns the list of actions in the dag rooted at root // as visited in a depth-first post-order traversal. func actionList(root *Action) []*Action { @@ -203,10 +196,13 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { fmt.Fprintf(h, "goos %s goarch %s\n", cfg.Goos, cfg.Goarch) fmt.Fprintf(h, "import %q\n", p.ImportPath) fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) + if p.Internal.ForceLibrary { + fmt.Fprintf(h, "forcelibrary\n") + } if len(p.CgoFiles)+len(p.SwigFiles) > 0 { fmt.Fprintf(h, "cgo %q\n", b.toolID("cgo")) - cppflags, cflags, cxxflags, fflags, _, _ := b.CFlags(p) - fmt.Fprintf(h, "CC=%q %q %q\n", b.ccExe(), cppflags, cflags) + cppflags, cflags, cxxflags, fflags, ldflags, _ := b.CFlags(p) + fmt.Fprintf(h, "CC=%q %q %q %q\n", b.ccExe(), cppflags, cflags, ldflags) if len(p.CXXFiles)+len(p.SwigFiles) > 0 { fmt.Fprintf(h, "CXX=%q %q\n", b.cxxExe(), cxxflags) } @@ -228,7 +224,9 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { if len(p.SFiles) > 0 { fmt.Fprintf(h, "asm %q %q %q\n", b.toolID("asm"), forcedAsmflags, p.Internal.Asmflags) } - fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(cfg.BuildContext.GOARCH))) // GO386, GOARM, etc + // GO386, GOARM, GOMIPS, etc. + baseArch := strings.TrimSuffix(cfg.BuildContext.GOARCH, "le") + fmt.Fprintf(h, "GO$GOARCH=%s\n", os.Getenv("GO"+strings.ToUpper(baseArch))) // TODO(rsc): Convince compiler team not to add more magic environment variables, // or perhaps restrict the environment variables passed to subprocesses. @@ -324,11 +322,32 @@ func (b *Builder) needCgoHdr(a *Action) bool { return false } +// allowedVersion reports whether the version v is an allowed version of go +// (one that we can compile). +// v is known to be of the form "1.23". +func allowedVersion(v string) bool { + // Special case: no requirement. + if v == "" { + return true + } + // Special case "1.0" means "go1", which is OK. + if v == "1.0" { + return true + } + // Otherwise look through release tags of form "go1.23" for one that matches. + for _, tag := range cfg.BuildContext.ReleaseTags { + if strings.HasPrefix(tag, "go") && tag[2:] == v { + return true + } + } + return false +} + const ( needBuild uint32 = 1 << iota needCgoHdr needVet - needCgoFiles + needCompiledGoFiles needStale ) @@ -348,10 +367,7 @@ func (b *Builder) build(a *Action) (err error) { need := bit(needBuild, !b.IsCmdList || b.NeedExport) | bit(needCgoHdr, b.needCgoHdr(a)) | bit(needVet, a.needVet) | - bit(needCgoFiles, b.NeedCgoFiles && (p.UsesCgo() || p.UsesSwig())) - - // Save p.CgoFiles now, because we may modify it for go list. - cgofiles := append([]string{}, p.CgoFiles...) + bit(needCompiledGoFiles, b.NeedCompiledGoFiles) if !p.BinaryOnly { if b.useCache(a, p, b.buildActionID(a), p.Target) { @@ -361,8 +377,8 @@ func (b *Builder) build(a *Action) (err error) { if b.NeedExport { p.Export = a.built } - if need&needCgoFiles != 0 && b.loadCachedCgoFiles(a) { - need &^= needCgoFiles + if need&needCompiledGoFiles != 0 && b.loadCachedGoFiles(a) { + need &^= needCompiledGoFiles } // Otherwise, we need to write files to a.Objdir (needVet, needCgoHdr). // Remember that we might have them in cache @@ -415,7 +431,11 @@ func (b *Builder) build(a *Action) (err error) { if b.IsCmdList { return nil } - return fmt.Errorf("missing or invalid binary-only package") + return fmt.Errorf("missing or invalid binary-only package; expected file %q", a.Package.Target) + } + + if p.Module != nil && !allowedVersion(p.Module.GoVersion) { + return fmt.Errorf("module requires Go %s", p.Module.GoVersion) } if err := b.Mkdir(a.Objdir); err != nil { @@ -448,11 +468,12 @@ func (b *Builder) build(a *Action) (err error) { } } - var gofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string - gofiles = append(gofiles, a.Package.GoFiles...) - cfiles = append(cfiles, a.Package.CFiles...) - sfiles = append(sfiles, a.Package.SFiles...) - cxxfiles = append(cxxfiles, a.Package.CXXFiles...) + gofiles := str.StringList(a.Package.GoFiles) + cgofiles := str.StringList(a.Package.CgoFiles) + cfiles := str.StringList(a.Package.CFiles) + sfiles := str.StringList(a.Package.SFiles) + cxxfiles := str.StringList(a.Package.CXXFiles) + var objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string if a.Package.UsesCgo() || a.Package.UsesSwig() { if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.Package); err != nil { @@ -573,11 +594,11 @@ func (b *Builder) build(a *Action) (err error) { buildVetConfig(a, gofiles) need &^= needVet } - if need&needCgoFiles != 0 { - if !b.loadCachedCgoFiles(a) { - return fmt.Errorf("failed to cache translated CgoFiles") + if need&needCompiledGoFiles != 0 { + if !b.loadCachedGoFiles(a) { + return fmt.Errorf("failed to cache compiled Go files") } - need &^= needCgoFiles + need &^= needCompiledGoFiles } if need == 0 { // Nothing left to do. @@ -606,8 +627,8 @@ func (b *Builder) build(a *Action) (err error) { fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built) } - if p.Internal.BuildInfo != "" { - if err := b.writeFile(objdir+"_gomod_.go", vgo.ModInfoProg(p.Internal.BuildInfo)); err != nil { + if p.Internal.BuildInfo != "" && cfg.ModulesEnabled { + if err := b.writeFile(objdir+"_gomod_.go", load.ModInfoProg(p.Internal.BuildInfo)); err != nil { return err } gofiles = append(gofiles, objdir+"_gomod_.go") @@ -815,7 +836,7 @@ func (b *Builder) loadCachedVet(a *Action) bool { return true } -func (b *Builder) loadCachedCgoFiles(a *Action) bool { +func (b *Builder) loadCachedGoFiles(a *Action) bool { c := cache.Default() if c == nil { return false @@ -830,6 +851,7 @@ func (b *Builder) loadCachedCgoFiles(a *Action) bool { continue } if strings.HasPrefix(name, "./") { + files = append(files, name[len("./"):]) continue } file, err := b.findCachedObjdirFile(a, c, name) @@ -838,7 +860,7 @@ func (b *Builder) loadCachedCgoFiles(a *Action) bool { } files = append(files, file) } - a.Package.CgoFiles = files + a.Package.CompiledGoFiles = files return true } @@ -919,13 +941,17 @@ func (b *Builder) vet(a *Action) error { a.Failed = false // vet of dependency may have failed but we can still succeed + if a.Deps[0].Failed { + // The build of the package has failed. Skip vet check. + // Vet could return export data for non-typecheck errors, + // but we ignore it because the package cannot be compiled. + return nil + } + vcfg := a.Deps[0].vetCfg if vcfg == nil { // Vet config should only be missing if the build failed. - if !a.Deps[0].Failed { - return fmt.Errorf("vet config not found") - } - return nil + return fmt.Errorf("vet config not found") } vcfg.VetxOnly = a.VetxOnly @@ -987,7 +1013,7 @@ func (b *Builder) vet(a *Action) error { return err } - var env []string + env := b.cCompilerEnv() if cfg.BuildToolchainName == "gccgo" { env = append(env, "GCCGO="+BuildToolchain.compiler()) } @@ -1131,11 +1157,11 @@ func (b *Builder) link(a *Action) (err error) { // We still call updateBuildID to update a.buildID, which is important // for test result caching, but passing rewrite=false (final arg) // means we don't actually rewrite the binary, nor store the - // result into the cache. - // Not calling updateBuildID means we also don't insert these - // binaries into the build object cache. That's probably a net win: + // result into the cache. That's probably a net win: // less cache space wasted on large binaries we are not likely to // need again. (On the other hand it does make repeated go test slower.) + // It also makes repeated go run slower, which is a win in itself: + // we don't want people to treat go run like a scripting environment. if err := b.updateBuildID(a, a.Target, !a.Package.Internal.OmitDebug); err != nil { return err } @@ -1372,7 +1398,9 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { // so the built target is not in the a1.Objdir tree that b.cleanup(a1) removes. if a1.built == a.Target { a.built = a.Target - b.cleanup(a1) + if !a.buggyInstall { + b.cleanup(a1) + } // Whether we're smart enough to avoid a complete rebuild // depends on exactly what the staleness and rebuild algorithms // are, as well as potentially the state of the Go build cache. @@ -1426,7 +1454,9 @@ func BuildInstallFunc(b *Builder, a *Action) (err error) { } } - defer b.cleanup(a1) + if !a.buggyInstall { + defer b.cleanup(a1) + } return b.moveOrCopyFile(a.Target, a1.built, perm, false) } @@ -1860,6 +1890,13 @@ func joinUnambiguously(a []string) string { return buf.String() } +// cCompilerEnv returns environment variables to set when running the +// C compiler. This is needed to disable escape codes in clang error +// messages that confuse tools like cgo. +func (b *Builder) cCompilerEnv() []string { + return []string{"TERM=dumb"} +} + // mkdir makes the named directory. func (b *Builder) Mkdir(dir string) error { // Make Mkdir(a.Objdir) a no-op instead of an error when a.Objdir == "". @@ -2007,7 +2044,7 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s if !filepath.IsAbs(outfile) { outfile = filepath.Join(p.Dir, outfile) } - output, err := b.runOut(filepath.Dir(file), nil, compiler, flags, "-o", outfile, "-c", filepath.Base(file)) + output, err := b.runOut(filepath.Dir(file), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(file)) if len(output) > 0 { // On FreeBSD 11, when we pass -g to clang 3.8 it // invokes its internal assembler with -dwarf-version=2. @@ -2047,7 +2084,7 @@ func (b *Builder) gccld(p *load.Package, objdir, out string, flags []string, obj } else { cmd = b.GccCmd(p.Dir, objdir) } - return b.run(nil, p.Dir, p.ImportPath, nil, cmd, "-o", out, objs, flags) + return b.run(nil, p.Dir, p.ImportPath, b.cCompilerEnv(), cmd, "-o", out, objs, flags) } // Grab these before main helpfully overwrites them. @@ -2342,7 +2379,7 @@ func (b *Builder) cgo(a *Action, cgoExe, objdir string, pcCFLAGS, pcLDFLAGS, cgo // along to the host linker. At this point in the code, cgoLDFLAGS // consists of the original $CGO_LDFLAGS (unchecked) and all the // flags put together from source code (checked). - var cgoenv []string + cgoenv := b.cCompilerEnv() if len(cgoLDFLAGS) > 0 { flags := make([]string, len(cgoLDFLAGS)) for i, f := range cgoLDFLAGS { @@ -2470,7 +2507,15 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe // we need to use -pie for Linux/ARM to get accurate imported sym ldflags := cgoLDFLAGS if (cfg.Goarch == "arm" && cfg.Goos == "linux") || cfg.Goos == "android" { - ldflags = append(ldflags, "-pie") + // -static -pie doesn't make sense, and causes link errors. + // Issue 26197. + n := make([]string, 0, len(ldflags)) + for _, flag := range ldflags { + if flag != "-static" { + n = append(n, flag) + } + } + ldflags = append(n, "-pie") } if err := b.gccld(p, objdir, dynobj, ldflags, linkobj); err != nil { return err @@ -2481,7 +2526,7 @@ func (b *Builder) dynimport(a *Action, p *load.Package, objdir, importGo, cgoExe if p.Standard && p.ImportPath == "runtime/cgo" { cgoflags = []string{"-dynlinker"} // record path to dynamic linker } - return b.run(a, p.Dir, p.ImportPath, nil, cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) + return b.run(a, p.Dir, p.ImportPath, b.cCompilerEnv(), cfg.BuildToolexec, cgoExe, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags) } // Run SWIG on all SWIG input files. @@ -2815,7 +2860,7 @@ func useResponseFile(path string, argLen int) bool { } // On the Go build system, use response files about 10% of the - // time, just to excercise this codepath. + // time, just to exercise this codepath. isBuilder := os.Getenv("GO_BUILDER_NAME") != "" if isBuilder && rand.Intn(10) == 0 { return true diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go index 1081e5147e..3f6252ed84 100644 --- a/src/cmd/go/internal/work/init.go +++ b/src/cmd/go/internal/work/init.go @@ -9,13 +9,17 @@ package work import ( "cmd/go/internal/base" "cmd/go/internal/cfg" + "cmd/go/internal/load" + "cmd/internal/sys" "flag" "fmt" "os" "path/filepath" + "strings" ) func BuildInit() { + load.ModInit() instrumentInit() buildModeInit() @@ -39,18 +43,14 @@ func instrumentInit() { fmt.Fprintf(os.Stderr, "go %s: may not use -race and -msan simultaneously\n", flag.Args()[0]) os.Exit(2) } - if cfg.BuildMSan && (cfg.Goos != "linux" || cfg.Goarch != "amd64" && cfg.Goarch != "arm64") { + if cfg.BuildMSan && !sys.MSanSupported(cfg.Goos, cfg.Goarch) { fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch) os.Exit(2) } if cfg.BuildRace { - platform := cfg.Goos + "/" + cfg.Goarch - switch platform { - default: - fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) + if !sys.RaceDetectorSupported(cfg.Goos, cfg.Goarch) { + fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, netbsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0]) os.Exit(2) - case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "darwin/amd64", "windows/amd64": - // race supported on these platforms } } mode := "race" @@ -224,4 +224,31 @@ func buildModeInit() { cfg.BuildContext.InstallSuffix += codegenArg[1:] } } + + switch cfg.BuildMod { + case "": + // ok + case "readonly", "vendor": + if load.ModLookup == nil && !inGOFLAGS("-mod") { + base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod) + } + default: + base.Fatalf("-mod=%s not supported (can be '', 'readonly', or 'vendor')", cfg.BuildMod) + } +} + +func inGOFLAGS(flag string) bool { + for _, goflag := range base.GOFLAGS() { + name := goflag + if strings.HasPrefix(name, "--") { + name = name[1:] + } + if i := strings.Index(name, "="); i >= 0 { + name = name[:i] + } + if name == flag { + return true + } + } + return false } diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index cd39a8f791..d5d126123a 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -136,6 +136,7 @@ var validLinkerFlags = []*regexp.Regexp{ re(`-f(no-)?(pic|PIC|pie|PIE)`), re(`-f(no-)?openmp(-simd)?`), re(`-fsanitize=([^@\-].*)`), + re(`-flat_namespace`), re(`-g([^@\-].*)?`), re(`-headerpad_max_install_names`), re(`-m(abi|arch|cpu|fpu|tune)=([^@\-].*)`), diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index 6388b59551..31c554e715 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -27,6 +27,10 @@ import ( "cmd/go/internal/get" "cmd/go/internal/help" "cmd/go/internal/list" + "cmd/go/internal/modcmd" + "cmd/go/internal/modfetch" + "cmd/go/internal/modget" + "cmd/go/internal/modload" "cmd/go/internal/run" "cmd/go/internal/test" "cmd/go/internal/tool" @@ -36,7 +40,7 @@ import ( ) func init() { - base.Commands = []*base.Command{ + base.Go.Commands = []*base.Command{ bug.CmdBug, work.CmdBuild, clean.CmdClean, @@ -48,6 +52,7 @@ func init() { get.CmdGet, work.CmdInstall, list.CmdList, + modcmd.CmdMod, run.CmdRun, test.CmdTest, tool.CmdTool, @@ -59,8 +64,13 @@ func init() { help.HelpCache, help.HelpEnvironment, help.HelpFileType, + modload.HelpGoMod, help.HelpGopath, + get.HelpGopathGet, + modfetch.HelpGoproxy, help.HelpImportPath, + modload.HelpModules, + modget.HelpModuleGet, help.HelpPackages, test.HelpTestflag, test.HelpTestfunc, @@ -78,9 +88,14 @@ func main() { base.Usage() } + if modload.MustUseModules { + // If running with modules force-enabled, change get now to change help message. + *get.CmdGet = *modget.CmdGet + } + cfg.CmdName = args[0] // for error messages if args[0] == "help" { - help.Help(args[1:]) + help.Help(os.Stdout, args[1:]) return } @@ -115,6 +130,46 @@ func main() { os.Exit(2) } + // TODO(rsc): Remove all these helper prints in Go 1.12. + switch args[0] { + case "mod": + if len(args) >= 2 { + flag := args[1] + if strings.HasPrefix(flag, "--") { + flag = flag[1:] + } + if i := strings.Index(flag, "="); i >= 0 { + flag = flag[:i] + } + switch flag { + case "-sync": + fmt.Fprintf(os.Stderr, "go: go mod -sync is now go mod tidy\n") + os.Exit(2) + case "-init", "-fix", "-graph", "-vendor", "-verify": + fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod %s\n", flag, flag[1:]) + os.Exit(2) + case "-fmt", "-json", "-module", "-require", "-droprequire", "-replace", "-dropreplace", "-exclude", "-dropexclude": + fmt.Fprintf(os.Stderr, "go: go mod %s is now go mod edit %s\n", flag, flag) + os.Exit(2) + } + } + case "vendor": + fmt.Fprintf(os.Stderr, "go: vgo vendor is now go mod vendor\n") + os.Exit(2) + case "verify": + fmt.Fprintf(os.Stderr, "go: vgo verify is now go mod verify\n") + os.Exit(2) + } + + if args[0] == "get" { + // Replace get with module-aware get if appropriate. + // Note that if MustUseModules is true, this happened already above, + // but no harm in doing it again. + if modload.Init(); modload.Enabled() { + *get.CmdGet = *modget.CmdGet + } + } + // Set environment (GOOS, GOARCH, etc) explicitly. // In theory all the commands we invoke should have // the same default computation of these as we do, @@ -128,12 +183,36 @@ func main() { } } - for _, cmd := range base.Commands { - if cmd.Name() == args[0] && cmd.Runnable() { +BigCmdLoop: + for bigCmd := base.Go; ; { + for _, cmd := range bigCmd.Commands { + if cmd.Name() != args[0] { + continue + } + if len(cmd.Commands) > 0 { + bigCmd = cmd + args = args[1:] + if len(args) == 0 { + help.PrintUsage(os.Stderr, bigCmd) + base.SetExitStatus(2) + base.Exit() + } + if args[0] == "help" { + // Accept 'go mod help' and 'go mod help foo' for 'go help mod' and 'go help mod foo'. + help.Help(os.Stdout, append(strings.Split(cfg.CmdName, " "), args[1:]...)) + return + } + cfg.CmdName += " " + args[0] + continue BigCmdLoop + } + if !cmd.Runnable() { + continue + } cmd.Flag.Usage = func() { cmd.Usage() } if cmd.CustomFlags { args = args[1:] } else { + base.SetFromGOFLAGS(cmd.Flag) cmd.Flag.Parse(args[1:]) args = cmd.Flag.Args() } @@ -141,11 +220,14 @@ func main() { base.Exit() return } + helpArg := "" + if i := strings.LastIndex(cfg.CmdName, " "); i >= 0 { + helpArg = " " + cfg.CmdName[:i] + } + fmt.Fprintf(os.Stderr, "go %s: unknown command\nRun 'go help%s' for usage.\n", cfg.CmdName, helpArg) + base.SetExitStatus(2) + base.Exit() } - - fmt.Fprintf(os.Stderr, "go: unknown subcommand %q\nRun 'go help' for usage.\n", args[0]) - base.SetExitStatus(2) - base.Exit() } func init() { @@ -157,6 +239,13 @@ func mainUsage() { if len(os.Args) > 1 && os.Args[1] == "test" { test.Usage() } - help.PrintUsage(os.Stderr) + // Since vet shares code with test in cmdflag, it doesn't show its + // command usage properly. For now, special case it too. + // TODO(mvdan): fix the cmdflag package instead; see + // golang.org/issue/26999 + if len(os.Args) > 1 && os.Args[1] == "vet" { + vet.CmdVet.Usage() + } + help.PrintUsage(os.Stderr, base.Go) os.Exit(2) } diff --git a/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh index 72886db1ea..f37d59d2d7 100755 --- a/src/cmd/go/mkalldocs.sh +++ b/src/cmd/go/mkalldocs.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Copyright 2012 The Go Authors. All rights reserved. # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. @@ -6,6 +6,8 @@ set -e go build -o go.latest +# If the command used to generate alldocs.go changes, update TestDocsUpToDate in +# help_test.go. ./go.latest help documentation >alldocs.go gofmt -w alldocs.go rm go.latest diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go new file mode 100644 index 0000000000..212e5aa08f --- /dev/null +++ b/src/cmd/go/proxy_test.go @@ -0,0 +1,272 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main_test + +import ( + "archive/zip" + "bytes" + "encoding/json" + "flag" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "path/filepath" + "strings" + "sync" + "testing" + + "cmd/go/internal/modfetch" + "cmd/go/internal/modfetch/codehost" + "cmd/go/internal/module" + "cmd/go/internal/par" + "cmd/go/internal/semver" + "cmd/go/internal/txtar" +) + +var ( + proxyAddr = flag.String("proxy", "", "run proxy on this network address instead of running any tests") + proxyURL string +) + +var proxyOnce sync.Once + +// StartProxy starts the Go module proxy running on *proxyAddr (like "localhost:1234") +// and sets proxyURL to the GOPROXY setting to use to access the proxy. +// Subsequent calls are no-ops. +// +// The proxy serves from testdata/mod. See testdata/mod/README. +func StartProxy() { + proxyOnce.Do(func() { + fmt.Fprintf(os.Stderr, "go test proxy starting\n") + readModList() + addr := *proxyAddr + if addr == "" { + addr = "localhost:0" + } + l, err := net.Listen("tcp", addr) + if err != nil { + log.Fatal(err) + } + *proxyAddr = l.Addr().String() + proxyURL = "http://" + *proxyAddr + "/mod" + fmt.Fprintf(os.Stderr, "go test proxy running at GOPROXY=%s\n", proxyURL) + go func() { + log.Fatalf("go proxy: http.Serve: %v", http.Serve(l, http.HandlerFunc(proxyHandler))) + }() + }) +} + +var modList []module.Version + +func readModList() { + infos, err := ioutil.ReadDir("testdata/mod") + if err != nil { + log.Fatal(err) + } + for _, info := range infos { + name := info.Name() + if !strings.HasSuffix(name, ".txt") { + continue + } + name = strings.TrimSuffix(name, ".txt") + i := strings.LastIndex(name, "_v") + if i < 0 { + continue + } + encPath := strings.Replace(name[:i], "_", "/", -1) + path, err := module.DecodePath(encPath) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + continue + } + encVers := name[i+1:] + vers, err := module.DecodeVersion(encVers) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + continue + } + modList = append(modList, module.Version{Path: path, Version: vers}) + } +} + +var zipCache par.Cache + +// proxyHandler serves the Go module proxy protocol. +// See the proxy section of https://research.swtch.com/vgo-module. +func proxyHandler(w http.ResponseWriter, r *http.Request) { + if !strings.HasPrefix(r.URL.Path, "/mod/") { + http.NotFound(w, r) + return + } + path := strings.TrimPrefix(r.URL.Path, "/mod/") + i := strings.Index(path, "/@v/") + if i < 0 { + http.NotFound(w, r) + return + } + enc, file := path[:i], path[i+len("/@v/"):] + path, err := module.DecodePath(enc) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + http.NotFound(w, r) + return + } + if file == "list" { + n := 0 + for _, m := range modList { + if m.Path == path && !modfetch.IsPseudoVersion(m.Version) { + if err := module.Check(m.Path, m.Version); err == nil { + fmt.Fprintf(w, "%s\n", m.Version) + n++ + } + } + } + if n == 0 { + http.NotFound(w, r) + } + return + } + + i = strings.LastIndex(file, ".") + if i < 0 { + http.NotFound(w, r) + return + } + encVers, ext := file[:i], file[i+1:] + vers, err := module.DecodeVersion(encVers) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy_test: %v\n", err) + http.NotFound(w, r) + return + } + + if codehost.AllHex(vers) { + var best string + // Convert commit hash (only) to known version. + // Use latest version in semver priority, to match similar logic + // in the repo-based module server (see modfetch.(*codeRepo).convert). + for _, m := range modList { + if m.Path == path && semver.Compare(best, m.Version) < 0 { + var hash string + if modfetch.IsPseudoVersion(m.Version) { + hash = m.Version[strings.LastIndex(m.Version, "-")+1:] + } else { + hash = findHash(m) + } + if strings.HasPrefix(hash, vers) || strings.HasPrefix(vers, hash) { + best = m.Version + } + } + } + if best != "" { + vers = best + } + } + + a := readArchive(path, vers) + if a == nil { + fmt.Fprintf(os.Stderr, "go proxy: no archive %s %s\n", path, vers) + http.Error(w, "cannot load archive", 500) + return + } + + switch ext { + case "info", "mod": + want := "." + ext + for _, f := range a.Files { + if f.Name == want { + w.Write(f.Data) + return + } + } + + case "zip": + type cached struct { + zip []byte + err error + } + c := zipCache.Do(a, func() interface{} { + var buf bytes.Buffer + z := zip.NewWriter(&buf) + for _, f := range a.Files { + if strings.HasPrefix(f.Name, ".") { + continue + } + zf, err := z.Create(path + "@" + vers + "/" + f.Name) + if err != nil { + return cached{nil, err} + } + if _, err := zf.Write(f.Data); err != nil { + return cached{nil, err} + } + } + if err := z.Close(); err != nil { + return cached{nil, err} + } + return cached{buf.Bytes(), nil} + }).(cached) + + if c.err != nil { + fmt.Fprintf(os.Stderr, "go proxy: %v\n", c.err) + http.Error(w, c.err.Error(), 500) + return + } + w.Write(c.zip) + return + + } + http.NotFound(w, r) +} + +func findHash(m module.Version) string { + a := readArchive(m.Path, m.Version) + if a == nil { + return "" + } + var data []byte + for _, f := range a.Files { + if f.Name == ".info" { + data = f.Data + break + } + } + var info struct{ Short string } + json.Unmarshal(data, &info) + return info.Short +} + +var archiveCache par.Cache + +var cmdGoDir, _ = os.Getwd() + +func readArchive(path, vers string) *txtar.Archive { + enc, err := module.EncodePath(path) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy: %v\n", err) + return nil + } + encVers, err := module.EncodeVersion(vers) + if err != nil { + fmt.Fprintf(os.Stderr, "go proxy: %v\n", err) + return nil + } + + prefix := strings.Replace(enc, "/", "_", -1) + name := filepath.Join(cmdGoDir, "testdata/mod", prefix+"_"+encVers+".txt") + a := archiveCache.Do(name, func() interface{} { + a, err := txtar.ParseFile(name) + if err != nil { + if testing.Verbose() || !os.IsNotExist(err) { + fmt.Fprintf(os.Stderr, "go proxy: %v\n", err) + } + a = nil + } + return a + }).(*txtar.Archive) + return a +} diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go new file mode 100644 index 0000000000..7c083a87b9 --- /dev/null +++ b/src/cmd/go/script_test.go @@ -0,0 +1,903 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Script-driven tests. +// See testdata/script/README for an overview. + +package main_test + +import ( + "bytes" + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "testing" + "time" + + "cmd/go/internal/imports" + "cmd/go/internal/par" + "cmd/go/internal/txtar" +) + +// TestScript runs the tests in testdata/script/*.txt. +func TestScript(t *testing.T) { + testenv.MustHaveGoBuild(t) + if skipExternal { + t.Skipf("skipping external tests on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + files, err := filepath.Glob("testdata/script/*.txt") + if err != nil { + t.Fatal(err) + } + for _, file := range files { + file := file + name := strings.TrimSuffix(filepath.Base(file), ".txt") + t.Run(name, func(t *testing.T) { + t.Parallel() + ts := &testScript{t: t, name: name, file: file} + ts.setup() + if !*testWork { + defer removeAll(ts.workdir) + } + ts.run() + }) + } +} + +// A testScript holds execution state for a single test script. +type testScript struct { + t *testing.T + workdir string // temporary work dir ($WORK) + log bytes.Buffer // test execution log (printed at end of test) + mark int // offset of next log truncation + cd string // current directory during test execution; initially $WORK/gopath/src + name string // short name of test ("foo") + file string // full file name ("testdata/script/foo.txt") + lineno int // line number currently executing + line string // line currently executing + env []string // environment list (for os/exec) + envMap map[string]string // environment mapping (matches env) + stdout string // standard output from last 'go' command; for 'stdout' command + stderr string // standard error from last 'go' command; for 'stderr' command + stopped bool // test wants to stop early + start time.Time // time phase started +} + +var extraEnvKeys = []string{ + "SYSTEMROOT", // must be preserved on Windows to find DLLs; golang.org/issue/25210 +} + +// setup sets up the test execution temporary directory and environment. +func (ts *testScript) setup() { + StartProxy() + ts.workdir = filepath.Join(testTmpDir, "script-"+ts.name) + ts.check(os.MkdirAll(filepath.Join(ts.workdir, "tmp"), 0777)) + ts.check(os.MkdirAll(filepath.Join(ts.workdir, "gopath/src"), 0777)) + ts.cd = filepath.Join(ts.workdir, "gopath/src") + ts.env = []string{ + "WORK=" + ts.workdir, // must be first for ts.abbrev + "PATH=" + testBin + string(filepath.ListSeparator) + os.Getenv("PATH"), + homeEnvName() + "=/no-home", + "CCACHE_DISABLE=1", // ccache breaks with non-existent HOME + "GOARCH=" + runtime.GOARCH, + "GOCACHE=" + testGOCACHE, + "GOOS=" + runtime.GOOS, + "GOPATH=" + filepath.Join(ts.workdir, "gopath"), + "GOPROXY=" + proxyURL, + "GOROOT=" + testGOROOT, + tempEnvName() + "=" + filepath.Join(ts.workdir, "tmp"), + "devnull=" + os.DevNull, + ":=" + string(os.PathListSeparator), + } + + if runtime.GOOS == "plan9" { + ts.env = append(ts.env, "path="+testBin+string(filepath.ListSeparator)+os.Getenv("path")) + } + + if runtime.GOOS == "windows" { + ts.env = append(ts.env, "exe=.exe") + } else { + ts.env = append(ts.env, "exe=") + } + for _, key := range extraEnvKeys { + if val := os.Getenv(key); val != "" { + ts.env = append(ts.env, key+"="+val) + } + } + + ts.envMap = make(map[string]string) + for _, kv := range ts.env { + if i := strings.Index(kv, "="); i >= 0 { + ts.envMap[kv[:i]] = kv[i+1:] + } + } +} + +var execCache par.Cache + +// run runs the test script. +func (ts *testScript) run() { + // Truncate log at end of last phase marker, + // discarding details of successful phase. + rewind := func() { + if !testing.Verbose() { + ts.log.Truncate(ts.mark) + } + } + + // Insert elapsed time for phase at end of phase marker + markTime := func() { + if ts.mark > 0 && !ts.start.IsZero() { + afterMark := append([]byte{}, ts.log.Bytes()[ts.mark:]...) + ts.log.Truncate(ts.mark - 1) // cut \n and afterMark + fmt.Fprintf(&ts.log, " (%.3fs)\n", time.Since(ts.start).Seconds()) + ts.log.Write(afterMark) + } + ts.start = time.Time{} + } + + defer func() { + markTime() + // Flush testScript log to testing.T log. + ts.t.Log("\n" + ts.abbrev(ts.log.String())) + }() + + // Unpack archive. + a, err := txtar.ParseFile(ts.file) + ts.check(err) + for _, f := range a.Files { + name := ts.mkabs(ts.expand(f.Name)) + ts.check(os.MkdirAll(filepath.Dir(name), 0777)) + ts.check(ioutil.WriteFile(name, f.Data, 0666)) + } + + // With -v or -testwork, start log with full environment. + if *testWork || testing.Verbose() { + // Display environment. + ts.cmdEnv(false, nil) + fmt.Fprintf(&ts.log, "\n") + ts.mark = ts.log.Len() + } + + // Run script. + // See testdata/script/README for documentation of script form. + script := string(a.Comment) +Script: + for script != "" { + // Extract next line. + ts.lineno++ + var line string + if i := strings.Index(script, "\n"); i >= 0 { + line, script = script[:i], script[i+1:] + } else { + line, script = script, "" + } + + // # is a comment indicating the start of new phase. + if strings.HasPrefix(line, "#") { + // If there was a previous phase, it succeeded, + // so rewind the log to delete its details (unless -v is in use). + // If nothing has happened at all since the mark, + // rewinding is a no-op and adding elapsed time + // for doing nothing is meaningless, so don't. + if ts.log.Len() > ts.mark { + rewind() + markTime() + } + // Print phase heading and mark start of phase output. + fmt.Fprintf(&ts.log, "%s\n", line) + ts.mark = ts.log.Len() + ts.start = time.Now() + continue + } + + // Parse input line. Ignore blanks entirely. + args := ts.parse(line) + if len(args) == 0 { + continue + } + + // Echo command to log. + fmt.Fprintf(&ts.log, "> %s\n", line) + + // Command prefix [cond] means only run this command if cond is satisfied. + for strings.HasPrefix(args[0], "[") && strings.HasSuffix(args[0], "]") { + cond := args[0] + cond = cond[1 : len(cond)-1] + cond = strings.TrimSpace(cond) + args = args[1:] + if len(args) == 0 { + ts.fatalf("missing command after condition") + } + want := true + if strings.HasPrefix(cond, "!") { + want = false + cond = strings.TrimSpace(cond[1:]) + } + // Known conds are: $GOOS, $GOARCH, runtime.Compiler, and 'short' (for testing.Short). + // + // NOTE: If you make changes here, update testdata/script/README too! + // + ok := false + switch cond { + case runtime.GOOS, runtime.GOARCH, runtime.Compiler: + ok = true + case "short": + ok = testing.Short() + case "cgo": + ok = canCgo + case "msan": + ok = canMSan + case "race": + ok = canRace + case "net": + ok = testenv.HasExternalNetwork() + case "link": + ok = testenv.HasLink() + case "symlink": + ok = testenv.HasSymlink() + default: + if strings.HasPrefix(cond, "exec:") { + prog := cond[len("exec:"):] + ok = execCache.Do(prog, func() interface{} { + _, err := exec.LookPath(prog) + return err == nil + }).(bool) + break + } + if !imports.KnownArch[cond] && !imports.KnownOS[cond] && cond != "gc" && cond != "gccgo" { + ts.fatalf("unknown condition %q", cond) + } + } + if ok != want { + // Don't run rest of line. + continue Script + } + } + + // Command prefix ! means negate the expectations about this command: + // go command should fail, match should not be found, etc. + neg := false + if args[0] == "!" { + neg = true + args = args[1:] + if len(args) == 0 { + ts.fatalf("! on line by itself") + } + } + + // Run command. + cmd := scriptCmds[args[0]] + if cmd == nil { + ts.fatalf("unknown command %q", args[0]) + } + cmd(ts, neg, args[1:]) + + // Command can ask script to stop early. + if ts.stopped { + return + } + } + + // Final phase ended. + rewind() + markTime() + fmt.Fprintf(&ts.log, "PASS\n") +} + +// scriptCmds are the script command implementations. +// Keep list and the implementations below sorted by name. +// +// NOTE: If you make changes here, update testdata/script/README too! +// +var scriptCmds = map[string]func(*testScript, bool, []string){ + "addcrlf": (*testScript).cmdAddcrlf, + "cd": (*testScript).cmdCd, + "cmp": (*testScript).cmdCmp, + "cp": (*testScript).cmdCp, + "env": (*testScript).cmdEnv, + "exec": (*testScript).cmdExec, + "exists": (*testScript).cmdExists, + "go": (*testScript).cmdGo, + "grep": (*testScript).cmdGrep, + "mkdir": (*testScript).cmdMkdir, + "rm": (*testScript).cmdRm, + "skip": (*testScript).cmdSkip, + "stale": (*testScript).cmdStale, + "stderr": (*testScript).cmdStderr, + "stdout": (*testScript).cmdStdout, + "stop": (*testScript).cmdStop, + "symlink": (*testScript).cmdSymlink, +} + +// addcrlf adds CRLF line endings to the named files. +func (ts *testScript) cmdAddcrlf(neg bool, args []string) { + if len(args) == 0 { + ts.fatalf("usage: addcrlf file...") + } + + for _, file := range args { + file = ts.mkabs(file) + data, err := ioutil.ReadFile(file) + ts.check(err) + ts.check(ioutil.WriteFile(file, bytes.Replace(data, []byte("\n"), []byte("\r\n"), -1), 0666)) + } +} + +// cd changes to a different directory. +func (ts *testScript) cmdCd(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! cd") + } + if len(args) != 1 { + ts.fatalf("usage: cd dir") + } + + dir := args[0] + if !filepath.IsAbs(dir) { + dir = filepath.Join(ts.cd, dir) + } + info, err := os.Stat(dir) + if os.IsNotExist(err) { + ts.fatalf("directory %s does not exist", dir) + } + ts.check(err) + if !info.IsDir() { + ts.fatalf("%s is not a directory", dir) + } + ts.cd = dir + fmt.Fprintf(&ts.log, "%s\n", ts.cd) +} + +// cmp compares two files. +func (ts *testScript) cmdCmp(neg bool, args []string) { + if neg { + // It would be strange to say "this file can have any content except this precise byte sequence". + ts.fatalf("unsupported: ! cmp") + } + if len(args) != 2 { + ts.fatalf("usage: cmp file1 file2") + } + + name1, name2 := args[0], args[1] + var text1, text2 string + if name1 == "stdout" { + text1 = ts.stdout + } else if name1 == "stderr" { + text1 = ts.stderr + } else { + data, err := ioutil.ReadFile(ts.mkabs(name1)) + ts.check(err) + text1 = string(data) + } + + data, err := ioutil.ReadFile(ts.mkabs(name2)) + ts.check(err) + text2 = string(data) + + if text1 == text2 { + return + } + + fmt.Fprintf(&ts.log, "[diff -%s +%s]\n%s\n", name1, name2, diff(text1, text2)) + ts.fatalf("%s and %s differ", name1, name2) +} + +// cp copies files, maybe eventually directories. +func (ts *testScript) cmdCp(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! cp") + } + if len(args) < 2 { + ts.fatalf("usage: cp src... dst") + } + + dst := ts.mkabs(args[len(args)-1]) + info, err := os.Stat(dst) + dstDir := err == nil && info.IsDir() + if len(args) > 2 && !dstDir { + ts.fatalf("cp: destination %s is not a directory", dst) + } + + for _, arg := range args[:len(args)-1] { + src := ts.mkabs(arg) + info, err := os.Stat(src) + ts.check(err) + data, err := ioutil.ReadFile(src) + ts.check(err) + targ := dst + if dstDir { + targ = filepath.Join(dst, filepath.Base(src)) + } + ts.check(ioutil.WriteFile(targ, data, info.Mode()&0777)) + } +} + +// env displays or adds to the environment. +func (ts *testScript) cmdEnv(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! env") + } + if len(args) == 0 { + printed := make(map[string]bool) // env list can have duplicates; only print effective value (from envMap) once + for _, kv := range ts.env { + k := kv[:strings.Index(kv, "=")] + if !printed[k] { + fmt.Fprintf(&ts.log, "%s=%s\n", k, ts.envMap[k]) + } + } + return + } + for _, env := range args { + i := strings.Index(env, "=") + if i < 0 { + // Display value instead of setting it. + fmt.Fprintf(&ts.log, "%s=%s\n", env, ts.envMap[env]) + continue + } + ts.env = append(ts.env, env) + ts.envMap[env[:i]] = env[i+1:] + } +} + +// exec runs the given command. +func (ts *testScript) cmdExec(neg bool, args []string) { + if len(args) < 1 { + ts.fatalf("usage: exec program [args...]") + } + var err error + ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...) + if ts.stdout != "" { + fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout) + } + if ts.stderr != "" { + fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr) + } + if err != nil { + fmt.Fprintf(&ts.log, "[%v]\n", err) + if !neg { + ts.fatalf("unexpected command failure") + } + } else { + if neg { + ts.fatalf("unexpected command success") + } + } +} + +// exists checks that the list of files exists. +func (ts *testScript) cmdExists(neg bool, args []string) { + var readonly bool + if len(args) > 0 && args[0] == "-readonly" { + readonly = true + args = args[1:] + } + if len(args) == 0 { + ts.fatalf("usage: exists [-readonly] file...") + } + + for _, file := range args { + file = ts.mkabs(file) + info, err := os.Stat(file) + if err == nil && neg { + what := "file" + if info.IsDir() { + what = "directory" + } + ts.fatalf("%s %s unexpectedly exists", what, file) + } + if err != nil && !neg { + ts.fatalf("%s does not exist", file) + } + if err == nil && !neg && readonly && info.Mode()&0222 != 0 { + ts.fatalf("%s exists but is writable", file) + } + } +} + +// go runs the go command. +func (ts *testScript) cmdGo(neg bool, args []string) { + ts.cmdExec(neg, append([]string{testGo}, args...)) +} + +// mkdir creates directories. +func (ts *testScript) cmdMkdir(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! mkdir") + } + if len(args) < 1 { + ts.fatalf("usage: mkdir dir...") + } + for _, arg := range args { + ts.check(os.MkdirAll(ts.mkabs(arg), 0777)) + } +} + +// rm removes files or directories. +func (ts *testScript) cmdRm(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! rm") + } + if len(args) < 1 { + ts.fatalf("usage: rm file...") + } + for _, arg := range args { + file := ts.mkabs(arg) + removeAll(file) // does chmod and then attempts rm + ts.check(os.RemoveAll(file)) // report error + } +} + +// skip marks the test skipped. +func (ts *testScript) cmdSkip(neg bool, args []string) { + if len(args) > 1 { + ts.fatalf("usage: skip [msg]") + } + if neg { + ts.fatalf("unsupported: ! skip") + } + if len(args) == 1 { + ts.t.Skip(args[0]) + } + ts.t.Skip() +} + +// stale checks that the named build targets are stale. +func (ts *testScript) cmdStale(neg bool, args []string) { + if len(args) == 0 { + ts.fatalf("usage: stale target...") + } + tmpl := "{{if .Error}}{{.ImportPath}}: {{.Error.Err}}{else}}" + if neg { + tmpl += "{{if .Stale}}{{.ImportPath}} is unexpectedly stale{{end}}" + } else { + tmpl += "{{if not .Stale}}{{.ImportPath}} is unexpectedly NOT stale{{end}}" + } + tmpl += "{{end}}" + goArgs := append([]string{"list", "-e", "-f=" + tmpl}, args...) + stdout, stderr, err := ts.exec(testGo, goArgs...) + if err != nil { + ts.fatalf("go list: %v\n%s%s", err, stdout, stderr) + } + if stdout != "" { + ts.fatalf("%s", stdout) + } +} + +// stdout checks that the last go command standard output matches a regexp. +func (ts *testScript) cmdStdout(neg bool, args []string) { + scriptMatch(ts, neg, args, ts.stdout, "stdout") +} + +// stderr checks that the last go command standard output matches a regexp. +func (ts *testScript) cmdStderr(neg bool, args []string) { + scriptMatch(ts, neg, args, ts.stderr, "stderr") +} + +// grep checks that file content matches a regexp. +// Like stdout/stderr and unlike Unix grep, it accepts Go regexp syntax. +func (ts *testScript) cmdGrep(neg bool, args []string) { + scriptMatch(ts, neg, args, "", "grep") +} + +// scriptMatch implements both stdout and stderr. +func scriptMatch(ts *testScript, neg bool, args []string, text, name string) { + n := 0 + if len(args) >= 1 && strings.HasPrefix(args[0], "-count=") { + if neg { + ts.fatalf("cannot use -count= with negated match") + } + var err error + n, err = strconv.Atoi(args[0][len("-count="):]) + if err != nil { + ts.fatalf("bad -count=: %v", err) + } + if n < 1 { + ts.fatalf("bad -count=: must be at least 1") + } + args = args[1:] + } + + extraUsage := "" + want := 1 + if name == "grep" { + extraUsage = " file" + want = 2 + } + if len(args) != want { + ts.fatalf("usage: %s [-count=N] 'pattern' file%s", name, extraUsage) + } + + pattern := args[0] + re, err := regexp.Compile(`(?m)` + pattern) + ts.check(err) + + isGrep := name == "grep" + if isGrep { + name = args[1] // for error messages + data, err := ioutil.ReadFile(ts.mkabs(args[1])) + ts.check(err) + text = string(data) + } + + // Matching against workdir would be misleading. + text = strings.Replace(text, ts.workdir, "$WORK", -1) + + if neg { + if re.MatchString(text) { + if isGrep { + fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) + } + ts.fatalf("unexpected match for %#q found in %s: %s", pattern, name, re.FindString(text)) + } + } else { + if !re.MatchString(text) { + if isGrep { + fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) + } + ts.fatalf("no match for %#q found in %s", pattern, name) + } + if n > 0 { + count := len(re.FindAllString(text, -1)) + if count != n { + if isGrep { + fmt.Fprintf(&ts.log, "[%s]\n%s\n", name, text) + } + ts.fatalf("have %d matches for %#q, want %d", count, pattern, n) + } + } + } +} + +// stop stops execution of the test (marking it passed). +func (ts *testScript) cmdStop(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! stop") + } + if len(args) > 1 { + ts.fatalf("usage: stop [msg]") + } + if len(args) == 1 { + fmt.Fprintf(&ts.log, "stop: %s\n", args[0]) + } else { + fmt.Fprintf(&ts.log, "stop\n") + } + ts.stopped = true +} + +// symlink creates a symbolic link. +func (ts *testScript) cmdSymlink(neg bool, args []string) { + if neg { + ts.fatalf("unsupported: ! symlink") + } + if len(args) != 3 || args[1] != "->" { + ts.fatalf("usage: symlink file -> target") + } + // Note that the link target args[2] is not interpreted with mkabs: + // it will be interpreted relative to the directory file is in. + ts.check(os.Symlink(args[2], ts.mkabs(args[0]))) +} + +// Helpers for command implementations. + +// abbrev abbreviates the actual work directory in the string s to the literal string "$WORK". +func (ts *testScript) abbrev(s string) string { + s = strings.Replace(s, ts.workdir, "$WORK", -1) + if *testWork { + // Expose actual $WORK value in environment dump on first line of work script, + // so that the user can find out what directory -testwork left behind. + s = "WORK=" + ts.workdir + "\n" + strings.TrimPrefix(s, "WORK=$WORK\n") + } + return s +} + +// check calls ts.fatalf if err != nil. +func (ts *testScript) check(err error) { + if err != nil { + ts.fatalf("%v", err) + } +} + +// exec runs the given command line (an actual subprocess, not simulated) +// in ts.cd with environment ts.env and then returns collected standard output and standard error. +func (ts *testScript) exec(command string, args ...string) (stdout, stderr string, err error) { + cmd := exec.Command(command, args...) + cmd.Dir = ts.cd + cmd.Env = append(ts.env, "PWD="+ts.cd) + var stdoutBuf, stderrBuf strings.Builder + cmd.Stdout = &stdoutBuf + cmd.Stderr = &stderrBuf + err = cmd.Run() + return stdoutBuf.String(), stderrBuf.String(), err +} + +// expand applies environment variable expansion to the string s. +func (ts *testScript) expand(s string) string { + return os.Expand(s, func(key string) string { return ts.envMap[key] }) +} + +// fatalf aborts the test with the given failure message. +func (ts *testScript) fatalf(format string, args ...interface{}) { + fmt.Fprintf(&ts.log, "FAIL: %s:%d: %s\n", ts.file, ts.lineno, fmt.Sprintf(format, args...)) + ts.t.FailNow() +} + +// mkabs interprets file relative to the test script's current directory +// and returns the corresponding absolute path. +func (ts *testScript) mkabs(file string) string { + if filepath.IsAbs(file) { + return file + } + return filepath.Join(ts.cd, file) +} + +// parse parses a single line as a list of space-separated arguments +// subject to environment variable expansion (but not resplitting). +// Single quotes around text disable splitting and expansion. +// To embed a single quote, double it: 'Don''t communicate by sharing memory.' +func (ts *testScript) parse(line string) []string { + ts.line = line + + var ( + args []string + arg string // text of current arg so far (need to add line[start:i]) + start = -1 // if >= 0, position where current arg text chunk starts + quoted = false // currently processing quoted text + ) + for i := 0; ; i++ { + if !quoted && (i >= len(line) || line[i] == ' ' || line[i] == '\t' || line[i] == '\r' || line[i] == '#') { + // Found arg-separating space. + if start >= 0 { + arg += ts.expand(line[start:i]) + args = append(args, arg) + start = -1 + arg = "" + } + if i >= len(line) || line[i] == '#' { + break + } + continue + } + if i >= len(line) { + ts.fatalf("unterminated quoted argument") + } + if line[i] == '\'' { + if !quoted { + // starting a quoted chunk + if start >= 0 { + arg += ts.expand(line[start:i]) + } + start = i + 1 + quoted = true + continue + } + // 'foo''bar' means foo'bar, like in rc shell and Pascal. + if i+1 < len(line) && line[i+1] == '\'' { + arg += line[start:i] + start = i + 1 + i++ // skip over second ' before next iteration + continue + } + // ending a quoted chunk + arg += line[start:i] + start = i + 1 + quoted = false + continue + } + // found character worth saving; make sure we're saving + if start < 0 { + start = i + } + } + return args +} + +// diff returns a formatted diff of the two texts, +// showing the entire text and the minimum line-level +// additions and removals to turn text1 into text2. +// (That is, lines only in text1 appear with a leading -, +// and lines only in text2 appear with a leading +.) +func diff(text1, text2 string) string { + if text1 != "" && !strings.HasSuffix(text1, "\n") { + text1 += "(missing final newline)" + } + lines1 := strings.Split(text1, "\n") + lines1 = lines1[:len(lines1)-1] // remove empty string after final line + if text2 != "" && !strings.HasSuffix(text2, "\n") { + text2 += "(missing final newline)" + } + lines2 := strings.Split(text2, "\n") + lines2 = lines2[:len(lines2)-1] // remove empty string after final line + + // Naive dynamic programming algorithm for edit distance. + // https://en.wikipedia.org/wiki/Wagner–Fischer_algorithm + // dist[i][j] = edit distance between lines1[:len(lines1)-i] and lines2[:len(lines2)-j] + // (The reversed indices make following the minimum cost path + // visit lines in the same order as in the text.) + dist := make([][]int, len(lines1)+1) + for i := range dist { + dist[i] = make([]int, len(lines2)+1) + if i == 0 { + for j := range dist[0] { + dist[0][j] = j + } + continue + } + for j := range dist[i] { + if j == 0 { + dist[i][0] = i + continue + } + cost := dist[i][j-1] + 1 + if cost > dist[i-1][j]+1 { + cost = dist[i-1][j] + 1 + } + if lines1[len(lines1)-i] == lines2[len(lines2)-j] { + if cost > dist[i-1][j-1] { + cost = dist[i-1][j-1] + } + } + dist[i][j] = cost + } + } + + var buf strings.Builder + i, j := len(lines1), len(lines2) + for i > 0 || j > 0 { + cost := dist[i][j] + if i > 0 && j > 0 && cost == dist[i-1][j-1] && lines1[len(lines1)-i] == lines2[len(lines2)-j] { + fmt.Fprintf(&buf, " %s\n", lines1[len(lines1)-i]) + i-- + j-- + } else if i > 0 && cost == dist[i-1][j]+1 { + fmt.Fprintf(&buf, "-%s\n", lines1[len(lines1)-i]) + i-- + } else { + fmt.Fprintf(&buf, "+%s\n", lines2[len(lines2)-j]) + j-- + } + } + return buf.String() +} + +var diffTests = []struct { + text1 string + text2 string + diff string +}{ + {"a b c", "a b d e f", "a b -c +d +e +f"}, + {"", "a b c", "+a +b +c"}, + {"a b c", "", "-a -b -c"}, + {"a b c", "d e f", "-a -b -c +d +e +f"}, + {"a b c d e f", "a b d e f", "a b -c d e f"}, + {"a b c e f", "a b c d e f", "a b c +d e f"}, +} + +func TestDiff(t *testing.T) { + for _, tt := range diffTests { + // Turn spaces into \n. + text1 := strings.Replace(tt.text1, " ", "\n", -1) + if text1 != "" { + text1 += "\n" + } + text2 := strings.Replace(tt.text2, " ", "\n", -1) + if text2 != "" { + text2 += "\n" + } + out := diff(text1, text2) + // Cut final \n, cut spaces, turn remaining \n into spaces. + out = strings.Replace(strings.Replace(strings.TrimSuffix(out, "\n"), " ", "", -1), "\n", " ", -1) + if out != tt.diff { + t.Errorf("diff(%q, %q) = %q, want %q", text1, text2, out, tt.diff) + } + } +} diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go new file mode 100644 index 0000000000..19850af0f3 --- /dev/null +++ b/src/cmd/go/testdata/addmod.go @@ -0,0 +1,154 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Addmod adds a module as a txtar archive to the testdata/mod directory. +// +// Usage: +// +// go run addmod.go path@version... +// +// It should only be used for very small modules - we do not want to check +// very large files into testdata/mod. +// +// It is acceptable to edit the archive afterward to remove or shorten files. +// See mod/README for more information. +// +package main + +import ( + "bytes" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + + "../internal/txtar" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go run addmod.go path@version...\n") + os.Exit(2) +} + +var tmpdir string + +func fatalf(format string, args ...interface{}) { + os.RemoveAll(tmpdir) + log.Fatalf(format, args...) +} + +const goCmd = "vgo" + +func main() { + flag.Usage = usage + flag.Parse() + if flag.NArg() == 0 { + usage() + } + + log.SetPrefix("addmod: ") + log.SetFlags(0) + + var err error + tmpdir, err = ioutil.TempDir("", "addmod-") + if err != nil { + log.Fatal(err) + } + + run := func(command string, args ...string) string { + cmd := exec.Command(command, args...) + cmd.Dir = tmpdir + var stderr bytes.Buffer + cmd.Stderr = &stderr + out, err := cmd.Output() + if err != nil { + fatalf("%s %s: %v\n%s", command, strings.Join(args, " "), err, stderr.Bytes()) + } + return string(out) + } + + gopath := strings.TrimSpace(run("go", "env", "GOPATH")) + if gopath == "" { + fatalf("cannot find GOPATH") + } + + exitCode := 0 + for _, arg := range flag.Args() { + if err := ioutil.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module m\n"), 0666); err != nil { + fatalf("%v", err) + } + run(goCmd, "get", "-d", arg) + path := arg + if i := strings.Index(path, "@"); i >= 0 { + path = path[:i] + } + out := run(goCmd, "list", "-m", "-f={{.Path}} {{.Version}} {{.Dir}}", path) + f := strings.Fields(out) + if len(f) != 3 { + log.Printf("go list -m %s: unexpected output %q", arg, out) + exitCode = 1 + continue + } + path, vers, dir := f[0], f[1], f[2] + mod, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".mod")) + if err != nil { + log.Printf("%s: %v", arg, err) + exitCode = 1 + continue + } + info, err := ioutil.ReadFile(filepath.Join(gopath, "pkg/mod/cache/download", path, "@v", vers+".info")) + if err != nil { + log.Printf("%s: %v", arg, err) + exitCode = 1 + continue + } + + a := new(txtar.Archive) + title := arg + if !strings.Contains(arg, "@") { + title += "@" + vers + } + a.Comment = []byte(fmt.Sprintf("module %s\n\n", title)) + a.Files = []txtar.File{ + {Name: ".mod", Data: mod}, + {Name: ".info", Data: info}, + } + dir = filepath.Clean(dir) + err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if !info.Mode().IsRegular() { + return nil + } + name := info.Name() + if name == "go.mod" || strings.HasSuffix(name, ".go") { + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + a.Files = append(a.Files, txtar.File{Name: strings.TrimPrefix(path, dir+string(filepath.Separator)), Data: data}) + } + return nil + }) + if err != nil { + log.Printf("%s: %v", arg, err) + exitCode = 1 + continue + } + + data := txtar.Format(a) + target := filepath.Join("mod", strings.Replace(path, "/", "_", -1)+"_"+vers+".txt") + if err := ioutil.WriteFile(target, data, 0666); err != nil { + log.Printf("%s: %v", arg, err) + exitCode = 1 + continue + } + } + os.RemoveAll(tmpdir) + os.Exit(exitCode) +} diff --git a/src/cmd/go/testdata/mod/README b/src/cmd/go/testdata/mod/README new file mode 100644 index 0000000000..43ddf77eff --- /dev/null +++ b/src/cmd/go/testdata/mod/README @@ -0,0 +1,36 @@ +This directory holds Go modules served by a Go module proxy +that runs on localhost during tests, both to make tests avoid +requiring specific network servers and also to make them +significantly faster. + +A small go get'able test module can be added here by running + + cd cmd/go/testdata + go run addmod.go path@vers + +where path and vers are the module path and version to add here. + +For interactive experimentation using this set of modules, run: + + cd cmd/go + go test -proxy=localhost:1234 & + export GOPROXY=http://localhost:1234/mod + +and then run go commands as usual. + +Modules saved to this directory should be small: a few kilobytes at most. +It is acceptable to edit the archives created by addmod.go to remove +or shorten files. It is also acceptable to write module archives by hand: +they need not be backed by some public git repo. + +Each module archive is named path_vers.txt, where slashes in path +have been replaced with underscores. The archive must contain +two files ".info" and ".mod", to be served as the info and mod files +in the proxy protocol (see https://research.swtch.com/vgo-module). +The remaining files are served as the content of the module zip file. +The path@vers prefix required of files in the zip file is added +automatically by the proxy: the files in the archive have names without +the prefix, like plain "go.mod", "x.go", and so on. + +See ../addmod.go and ../savedir.go for tools to generate txtar files, +although again it is also fine to write them by hand. diff --git a/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt new file mode 100644 index 0000000000..1ecfa0b6de --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.0.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for package moved into a parent module. + +-- .mod -- +module example.com/join/subpkg +-- .info -- +{"Version": "v1.0.0"} +-- x.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt new file mode 100644 index 0000000000..9eb823adb7 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_join_subpkg_v1.1.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for package moved into a parent module. + +-- .mod -- +module example.com/join/subpkg + +require example.com/join v1.1.0 +-- .info -- +{"Version": "v1.1.0"} diff --git a/src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt new file mode 100644 index 0000000000..84c68b13b6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_join_v1.0.0.txt @@ -0,0 +1,7 @@ +Written by hand. +Test case for package moved into a parent module. + +-- .mod -- +module example.com/join +-- .info -- +{"Version": "v1.0.0"} diff --git a/src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt new file mode 100644 index 0000000000..5f92036d9e --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_join_v1.1.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for package moved into a parent module. + +-- .mod -- +module example.com/join +-- .info -- +{"Version": "v1.1.0"} +-- subpkg/x.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt new file mode 100644 index 0000000000..b197b66398 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split_subpkg_v1.1.0.txt @@ -0,0 +1,11 @@ +Written by hand. +Test case for getting a package that has been moved to a different module. + +-- .mod -- +module example.com/split/subpkg + +require example.com/split v1.1.0 +-- .info -- +{"Version": "v1.1.0"} +-- x.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt new file mode 100644 index 0000000000..b706e590d9 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split_v1.0.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for getting a package that has been moved to a different module. + +-- .mod -- +module example.com/split +-- .info -- +{"Version": "v1.0.0"} +-- subpkg/x.go -- +package subpkg diff --git a/src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt b/src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt new file mode 100644 index 0000000000..d38971f9b6 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_split_v1.1.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for getting a package that has been moved to a different module. + +-- .mod -- +module example.com/split + +require example.com/split/subpkg v1.1.0 +-- .info -- +{"Version": "v1.1.0"} diff --git a/src/cmd/go/testdata/mod/example.com_v1.0.0.txt b/src/cmd/go/testdata/mod/example.com_v1.0.0.txt new file mode 100644 index 0000000000..263287d9e2 --- /dev/null +++ b/src/cmd/go/testdata/mod/example.com_v1.0.0.txt @@ -0,0 +1,9 @@ +Written by hand. +Test case for module at root of domain. + +-- .mod -- +module example.com +-- .info -- +{"Version": "v1.0.0"} +-- x.go -- +package x diff --git a/src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt new file mode 100644 index 0000000000..0420a1a4a0 --- /dev/null +++ b/src/cmd/go/testdata/mod/golang.org_notx_useinternal_v0.1.0.txt @@ -0,0 +1,13 @@ +written by hand — attempts to use a prohibited internal package +(https://golang.org/s/go14internal) + +-- .mod -- +module golang.org/notx/useinternal +-- .info -- +{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"} +-- go.mod -- +module golang.org/notx/useinternal +-- useinternal.go -- +package useinternal + +import _ "golang.org/x/internal/subtle" diff --git a/src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt new file mode 100644 index 0000000000..5737e95cf4 --- /dev/null +++ b/src/cmd/go/testdata/mod/golang.org_x_internal_v0.1.0.txt @@ -0,0 +1,43 @@ +written by hand — loosely derived from golang.org/x/crypto/internal/subtle, +but splitting the internal package across a module boundary + +-- .mod -- +module golang.org/x/internal +-- .info -- +{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"} +-- go.mod -- +module golang.org/x/internal +-- subtle/aliasing.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !appengine + +// This is a tiny version of golang.org/x/crypto/internal/subtle. + +package subtle + +import "unsafe" + +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} +-- subtle/aliasing_appengine.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build appengine + +package subtle + +import "reflect" + +func AnyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() && + reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer() +} diff --git a/src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt b/src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt new file mode 100644 index 0000000000..f4f50cdedb --- /dev/null +++ b/src/cmd/go/testdata/mod/golang.org_x_text_v0.0.0-20170915032832-14c0d48ead0c.txt @@ -0,0 +1,47 @@ +written by hand - just enough to compile rsc.io/sampler, rsc.io/quote + +-- .mod -- +module golang.org/x/text +-- .info -- +{"Version":"v0.0.0-20170915032832-14c0d48ead0c","Name":"v0.0.0-20170915032832-14c0d48ead0c","Short":"14c0d48ead0c","Time":"2017-09-15T03:28:32Z"} +-- go.mod -- +module golang.org/x/text +-- unused/unused.go -- +package unused +-- language/lang.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a tiny version of golang.org/x/text. + +package language + +import "strings" + +type Tag string + +func Make(s string) Tag { return Tag(s) } + +func (t Tag) String() string { return string(t) } + +func NewMatcher(tags []Tag) Matcher { return &matcher{tags} } + +type Matcher interface { + Match(...Tag) (Tag, int, int) +} + +type matcher struct { + tags []Tag +} + +func (m *matcher) Match(prefs ...Tag) (Tag, int, int) { + for _, pref := range prefs { + for _, tag := range m.tags { + if tag == pref || strings.HasPrefix(string(pref), string(tag+"-")) || strings.HasPrefix(string(tag), string(pref+"-")) { + return tag, 0, 0 + } + } + } + return m.tags[0], 0, 0 +} diff --git a/src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt b/src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt new file mode 100644 index 0000000000..5561afae8e --- /dev/null +++ b/src/cmd/go/testdata/mod/golang.org_x_text_v0.3.0.txt @@ -0,0 +1,47 @@ +written by hand - just enough to compile rsc.io/sampler, rsc.io/quote + +-- .mod -- +module golang.org/x/text +-- .info -- +{"Version":"v0.3.0","Name":"","Short":"","Time":"2017-09-16T03:28:32Z"} +-- go.mod -- +module golang.org/x/text +-- unused/unused.go -- +package unused +-- language/lang.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This is a tiny version of golang.org/x/text. + +package language + +import "strings" + +type Tag string + +func Make(s string) Tag { return Tag(s) } + +func (t Tag) String() string { return string(t) } + +func NewMatcher(tags []Tag) Matcher { return &matcher{tags} } + +type Matcher interface { + Match(...Tag) (Tag, int, int) +} + +type matcher struct { + tags []Tag +} + +func (m *matcher) Match(prefs ...Tag) (Tag, int, int) { + for _, pref := range prefs { + for _, tag := range m.tags { + if tag == pref || strings.HasPrefix(string(pref), string(tag+"-")) || strings.HasPrefix(string(tag), string(pref+"-")) { + return tag, 0, 0 + } + } + } + return m.tags[0], 0, 0 +} diff --git a/src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt b/src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt new file mode 100644 index 0000000000..3fcba447be --- /dev/null +++ b/src/cmd/go/testdata/mod/golang.org_x_useinternal_v0.1.0.txt @@ -0,0 +1,13 @@ +written by hand — uses an internal package from another module +(https://golang.org/s/go14internal) + +-- .mod -- +module golang.org/x/useinternal +-- .info -- +{"Version":"v0.1.0","Name":"","Short":"","Time":"2018-07-25T17:24:00Z"} +-- go.mod -- +module golang.org/x/useinternal +-- useinternal.go -- +package useinternal + +import _ "golang.org/x/internal/subtle" diff --git a/src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt b/src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt new file mode 100644 index 0000000000..f174159fd3 --- /dev/null +++ b/src/cmd/go/testdata/mod/gopkg.in_dummy.v2-unstable_v2.0.0.txt @@ -0,0 +1,9 @@ +gopkg.in/dummy.v2-unstable v2.0.0 +written by hand + +-- .mod -- +module gopkg.in/dummy.v2-unstable +-- .info -- +{"Version":"v2.0.0"} +-- dummy.go -- +package dummy diff --git a/src/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt b/src/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt new file mode 100644 index 0000000000..0f060dc8e3 --- /dev/null +++ b/src/cmd/go/testdata/mod/research.swtch.com_vgo-tour_v1.0.0.txt @@ -0,0 +1,23 @@ +research.swtch.com/vgo-tour@v1.0.0 + +-- .mod -- +module "research.swtch.com/vgo-tour" +-- .info -- +{"Version":"v1.0.0","Name":"84de74b35823c1e49634f2262f1a58cfc951ebae","Short":"84de74b35823","Time":"2018-02-20T00:04:00Z"} +-- go.mod -- +module "research.swtch.com/vgo-tour" +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "rsc.io/quote" +) + +func main() { + fmt.Println(quote.Hello()) +} diff --git a/src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt new file mode 100644 index 0000000000..6276147535 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_!c!g!o_v1.0.0.txt @@ -0,0 +1,19 @@ +rsc.io/CGO v1.0.0 + +-- .mod -- +module rsc.io/CGO +-- .info -- +{"Version":"v1.0.0","Name":"","Short":"","Time":"2018-08-01T18:23:45Z"} +-- go.mod -- +module rsc.io/CGO +-- cgo.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package CGO + +// #cgo CFLAGS: -I${SRCDIR} +import "C" + +var V = 0 diff --git a/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt new file mode 100644 index 0000000000..21185c39f3 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.2.txt @@ -0,0 +1,88 @@ +rsc.io/QUOTE v1.5.2 + +-- .mod -- +module rsc.io/QUOTE + +require rsc.io/quote v1.5.2 +-- .info -- +{"Version":"v1.5.2","Name":"","Short":"","Time":"2018-07-15T16:25:34Z"} +-- go.mod -- +module rsc.io/QUOTE + +require rsc.io/quote v1.5.2 +-- QUOTE/quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// PACKAGE QUOTE COLLECTS LOUD SAYINGS. +package QUOTE + +import ( + "strings" + + "rsc.io/quote" +) + +// HELLO RETURNS A GREETING. +func HELLO() string { + return strings.ToUpper(quote.Hello()) +} + +// GLASS RETURNS A USEFUL PHRASE FOR WORLD TRAVELERS. +func GLASS() string { + return strings.ToUpper(quote.GLASS()) +} + +// GO RETURNS A GO PROVERB. +func GO() string { + return strings.ToUpper(quote.GO()) +} + +// OPT RETURNS AN OPTIMIZATION TRUTH. +func OPT() string { + return strings.ToUpper(quote.OPT()) +} +-- QUOTE/quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package QUOTE + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHELLO(t *testing.T) { + hello := "HELLO, WORLD" + if out := HELLO(); out != hello { + t.Errorf("HELLO() = %q, want %q", out, hello) + } +} + +func TestGLASS(t *testing.T) { + glass := "I CAN EAT GLASS AND IT DOESN'T HURT ME." + if out := GLASS(); out != glass { + t.Errorf("GLASS() = %q, want %q", out, glass) + } +} + +func TestGO(t *testing.T) { + go1 := "DON'T COMMUNICATE BY SHARING MEMORY, SHARE MEMORY BY COMMUNICATING." + if out := GO(); out != go1 { + t.Errorf("GO() = %q, want %q", out, go1) + } +} + +func TestOPT(t *testing.T) { + opt := "IF A PROGRAM IS TOO SLOW, IT MUST HAVE A LOOP." + if out := OPT(); out != opt { + t.Errorf("OPT() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt new file mode 100644 index 0000000000..54bac2df7b --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_!q!u!o!t!e_v1.5.3-!p!r!e.txt @@ -0,0 +1,88 @@ +rsc.io/QUOTE v1.5.3-PRE (sigh) + +-- .mod -- +module rsc.io/QUOTE + +require rsc.io/quote v1.5.2 +-- .info -- +{"Version":"v1.5.3-PRE","Name":"","Short":"","Time":"2018-07-15T16:25:34Z"} +-- go.mod -- +module rsc.io/QUOTE + +require rsc.io/quote v1.5.2 +-- QUOTE/quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// PACKAGE QUOTE COLLECTS LOUD SAYINGS. +package QUOTE + +import ( + "strings" + + "rsc.io/quote" +) + +// HELLO RETURNS A GREETING. +func HELLO() string { + return strings.ToUpper(quote.Hello()) +} + +// GLASS RETURNS A USEFUL PHRASE FOR WORLD TRAVELERS. +func GLASS() string { + return strings.ToUpper(quote.GLASS()) +} + +// GO RETURNS A GO PROVERB. +func GO() string { + return strings.ToUpper(quote.GO()) +} + +// OPT RETURNS AN OPTIMIZATION TRUTH. +func OPT() string { + return strings.ToUpper(quote.OPT()) +} +-- QUOTE/quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package QUOTE + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHELLO(t *testing.T) { + hello := "HELLO, WORLD" + if out := HELLO(); out != hello { + t.Errorf("HELLO() = %q, want %q", out, hello) + } +} + +func TestGLASS(t *testing.T) { + glass := "I CAN EAT GLASS AND IT DOESN'T HURT ME." + if out := GLASS(); out != glass { + t.Errorf("GLASS() = %q, want %q", out, glass) + } +} + +func TestGO(t *testing.T) { + go1 := "DON'T COMMUNICATE BY SHARING MEMORY, SHARE MEMORY BY COMMUNICATING." + if out := GO(); out != go1 { + t.Errorf("GO() = %q, want %q", out, go1) + } +} + +func TestOPT(t *testing.T) { + opt := "IF A PROGRAM IS TOO SLOW, IT MUST HAVE A LOOP." + if out := OPT(); out != opt { + t.Errorf("OPT() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt new file mode 100644 index 0000000000..9d23e7db98 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badfile1_v1.0.0.txt @@ -0,0 +1,14 @@ +rsc.io/badfile1 v1.0.0 +written by hand +this is part of the badfile test but is a valid zip file. + +-- .mod -- +module rsc.io/badfile1 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module rsc.io/badfile1 +-- α.go -- +package α +-- .gitignore -- +-- x/y/z/.gitignore -- diff --git a/src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt new file mode 100644 index 0000000000..58e1e1c103 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badfile2_v1.0.0.txt @@ -0,0 +1,12 @@ +rsc.io/badfile1 v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badfile2 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module rsc.io/badfile2 +-- ☺.go -- +package smiley + diff --git a/src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt new file mode 100644 index 0000000000..a008448c5f --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badfile3_v1.0.0.txt @@ -0,0 +1,12 @@ +rsc.io/badfile3 v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badfile3 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module rsc.io/badfile3 +-- x?y.go -- +package x + diff --git a/src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt new file mode 100644 index 0000000000..e28844dc63 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badfile4_v1.0.0.txt @@ -0,0 +1,15 @@ +rsc.io/badfile4 v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badfile4 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module rsc.io/badfile4 +-- x/Y.go -- +package x +-- x/y.go -- +package x + + diff --git a/src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt new file mode 100644 index 0000000000..3c7903a3bc --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badfile5_v1.0.0.txt @@ -0,0 +1,13 @@ +rsc.io/badfile5 v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badfile5 +-- .info -- +{"Version":"v1.0.0"} +-- go.mod -- +module rsc.io/badfile5 +-- x/y/z/w.go -- +package z +-- x/Y/zz/ww.go -- +package zz diff --git a/src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt new file mode 100644 index 0000000000..993ceb7a0b --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_badmod_v1.0.0.txt @@ -0,0 +1,11 @@ +rsc.io/badmod v1.0.0 +written by hand + +-- .mod -- +module rsc.io/badmod +hello world +-- .info -- +{"Version":"v1.0.0"} +-- x.go -- +package x + diff --git a/src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt new file mode 100644 index 0000000000..a103e3f8aa --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_breaker_v1.0.0.txt @@ -0,0 +1,11 @@ +rsc.io/breaker v1.0.0 +written by hand + +-- .mod -- +module rsc.io/breaker +-- .info -- +{"Version":"v1.0.0"} +-- breaker.go -- +package breaker + +const X = 1 diff --git a/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt new file mode 100644 index 0000000000..59d8bacf07 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0+incompatible.txt @@ -0,0 +1,11 @@ +rsc.io/breaker v2.0.0+incompatible +written by hand + +-- .mod -- +module rsc.io/breaker +-- .info -- +{"Version":"v2.0.0+incompatible", "Name": "7307b307f4f0dde421900f8e5126fadac1e13aed", "Short": "7307b307f4f0"} +-- breaker.go -- +package breaker + +const XX = 2 diff --git a/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt new file mode 100644 index 0000000000..59d8bacf07 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_breaker_v2.0.0.txt @@ -0,0 +1,11 @@ +rsc.io/breaker v2.0.0+incompatible +written by hand + +-- .mod -- +module rsc.io/breaker +-- .info -- +{"Version":"v2.0.0+incompatible", "Name": "7307b307f4f0dde421900f8e5126fadac1e13aed", "Short": "7307b307f4f0"} +-- breaker.go -- +package breaker + +const XX = 2 diff --git a/src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt new file mode 100644 index 0000000000..d8a71f3cd9 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_fortune_v1.0.0.txt @@ -0,0 +1,15 @@ +rsc.io/fortune v1.0.0 +written by hand + +-- .mod -- +module rsc.io/fortune +-- .info -- +{"Version":"v1.0.0"} +-- fortune.go -- +package main + +import "rsc.io/quote" + +func main() { + println(quote.Hello()) +} diff --git a/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt new file mode 100644 index 0000000000..cfa91f08a5 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_fortune_v2_v2.0.0.txt @@ -0,0 +1,15 @@ +rsc.io/fortune v2.0.0 +written by hand + +-- .mod -- +module rsc.io/fortune/v2 +-- .info -- +{"Version":"v2.0.0"} +-- fortune.go -- +package main + +import "rsc.io/quote" + +func main() { + println(quote.Hello()) +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt new file mode 100644 index 0000000000..8ae173e7ae --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005133-e7a685a342c0.txt @@ -0,0 +1,60 @@ +rsc.io/quote@e7a685a342 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v0.0.0-20180214005133-e7a685a342c0","Name":"e7a685a342c001acc3eb7f5eafa82980480042c7","Short":"e7a685a342c0","Time":"2018-02-14T00:51:33Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory. Share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt new file mode 100644 index 0000000000..bc626bac7a --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180214005840-23179ee8a569.txt @@ -0,0 +1,86 @@ +rsc.io/quote@v0.0.0-20180214005840-23179ee8a569 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180214005840-23179ee8a569","Name":"23179ee8a569bb05d896ae05c6503ec69a19f99f","Short":"23179ee8a569","Time":"2018-02-14T00:58:40Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt new file mode 100644 index 0000000000..bbc8097dc3 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180628003336-dd9747d19b04.txt @@ -0,0 +1,100 @@ +rsc.io/quote@dd9747d + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180628003336-dd9747d19b04","Name":"dd9747d19b041365fbddf0399ddba6bff5eb1b3e","Short":"dd9747d19b04","Time":"2018-06-28T00:33:36Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +AN EVEN WORSE CHANGE! + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt new file mode 100644 index 0000000000..e461ed4231 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709153244-fd906ed3b100.txt @@ -0,0 +1,86 @@ +rsc.io/quote@v2.0.0 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180709153244-fd906ed3b100","Name":"fd906ed3b100e47181ffa9ec36d82294525c9109","Short":"fd906ed3b100","Time":"2018-07-09T15:32:44Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV2() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV2() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func GoV2() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func OptV2() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt new file mode 100644 index 0000000000..c1d511fda7 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709160352-0d003b9c4bfa.txt @@ -0,0 +1,98 @@ +rsc.io/quote@v0.0.0-20180709160352-0d003b9c4bfa + +-- .mod -- +module rsc.io/quote + +require rsc.io/sampler v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180709160352-0d003b9c4bfa","Name":"0d003b9c4bfac881641be8eb1598b782a467a97f","Short":"0d003b9c4bfa","Time":"2018-07-09T16:03:52Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module rsc.io/quote + +require rsc.io/sampler v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/quote/v2" + +// Hello returns a greeting. +func Hello() string { + return quote.HelloV2() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return quote.GlassV2() +} + +// Go returns a Go proverb. +func Go() string { + return quote.GoV2() +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return quote.OptV2() +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt new file mode 100644 index 0000000000..f7f794d76d --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162749-b44a0b17b2d1.txt @@ -0,0 +1,104 @@ +rsc.io/quote@v0.0.0-20180709162749-b44a0b17b2d1 + +-- .mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v2 v2.0.1 + rsc.io/sampler v1.3.0 +) +-- .info -- +{"Version":"v0.0.0-20180709162749-b44a0b17b2d1","Name":"b44a0b17b2d1fe4c98a8d0e7a68c9bf9e762799a","Short":"b44a0b17b2d1","Time":"2018-07-09T16:27:49Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v2 v2.0.1 + rsc.io/sampler v1.3.0 +) +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/quote/v2" + +// Hello returns a greeting. +func Hello() string { + return quote.HelloV2() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return quote.GlassV2() +} + +// Go returns a Go proverb. +func Go() string { + return quote.GoV2() +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return quote.OptV2() +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt new file mode 100644 index 0000000000..2d5d8b4e72 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162816-fe488b867524.txt @@ -0,0 +1,104 @@ +rsc.io/quote@v0.0.0-20180709162816-fe488b867524 + +-- .mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v2 v2.0.1 + rsc.io/sampler v1.3.0 +) +-- .info -- +{"Version":"v0.0.0-20180709162816-fe488b867524","Name":"fe488b867524806e861c3f4f43ae6946a42ca3f1","Short":"fe488b867524","Time":"2018-07-09T16:28:16Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v2 v2.0.1 + rsc.io/sampler v1.3.0 +) +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/quote/v2" + +// Hello returns a greeting. +func Hello() string { + return quote.HelloV2() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return quote.GlassV2() +} + +// Go returns a Go proverb. +func Go() string { + return quote.GoV2() +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return quote.OptV2() +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt new file mode 100644 index 0000000000..853a8c2a1a --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180709162918-a91498bed0a7.txt @@ -0,0 +1,98 @@ +rsc.io/quote@v0.0.0-20180709162918-a91498bed0a7 + +-- .mod -- +module rsc.io/quote + +require rsc.io/sampler v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180709162918-a91498bed0a7","Name":"a91498bed0a73d4bb9c1fb2597925f7883bc40a7","Short":"a91498bed0a7","Time":"2018-07-09T16:29:18Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module rsc.io/quote + +require rsc.io/sampler v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/quote/v3" + +// Hello returns a greeting. +func Hello() string { + return quote.HelloV3() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return quote.GlassV3() +} + +// Go returns a Go proverb. +func Go() string { + return quote.GoV3() +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return quote.OptV3() +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt new file mode 100644 index 0000000000..2ebeac3971 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v0.0.0-20180710144737-5d9f230bcfba.txt @@ -0,0 +1,104 @@ +rsc.io/quote@v0.0.0-20180710144737-5d9f230bcfba + +-- .mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v3 v3.0.0 + rsc.io/sampler v1.3.0 +) +-- .info -- +{"Version":"v0.0.0-20180710144737-5d9f230bcfba","Name":"5d9f230bcfbae514bb6c2215694c2ce7273fc604","Short":"5d9f230bcfba","Time":"2018-07-10T14:47:37Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module rsc.io/quote + +require ( + rsc.io/quote/v3 v3.0.0 + rsc.io/sampler v1.3.0 +) +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/quote/v3" + +// Hello returns a greeting. +func Hello() string { + return quote.HelloV3() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return quote.GlassV3() +} + +// Go returns a Go proverb. +func Go() string { + return quote.GoV3() +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return quote.OptV3() +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt new file mode 100644 index 0000000000..9a07937444 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.0.0.txt @@ -0,0 +1,35 @@ +rsc.io/quote@v1.0.0 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v1.0.0","Name":"f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6","Short":"f488df80bcdb","Time":"2018-02-14T00:45:20Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt new file mode 100644 index 0000000000..0c41605390 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.1.0.txt @@ -0,0 +1,48 @@ +rsc.io/quote@v1.1.0 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v1.1.0","Name":"cfd7145f43f92a8d56b4a3dd603795a3291381a9","Short":"cfd7145f43f9","Time":"2018-02-14T00:46:44Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt new file mode 100644 index 0000000000..e714f0b913 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.0.txt @@ -0,0 +1,61 @@ +rsc.io/quote@v1.2.0 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v1.2.0","Name":"d8a3de91045c932a1c71e545308fe97571d6d65c","Short":"d8a3de91045c","Time":"2018-02-14T00:47:51Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +// Go returns a Go proverb. +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory. Share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt new file mode 100644 index 0000000000..89d5191d3a --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.2.1.txt @@ -0,0 +1,60 @@ +rsc.io/quote@v1.2.1 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v1.2.1","Name":"5c1f03b64ab7aa958798a569a31924655dc41e76","Short":"5c1f03b64ab7","Time":"2018-02-14T00:54:20Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt new file mode 100644 index 0000000000..d62766c7d2 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.3.0.txt @@ -0,0 +1,73 @@ +rsc.io/quote@v1.3.0 + +-- .mod -- +module "rsc.io/quote" +-- .info -- +{"Version":"v1.3.0","Name":"84de74b35823c1e49634f2262f1a58cfc951ebae","Short":"84de74b35823","Time":"2018-02-14T00:54:53Z"} +-- go.mod -- +module "rsc.io/quote" +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt new file mode 100644 index 0000000000..698ff8de81 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.4.0.txt @@ -0,0 +1,79 @@ +rsc.io/quote@v1.4.0 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.0.0 +-- .info -- +{"Version":"v1.4.0","Name":"19e8b977bd2f437798c2cc2dcfe8a1c0f169481b","Short":"19e8b977bd2f","Time":"2018-02-14T00:56:05Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.0.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt new file mode 100644 index 0000000000..e7fcdbccff --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.0.txt @@ -0,0 +1,79 @@ +rsc.io/quote@v1.5.0 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v1.5.0","Name":"3ba1e30dc83bd52c990132b9dfb1688a9d22de13","Short":"3ba1e30dc83b","Time":"2018-02-14T00:58:15Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import "testing" + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt new file mode 100644 index 0000000000..eed051bea0 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.1.txt @@ -0,0 +1,86 @@ +rsc.io/quote@23179ee8a569 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v1.5.1","Name":"23179ee8a569bb05d896ae05c6503ec69a19f99f","Short":"23179ee8a569","Time":"2018-02-14T00:58:40Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt new file mode 100644 index 0000000000..8671f6fe77 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.2.txt @@ -0,0 +1,98 @@ +rsc.io/quote@v1.5.2 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v1.5.2","Name":"c4d4236f92427c64bfbcf1cc3f8142ab18f30b22","Short":"c4d4236f9242","Time":"2018-02-14T15:44:20Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt new file mode 100644 index 0000000000..212ef13aaf --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v1.5.3-pre1.txt @@ -0,0 +1,100 @@ +rsc.io/quote@v1.5.3-pre1 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v1.5.3-pre1","Name":"2473dfd877c95382420e47686aa9076bf58c79e0","Short":"2473dfd877c9","Time":"2018-06-28T00:32:53Z"} +-- buggy/buggy_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package buggy + +import "testing" + +func Test(t *testing.T) { + t.Fatal("buggy!") +} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// A CHANGE! + +// Hello returns a greeting. +func Hello() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func Glass() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func Go() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func Opt() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt new file mode 100644 index 0000000000..e461ed4231 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v2.0.0.txt @@ -0,0 +1,86 @@ +rsc.io/quote@v2.0.0 + +-- .mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- .info -- +{"Version":"v0.0.0-20180709153244-fd906ed3b100","Name":"fd906ed3b100e47181ffa9ec36d82294525c9109","Short":"fd906ed3b100","Time":"2018-07-09T15:32:44Z"} +-- go.mod -- +module "rsc.io/quote" + +require "rsc.io/sampler" v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV2() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV2() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func GoV2() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func OptV2() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt new file mode 100644 index 0000000000..d51128c46b --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v2_v2.0.1.txt @@ -0,0 +1,86 @@ +rsc.io/quote/v2@v2.0.1 + +-- .mod -- +module rsc.io/quote/v2 + +require rsc.io/sampler v1.3.0 +-- .info -- +{"Version":"v2.0.1","Name":"754f68430672776c84704e2d10209a6ec700cd64","Short":"754f68430672","Time":"2018-07-09T16:25:34Z"} +-- go.mod -- +module rsc.io/quote/v2 + +require rsc.io/sampler v1.3.0 +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV2() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV2() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func GoV2() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func OptV2() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} +-- quote_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package quote + +import ( + "os" + "testing" +) + +func init() { + os.Setenv("LC_ALL", "en") +} + +func TestHello(t *testing.T) { + hello := "Hello, world." + if out := Hello(); out != hello { + t.Errorf("Hello() = %q, want %q", out, hello) + } +} + +func TestGlass(t *testing.T) { + glass := "I can eat glass and it doesn't hurt me." + if out := Glass(); out != glass { + t.Errorf("Glass() = %q, want %q", out, glass) + } +} + +func TestGo(t *testing.T) { + go1 := "Don't communicate by sharing memory, share memory by communicating." + if out := Go(); out != go1 { + t.Errorf("Go() = %q, want %q", out, go1) + } +} + +func TestOpt(t *testing.T) { + opt := "If a program is too slow, it must have a loop." + if out := Opt(); out != opt { + t.Errorf("Opt() = %q, want %q", out, opt) + } +} diff --git a/src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt new file mode 100644 index 0000000000..0afe1f0519 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_quote_v3_v3.0.0.txt @@ -0,0 +1,45 @@ +rsc.io/quote/v3@v3.0.0 + +-- .mod -- +module rsc.io/quote/v3 + +require rsc.io/sampler v1.3.0 + +-- .info -- +{"Version":"v3.0.0","Name":"d88915d7e77ed0fd35d0a022a2f244e2202fd8c8","Short":"d88915d7e77e","Time":"2018-07-09T15:34:46Z"} +-- go.mod -- +module rsc.io/quote/v3 + +require rsc.io/sampler v1.3.0 + +-- quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote // import "rsc.io/quote" + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV3() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV3() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a Go proverb. +func GoV3() string { + return "Don't communicate by sharing memory, share memory by communicating." +} + +// Opt returns an optimization truth. +func OptV3() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt new file mode 100644 index 0000000000..c4b6a71c88 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.0.0.txt @@ -0,0 +1,20 @@ +rsc.io/sampler@v1.0.0 + +-- .mod -- +module "rsc.io/sampler" +-- .info -- +{"Version":"v1.0.0","Name":"60bef405c52117ad21d2adb10872b95cf17f8fca","Short":"60bef405c521","Time":"2018-02-13T18:05:54Z"} +-- go.mod -- +module "rsc.io/sampler" +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts. +package sampler // import "rsc.io/sampler" + +// Hello returns a greeting. +func Hello() string { + return "Hello, world." +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt new file mode 100644 index 0000000000..98c35fa238 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.0.txt @@ -0,0 +1,138 @@ +rsc.io/sampler@v1.2.0 + +-- .mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- .info -- +{"Version":"v1.2.0","Name":"25f24110b153246056eccc14a3a4cd81afaff586","Short":"25f24110b153","Time":"2018-02-13T18:13:45Z"} +-- go.mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations by Google Translate. + +package sampler + +var hello = newText(` + +English: en: Hello, world. +French: fr: Bonjour le monde. +Spanish: es: Hola Mundo. + +`) +-- hello_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var helloTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "Hello, world.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Bonjour la monde.", + }, +} + +func TestHello(t *testing.T) { + for _, tt := range helloTests { + text := Hello(tt.prefs...) + if text != tt.text { + t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts. +package sampler // import "rsc.io/sampler" + +import ( + "os" + "strings" + + "golang.org/x/text/language" +) + +// DefaultUserPrefs returns the default user language preferences. +// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment +// variables, in that order. +func DefaultUserPrefs() []language.Tag { + var prefs []language.Tag + for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} { + if env := os.Getenv(k); env != "" { + prefs = append(prefs, language.Make(env)) + } + } + return prefs +} + +// Hello returns a localized greeting. +// If no prefs are given, Hello uses DefaultUserPrefs. +func Hello(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return hello.find(prefs) +} + +// A text is a localized text. +type text struct { + byTag map[string]string + matcher language.Matcher +} + +// newText creates a new localized text, given a list of translations. +func newText(s string) *text { + t := &text{ + byTag: make(map[string]string), + } + var tags []language.Tag + for _, line := range strings.Split(s, "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + f := strings.Split(line, ": ") + if len(f) != 3 { + continue + } + tag := language.Make(f[1]) + tags = append(tags, tag) + t.byTag[tag.String()] = f[2] + } + t.matcher = language.NewMatcher(tags) + return t +} + +// find finds the text to use for the given language tag preferences. +func (t *text) find(prefs []language.Tag) string { + tag, _, _ := t.matcher.Match(prefs...) + s := t.byTag[tag.String()] + if strings.HasPrefix(s, "RTL ") { + s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E" + } + return s +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt new file mode 100644 index 0000000000..00b71bf0d5 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.2.1.txt @@ -0,0 +1,134 @@ +generated by ./addmod.bash rsc.io/sampler@v1.2.1 + +-- .mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- .info -- +{"Version":"v1.2.1","Name":"cac3af4f8a0ab40054fa6f8d423108a63a1255bb","Short":"cac3af4f8a0a","Time":"2018-02-13T18:16:22Z"}EOF +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations by Google Translate. + +package sampler + +var hello = newText(` + +English: en: Hello, world. +French: fr: Bonjour le monde. +Spanish: es: Hola Mundo. + +`) +-- hello_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var helloTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "Hello, world.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Bonjour le monde.", + }, +} + +func TestHello(t *testing.T) { + for _, tt := range helloTests { + text := Hello(tt.prefs...) + if text != tt.text { + t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts. +package sampler // import "rsc.io/sampler" + +import ( + "os" + "strings" + + "golang.org/x/text/language" +) + +// DefaultUserPrefs returns the default user language preferences. +// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment +// variables, in that order. +func DefaultUserPrefs() []language.Tag { + var prefs []language.Tag + for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} { + if env := os.Getenv(k); env != "" { + prefs = append(prefs, language.Make(env)) + } + } + return prefs +} + +// Hello returns a localized greeting. +// If no prefs are given, Hello uses DefaultUserPrefs. +func Hello(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return hello.find(prefs) +} + +// A text is a localized text. +type text struct { + byTag map[string]string + matcher language.Matcher +} + +// newText creates a new localized text, given a list of translations. +func newText(s string) *text { + t := &text{ + byTag: make(map[string]string), + } + var tags []language.Tag + for _, line := range strings.Split(s, "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + f := strings.Split(line, ": ") + if len(f) != 3 { + continue + } + tag := language.Make(f[1]) + tags = append(tags, tag) + t.byTag[tag.String()] = f[2] + } + t.matcher = language.NewMatcher(tags) + return t +} + +// find finds the text to use for the given language tag preferences. +func (t *text) find(prefs []language.Tag) string { + tag, _, _ := t.matcher.Match(prefs...) + s := t.byTag[tag.String()] + if strings.HasPrefix(s, "RTL ") { + s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E" + } + return s +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt new file mode 100644 index 0000000000..febe51fd9a --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.0.txt @@ -0,0 +1,202 @@ +rsc.io/sampler@v1.3.0 + +-- .mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- .info -- +{"Version":"v1.3.0","Name":"0cc034b51e57ed7832d4c67d526f75a900996e5c","Short":"0cc034b51e57","Time":"2018-02-13T19:05:03Z"} +-- glass.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations from Frank da Cruz, Ethan Mollick, and many others. +// See http://kermitproject.org/utf8.html. +// http://www.oocities.org/nodotus/hbglass.html +// https://en.wikipedia.org/wiki/I_Can_Eat_Glass + +package sampler + +var glass = newText(` + +English: en: I can eat glass and it doesn't hurt me. +French: fr: Je peux manger du verre, ça ne me fait pas mal. +Spanish: es: Puedo comer vidrio, no me hace daño. + +`) +-- glass_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" + _ "rsc.io/testonly" +) + +var glassTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "I can eat glass and it doesn't hurt me.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Je peux manger du verre, ça ne me fait pas mal.", + }, +} + +func TestGlass(t *testing.T) { + for _, tt := range glassTests { + text := Glass(tt.prefs...) + if text != tt.text { + t.Errorf("Glass(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- go.mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations by Google Translate. + +package sampler + +var hello = newText(` + +English: en: Hello, world. +French: fr: Bonjour le monde. +Spanish: es: Hola Mundo. + +`) +-- hello_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var helloTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "Hello, world.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Bonjour le monde.", + }, +} + +func TestHello(t *testing.T) { + for _, tt := range helloTests { + text := Hello(tt.prefs...) + if text != tt.text { + t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts. +package sampler // import "rsc.io/sampler" + +import ( + "os" + "strings" + + "golang.org/x/text/language" +) + +// DefaultUserPrefs returns the default user language preferences. +// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment +// variables, in that order. +func DefaultUserPrefs() []language.Tag { + var prefs []language.Tag + for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} { + if env := os.Getenv(k); env != "" { + prefs = append(prefs, language.Make(env)) + } + } + return prefs +} + +// Hello returns a localized greeting. +// If no prefs are given, Hello uses DefaultUserPrefs. +func Hello(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return hello.find(prefs) +} + +// Glass returns a localized silly phrase. +// If no prefs are given, Glass uses DefaultUserPrefs. +func Glass(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return glass.find(prefs) +} + +// A text is a localized text. +type text struct { + byTag map[string]string + matcher language.Matcher +} + +// newText creates a new localized text, given a list of translations. +func newText(s string) *text { + t := &text{ + byTag: make(map[string]string), + } + var tags []language.Tag + for _, line := range strings.Split(s, "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + f := strings.Split(line, ": ") + if len(f) != 3 { + continue + } + tag := language.Make(f[1]) + tags = append(tags, tag) + t.byTag[tag.String()] = f[2] + } + t.matcher = language.NewMatcher(tags) + return t +} + +// find finds the text to use for the given language tag preferences. +func (t *text) find(prefs []language.Tag) string { + tag, _, _ := t.matcher.Match(prefs...) + s := t.byTag[tag.String()] + if strings.HasPrefix(s, "RTL ") { + s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E" + } + return s +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt new file mode 100644 index 0000000000..a293f10869 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.3.1.txt @@ -0,0 +1,201 @@ +rsc.io/sampler@v1.3.1 + +-- .mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- .info -- +{"Version":"v1.3.1","Name":"f545d0289d06e2add4556ea6a15fc4938014bf87","Short":"f545d0289d06","Time":"2018-02-14T16:34:12Z"} +-- glass.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations from Frank da Cruz, Ethan Mollick, and many others. +// See http://kermitproject.org/utf8.html. +// http://www.oocities.org/nodotus/hbglass.html +// https://en.wikipedia.org/wiki/I_Can_Eat_Glass + +package sampler + +var glass = newText(` + +English: en: I can eat glass and it doesn't hurt me. +French: fr: Je peux manger du verre, ça ne me fait pas mal. +Spanish: es: Puedo comer vidrio, no me hace daño. + +`) +-- glass_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var glassTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "I can eat glass and it doesn't hurt me.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Je peux manger du verre, ça ne me fait pas mal.", + }, +} + +func TestGlass(t *testing.T) { + for _, tt := range glassTests { + text := Glass(tt.prefs...) + if text != tt.text { + t.Errorf("Glass(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- go.mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations by Google Translate. + +package sampler + +var hello = newText(` + +English: en: Hello, world. +French: fr: Bonjour le monde. +Spanish: es: Hola Mundo. + +`) +-- hello_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var helloTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "Hello, world.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Bonjour le monde.", + }, +} + +func TestHello(t *testing.T) { + for _, tt := range helloTests { + text := Hello(tt.prefs...) + if text != tt.text { + t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts in a variety of languages. +package sampler // import "rsc.io/sampler" + +import ( + "os" + "strings" + + "golang.org/x/text/language" +) + +// DefaultUserPrefs returns the default user language preferences. +// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment +// variables, in that order. +func DefaultUserPrefs() []language.Tag { + var prefs []language.Tag + for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} { + if env := os.Getenv(k); env != "" { + prefs = append(prefs, language.Make(env)) + } + } + return prefs +} + +// Hello returns a localized greeting. +// If no prefs are given, Hello uses DefaultUserPrefs. +func Hello(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return hello.find(prefs) +} + +// Glass returns a localized silly phrase. +// If no prefs are given, Glass uses DefaultUserPrefs. +func Glass(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return glass.find(prefs) +} + +// A text is a localized text. +type text struct { + byTag map[string]string + matcher language.Matcher +} + +// newText creates a new localized text, given a list of translations. +func newText(s string) *text { + t := &text{ + byTag: make(map[string]string), + } + var tags []language.Tag + for _, line := range strings.Split(s, "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + f := strings.Split(line, ": ") + if len(f) != 3 { + continue + } + tag := language.Make(f[1]) + tags = append(tags, tag) + t.byTag[tag.String()] = f[2] + } + t.matcher = language.NewMatcher(tags) + return t +} + +// find finds the text to use for the given language tag preferences. +func (t *text) find(prefs []language.Tag) string { + tag, _, _ := t.matcher.Match(prefs...) + s := t.byTag[tag.String()] + if strings.HasPrefix(s, "RTL ") { + s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E" + } + return s +} diff --git a/src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt new file mode 100644 index 0000000000..5036d20ab5 --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_sampler_v1.99.99.txt @@ -0,0 +1,140 @@ +rsc.io/sampler@v1.99.99 + +-- .mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- .info -- +{"Version":"v1.99.99","Name":"732a3c400797d8835f2af34a9561f155bef85435","Short":"732a3c400797","Time":"2018-02-13T22:20:19Z"} +-- go.mod -- +module "rsc.io/sampler" + +require "golang.org/x/text" v0.0.0-20170915032832-14c0d48ead0c +-- hello.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Translations by Google Translate. + +package sampler + +var hello = newText(` + +English: en: 99 bottles of beer on the wall, 99 bottles of beer, ... + +`) +-- hello_test.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sampler + +import ( + "testing" + + "golang.org/x/text/language" +) + +var helloTests = []struct { + prefs []language.Tag + text string +}{ + { + []language.Tag{language.Make("en-US"), language.Make("fr")}, + "Hello, world.", + }, + { + []language.Tag{language.Make("fr"), language.Make("en-US")}, + "Bonjour le monde.", + }, +} + +func TestHello(t *testing.T) { + for _, tt := range helloTests { + text := Hello(tt.prefs...) + if text != tt.text { + t.Errorf("Hello(%v) = %q, want %q", tt.prefs, text, tt.text) + } + } +} +-- sampler.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package sampler shows simple texts. +package sampler // import "rsc.io/sampler" + +import ( + "os" + "strings" + + "golang.org/x/text/language" +) + +// DefaultUserPrefs returns the default user language preferences. +// It consults the $LC_ALL, $LC_MESSAGES, and $LANG environment +// variables, in that order. +func DefaultUserPrefs() []language.Tag { + var prefs []language.Tag + for _, k := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} { + if env := os.Getenv(k); env != "" { + prefs = append(prefs, language.Make(env)) + } + } + return prefs +} + +// Hello returns a localized greeting. +// If no prefs are given, Hello uses DefaultUserPrefs. +func Hello(prefs ...language.Tag) string { + if len(prefs) == 0 { + prefs = DefaultUserPrefs() + } + return hello.find(prefs) +} + +func Glass() string { + return "I can eat glass and it doesn't hurt me." +} + +// A text is a localized text. +type text struct { + byTag map[string]string + matcher language.Matcher +} + +// newText creates a new localized text, given a list of translations. +func newText(s string) *text { + t := &text{ + byTag: make(map[string]string), + } + var tags []language.Tag + for _, line := range strings.Split(s, "\n") { + line = strings.TrimSpace(line) + if line == "" { + continue + } + f := strings.Split(line, ": ") + if len(f) != 3 { + continue + } + tag := language.Make(f[1]) + tags = append(tags, tag) + t.byTag[tag.String()] = f[2] + } + t.matcher = language.NewMatcher(tags) + return t +} + +// find finds the text to use for the given language tag preferences. +func (t *text) find(prefs []language.Tag) string { + tag, _, _ := t.matcher.Match(prefs...) + s := t.byTag[tag.String()] + if strings.HasPrefix(s, "RTL ") { + s = "\u200F" + strings.TrimPrefix(s, "RTL ") + "\u200E" + } + return s +} diff --git a/src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt b/src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt new file mode 100644 index 0000000000..dfb8ca24ec --- /dev/null +++ b/src/cmd/go/testdata/mod/rsc.io_testonly_v1.0.0.txt @@ -0,0 +1,9 @@ +rsc.io/testonly v1.0.0 +written by hand + +-- .mod -- +module rsc.io/testonly +-- .info -- +{"Version":"v1.0.0"} +-- testonly.go -- +package testonly diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go new file mode 100644 index 0000000000..48a6318860 --- /dev/null +++ b/src/cmd/go/testdata/savedir.go @@ -0,0 +1,79 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Savedir archives a directory tree as a txtar archive printed to standard output. +// +// Usage: +// +// go run savedir.go /path/to/dir >saved.txt +// +// Typically the tree is later extracted during a test with tg.extract("testdata/saved.txt"). +// +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "path/filepath" + "strings" + "unicode/utf8" + + "../internal/txtar" +) + +func usage() { + fmt.Fprintf(os.Stderr, "usage: go run savedir.go dir >saved.txt\n") + os.Exit(2) +} + +const goCmd = "vgo" + +func main() { + flag.Usage = usage + flag.Parse() + if flag.NArg() != 1 { + usage() + } + + log.SetPrefix("savedir: ") + log.SetFlags(0) + + dir := flag.Arg(0) + + a := new(txtar.Archive) + dir = filepath.Clean(dir) + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if path == dir { + return nil + } + name := info.Name() + if strings.HasPrefix(name, ".") { + if info.IsDir() { + return filepath.SkipDir + } + return nil + } + if !info.Mode().IsRegular() { + return nil + } + data, err := ioutil.ReadFile(path) + if err != nil { + log.Fatal(err) + } + if !utf8.Valid(data) { + log.Printf("%s: ignoring invalid UTF-8 data", path) + return nil + } + a.Files = append(a.Files, txtar.File{Name: strings.TrimPrefix(path, dir+string(filepath.Separator)), Data: data}) + return nil + }) + + data := txtar.Format(a) + os.Stdout.Write(data) +} diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README new file mode 100644 index 0000000000..a80233b8c3 --- /dev/null +++ b/src/cmd/go/testdata/script/README @@ -0,0 +1,261 @@ +This directory holds test scripts *.txt run during 'go test cmd/go'. +To run a specific script foo.txt + + go test cmd/go -run=Script/^foo$ + +In general script files should have short names: a few words, not whole sentences. +The first word should be the general category of behavior being tested, +often the name of a go subcommand (list, build, test, ...) or concept (vendor, pattern). + +Each script is a text archive (go doc cmd/go/internal/txtar). +The script begins with an actual command script to run +followed by the content of zero or more supporting files to +create in the script's temporary file system before it starts executing. + +As an example, run_hello.txt says: + + # hello world + go run hello.go + stderr 'hello world' + ! stdout . + + -- hello.go -- + package main + func main() { println("hello world") } + +Each script runs in a fresh temporary work directory tree, available to scripts as $WORK. +Scripts also have access to these other environment variables: + + GOARCH= + GOCACHE= + GOOS= + GOPATH=$WORK/gopath + GOPROXY= + GOROOT= + HOME=/no-home + PATH= + TMPDIR=$WORK/tmp + devnull= + +The environment variable $exe (lowercase) is an empty string on most systems, ".exe" on Windows. + +The scripts supporting files are unpacked relative to $GOPATH/src (aka $WORK/gopath/src) +and then the script begins execution in that directory as well. Thus the example above runs +in $WORK/gopath/src with GOPATH=$WORK/gopath and $WORK/gopath/src/hello.go +containing the listed contents. + +The lines at the top of the script are a sequence of commands to be executed +by a tiny script engine in ../../script_test.go (not the system shell). +The script stops and the overall test fails if any particular command fails. + +Each line is parsed into a sequence of space-separated command words, +with environment variable expansion and # marking an end-of-line comment. +Adding single quotes around text keeps spaces in that text from being treated +as word separators and also disables environment variable expansion. +Inside a single-quoted block of text, a repeated single quote indicates +a literal single quote, as in: + + 'Don''t communicate by sharing memory.' + +A line beginning with # is a comment and conventionally explains what is +being done or tested at the start of a new phase in the script. + +The command prefix ! indicates that the command on the rest of the line +(typically go or a matching predicate) must fail, not succeed. Only certain +commands support this prefix. They are indicated below by [!] in the synopsis. + +The command prefix [cond] indicates that the command on the rest of the line +should only run when the condition is satisfied. The available conditions are: + + - GOOS and GOARCH values, like [386], [windows], and so on. + - Compiler names, like [gccgo], [gc]. + - Test environment details: + - [short] for testing.Short() + - [cgo], [msan], [race] for whether cgo, msan, and the race detector can be used + - [net] for whether the external network can be used + - [link] for testenv.HasLink() + - [symlink] for testenv.HasSymlink() + - [exec:prog] for whether prog is available for execution (found by exec.LookPath) + +A condition can be negated: [!short] means to run the rest of the line +when testing.Short() is false. + +The commands are: + +- cd dir + Change to the given directory for future commands. + +- cmp file1 file2 + Check that the named files have the same content. + By convention, file1 is the actual data and file2 the expected data. + File1 can be "stdout" or "stderr" to use the standard output or standard error + from the most recent exec or go command. + (If the files have differing content, the failure prints a diff.) + +- cp src... dst + Copy the listed files to the target file or existing directory. + +- env [key=value...] + With no arguments, print the environment (useful for debugging). + Otherwise add the listed key=value pairs to the environment. + +- [!] exec program [args...] + Run the given executable program with the arguments. + It must (or must not) succeed. + Note that 'exec' does not terminate the script (unlike in Unix shells). + +- [!] exists [-readonly] file... + Each of the listed files or directories must (or must not) exist. + If -readonly is given, the files or directories must be unwritable. + +- [!] go args... + Run the (test copy of the) go command with the given arguments. + It must (or must not) succeed. + +- [!] grep [-count=N] pattern file + The file's content must (or must not) match the regular expression pattern. + For positive matches, -count=N specifies an exact number of matches to require. + +- mkdir path... + Create the listed directories, if they do not already exists. + +- rm file... + Remove the listed files or directories. + +- skip [message] + Mark the test skipped, including the message if given. + +- [!] stale path... + The packages named by the path arguments must (or must not) + be reported as "stale" by the go command. + +- [!] stderr [-count=N] pattern + Apply the grep command (see above) to the standard error + from the most recent exec or go command. + +- [!] stdout [-count=N] pattern + Apply the grep command (see above) to the standard output + from the most recent exec or go command. + +- stop [message] + Stop the test early (marking it as passing), including the message if given. + +- symlink file -> target + Create file as a symlink to target. The -> (like in ls -l output) is required. + +When TestScript runs a script and the script fails, by default TestScript shows +the execution of the most recent phase of the script (since the last # comment) +and only shows the # comments for earlier phases. For example, here is a +multi-phase script with a bug in it: + + # GOPATH with p1 in d2, p2 in d2 + env GOPATH=$WORK/d1${:}$WORK/d2 + + # build & install p1 + env + go install -i p1 + ! stale p1 + ! stale p2 + + # modify p2 - p1 should appear stale + cp $WORK/p2x.go $WORK/d2/src/p2/p2.go + stale p1 p2 + + # build & install p1 again + go install -i p11 + ! stale p1 + ! stale p2 + + -- $WORK/d1/src/p1/p1.go -- + package p1 + import "p2" + func F() { p2.F() } + -- $WORK/d2/src/p2/p2.go -- + package p2 + func F() {} + -- $WORK/p2x.go -- + package p2 + func F() {} + func G() {} + +The bug is that the final phase installs p11 instead of p1. The test failure looks like: + + $ go test -run=Script + --- FAIL: TestScript (3.75s) + --- FAIL: TestScript/install_rebuild_gopath (0.16s) + script_test.go:223: + # GOPATH with p1 in d2, p2 in d2 (0.000s) + # build & install p1 (0.087s) + # modify p2 - p1 should appear stale (0.029s) + # build & install p1 again (0.022s) + > go install -i p11 + [stderr] + can't load package: package p11: cannot find package "p11" in any of: + /Users/rsc/go/src/p11 (from $GOROOT) + $WORK/d1/src/p11 (from $GOPATH) + $WORK/d2/src/p11 + [exit status 1] + FAIL: unexpected go command failure + + script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src + + FAIL + exit status 1 + FAIL cmd/go 4.875s + $ + +Note that the commands in earlier phases have been hidden, so that the relevant +commands are more easily found, and the elapsed time for a completed phase +is shown next to the phase heading. To see the entire execution, use "go test -v", +which also adds an initial environment dump to the beginning of the log. + +Note also that in reported output, the actual name of the per-script temporary directory +has been consistently replaced with the literal string $WORK. + +The cmd/go test flag -testwork (which must appear on the "go test" command line after +standard test flags) causes each test to log the name of its $WORK directory and other +environment variable settings and also to leave that directory behind when it exits, +for manual debugging of failing tests: + + $ go test -run=Script -work + --- FAIL: TestScript (3.75s) + --- FAIL: TestScript/install_rebuild_gopath (0.16s) + script_test.go:223: + WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath + GOARCH= + GOCACHE=/Users/rsc/Library/Caches/go-build + GOOS= + GOPATH=$WORK/gopath + GOROOT=/Users/rsc/go + HOME=/no-home + TMPDIR=$WORK/tmp + exe= + + # GOPATH with p1 in d2, p2 in d2 (0.000s) + # build & install p1 (0.085s) + # modify p2 - p1 should appear stale (0.030s) + # build & install p1 again (0.019s) + > go install -i p11 + [stderr] + can't load package: package p11: cannot find package "p11" in any of: + /Users/rsc/go/src/p11 (from $GOROOT) + $WORK/d1/src/p11 (from $GOPATH) + $WORK/d2/src/p11 + [exit status 1] + FAIL: unexpected go command failure + + script_test.go:73: failed at testdata/script/install_rebuild_gopath.txt:15 in $WORK/gopath/src + + FAIL + exit status 1 + FAIL cmd/go 4.875s + $ + + $ WORK=/tmp/cmd-go-test-745953508/script-install_rebuild_gopath + $ cd $WORK/d1/src/p1 + $ cat p1.go + package p1 + import "p2" + func F() { p2.F() } + $ + diff --git a/src/cmd/go/testdata/script/binary_only.txt b/src/cmd/go/testdata/script/binary_only.txt new file mode 100644 index 0000000000..397904efaa --- /dev/null +++ b/src/cmd/go/testdata/script/binary_only.txt @@ -0,0 +1,10 @@ +# check that error for missing binary-only says where it should be +! go build b +stderr pkg[\\/].*a\.a + +-- a/a.go -- +//go:binary-only-package + +package a +-- b/b.go -- +package b; import "a" diff --git a/src/cmd/go/testdata/script/build_GOTMPDIR.txt b/src/cmd/go/testdata/script/build_GOTMPDIR.txt new file mode 100644 index 0000000000..4c387afbba --- /dev/null +++ b/src/cmd/go/testdata/script/build_GOTMPDIR.txt @@ -0,0 +1,11 @@ +# Build should use GOTMPDIR if set. +env GOTMPDIR=$WORK/my-favorite-tmpdir +env GOCACHE=off +mkdir $GOTMPDIR +go build -work hello.go +stderr ^WORK=.*my-favorite-tmpdir + +-- hello.go -- +package main +func main() { println("hello") } + diff --git a/src/cmd/go/testdata/script/build_cache_compile.txt b/src/cmd/go/testdata/script/build_cache_compile.txt new file mode 100644 index 0000000000..7db881a268 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_compile.txt @@ -0,0 +1,18 @@ +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building trivial non-main package should run compiler the first time. +go build -x lib.go +stderr '(compile|gccgo)( |\.exe).*lib\.go' + +# ... but not again ... +go build -x lib.go +! stderr '(compile|gccgo)( |\.exe).*lib\.go' + +# ... unless we use -a. +go build -a -x lib.go +stderr '(compile|gccgo)( |\.exe)' + +-- lib.go -- +package lib diff --git a/src/cmd/go/testdata/script/build_cache_gomips.txt b/src/cmd/go/testdata/script/build_cache_gomips.txt new file mode 100644 index 0000000000..c77acc3f2f --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_gomips.txt @@ -0,0 +1,37 @@ +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building for mipsle without setting GOMIPS will use floating point registers. +env GOARCH=mipsle +env GOOS=linux +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Building with GOMIPS=softfloat will not use floating point registers +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Clean cache +go clean -cache + +# Build without setting GOMIPS +env GOMIPS= +go build -gcflags=-S f.go +stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +# Building with GOMIPS should still not use floating point registers. +env GOMIPS=softfloat +go build -gcflags=-S f.go +! stderr ADDD.F[0-9]+,.F[0-9]+,.F[0-9]+ + +-- f.go -- +package f + +func F(x float64) float64 { + return x + x +} diff --git a/src/cmd/go/testdata/script/build_cache_link.txt b/src/cmd/go/testdata/script/build_cache_link.txt new file mode 100644 index 0000000000..61e7ee46d3 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_link.txt @@ -0,0 +1,23 @@ +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building a main package should run the compiler and linker ... +go build -o $devnull -x main.go +stderr '(compile|gccgo)( |\.exe).*main\.go' +stderr '(link|gccgo)( |\.exe)' + +# ... and then the linker again ... +go build -o $devnull -x main.go +! stderr '(compile|gccgo)( |\.exe).*main\.go' +stderr '(link|gccgo)( |\.exe)' + +# ... but the output binary can serve as a cache. +go build -o main$exe -x main.go +stderr '(link|gccgo)( |\.exe)' +go build -o main$exe -x main.go +! stderr '(link|gccgo)( |\.exe)' + +-- main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/build_cache_output.txt b/src/cmd/go/testdata/script/build_cache_output.txt new file mode 100644 index 0000000000..ee4099e5f3 --- /dev/null +++ b/src/cmd/go/testdata/script/build_cache_output.txt @@ -0,0 +1,63 @@ +[!gc] skip + +# Set up fresh GOCACHE. +env GOCACHE=$WORK/gocache +mkdir $GOCACHE + +# Building a trivial non-main package should run compiler the first time. +go build -x -gcflags=-m lib.go +stderr 'compile( |\.exe"?)' +stderr 'lib.go:2.* can inline f' + +# ... but not the second, even though it still prints the compiler output. +go build -x -gcflags=-m lib.go +! stderr 'compile( |\.exe"?)' +stderr 'lib.go:2.* can inline f' + +# Building a trivial main package should run the compiler and linker the first time. +go build -x -gcflags=-m -ldflags='-v -w' main.go +stderr 'compile( |\.exe"?)' +stderr 'main.go:2.* can inline main' # from compiler +stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker + +# ... but not the second, even though it still prints the compiler and linker output. +go build -x -gcflags=-m -ldflags='-v -w' main.go +! stderr 'compile( |\.exe"?)' +stderr 'main.go:2.* can inline main' # from compiler +! stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker + +# Running a test should run the compiler, linker, and the test the first time. +go test -v -x -gcflags=-m -ldflags=-v p_test.go +stderr 'compile( |\.exe"?)' +stderr 'p_test.go:.*can inline Test' # from compile of p_test +stderr 'testmain\.go:.*inlin' # from compile of testmain +stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker +stderr 'p\.test( |\.exe"?)' +stdout 'TEST' # from test + +# ... but not the second, even though it still prints the compiler, linker, and test output. +go test -v -x -gcflags=-m -ldflags=-v p_test.go +! stderr 'compile( |\.exe"?)' +stderr 'p_test.go:.*can inline Test' # from compile of p_test +stderr 'testmain\.go:.*inlin' # from compile of testmain +! stderr 'link(\.exe"?)? -' +stderr '\d+ symbols' # from linker +! stderr 'p\.test( |\.exe"?)' +stdout 'TEST' # from test + + +-- lib.go -- +package p +func f(x *int) *int { return x } + +-- main.go -- +package main +func main() {} + +-- p_test.go -- +package p +import "testing" +func Test(t *testing.T) {println("TEST")} diff --git a/src/cmd/go/testdata/script/cover_atomic_pkgall.txt b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt new file mode 100644 index 0000000000..c122c05cb6 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_atomic_pkgall.txt @@ -0,0 +1,23 @@ +[short] skip + +go test -coverpkg=all -covermode=atomic x +stdout ok[\s\S]+?coverage + +[!race] stop + +go test -coverpkg=all -race x +stdout ok[\s\S]+?coverage + +-- x/x.go -- +package x + +import _ "sync/atomic" + +func F() {} + +-- x/x_test.go -- +package x + +import "testing" + +func TestF(t *testing.T) { F() } diff --git a/src/cmd/go/testdata/script/cover_pkgall_runtime.txt b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt new file mode 100644 index 0000000000..5d169d6312 --- /dev/null +++ b/src/cmd/go/testdata/script/cover_pkgall_runtime.txt @@ -0,0 +1,21 @@ +# Issue 23882 + +[short] skip + +go test -coverpkg=all x +stdout ok[\s\S]+?coverage + +[!race] stop + +go test -coverpkg=all -race x +stdout ok[\s\S]+?coverage + +-- x/x.go -- +package x +import _ "runtime" +func F() {} + +-- x/x_test.go -- +package x +import "testing" +func TestF(t *testing.T) { F() } diff --git a/src/cmd/go/testdata/script/cpu_profile_twice.txt b/src/cmd/go/testdata/script/cpu_profile_twice.txt new file mode 100644 index 0000000000..142d5ee718 --- /dev/null +++ b/src/cmd/go/testdata/script/cpu_profile_twice.txt @@ -0,0 +1,20 @@ +# Issue 23150 + +[short] skip + +go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x +rm $WORK/cpu_profile_twice.out + +go test -o=$WORK/x.test -cpuprofile=$WORK/cpu_profile_twice.out x +exists $WORK/cpu_profile_twice.out + + +-- x/x_test.go -- +package x_test +import ( + "testing" + "time" +) +func TestSleep(t *testing.T) { + time.Sleep(10 * time.Millisecond) +} diff --git a/src/cmd/go/testdata/script/fileline.txt b/src/cmd/go/testdata/script/fileline.txt new file mode 100644 index 0000000000..cdc3be2df8 --- /dev/null +++ b/src/cmd/go/testdata/script/fileline.txt @@ -0,0 +1,6 @@ +# look for short, relative file:line in error message +! go run ../../gopath/x/y/z/err.go +stderr ^..[\\/]x[\\/]y[\\/]z[\\/]err.go: + +-- ../x/y/z/err.go -- +package main; import "bar" diff --git a/src/cmd/go/testdata/script/gcflags_patterns.txt b/src/cmd/go/testdata/script/gcflags_patterns.txt new file mode 100644 index 0000000000..fe2cf6f0fb --- /dev/null +++ b/src/cmd/go/testdata/script/gcflags_patterns.txt @@ -0,0 +1,71 @@ +[!gc] skip 'using -gcflags and -ldflags' + +# -gcflags=-e applies to named packages, not dependencies +go build -n -v -gcflags=-e z1 z2 +stderr 'compile.* -e .*-p z1' +stderr 'compile.* -e .*-p z2' +stderr 'compile.* -p y' +! stderr 'compile.* -e .*-p [^z]' + +# -gcflags can specify package=flags, and can be repeated; last match wins +go build -n -v -gcflags=-e -gcflags=z1=-N z1 z2 +stderr 'compile.* -N .*-p z1' +! stderr 'compile.* -e .*-p z1' +! stderr 'compile.* -N .*-p z2' +stderr 'compile.* -e .*-p z2' +stderr 'compile.* -p y' +! stderr 'compile.* -e .*-p [^z]' +! stderr 'compile.* -N .*-p [^z]' + +# -gcflags can have arbitrary spaces around the flags +go build -n -v -gcflags=' z1 = -e ' z1 +stderr 'compile.* -e .*-p z1' + +# -ldflags for implicit test package applies to test binary +go test -c -n -gcflags=-N -ldflags=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags for explicit test package applies to test binary +go test -c -n -gcflags=z1=-N -ldflags=z1=-X=x.y=z z1 +stderr 'compile.* -N .*z_test.go' +stderr 'link.* -X=x.y=z' + +# -ldflags applies to link of command +go build -n -ldflags=-X=math.pi=3 my/cmd/prog +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to link of command even with strange directory name +go build -n -ldflags=-X=math.pi=3 my/cmd/prog/ +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory +cd my/cmd/prog +go build -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +# -ldflags applies to current directory even if GOPATH is funny +[windows] cd $WORK/GoPath/src/my/cmd/prog +[darwin] cd $WORK/GoPath/src/my/cmd/prog +go build -n -ldflags=-X=math.pi=3 +stderr 'link.* -X=math.pi=3' + +-- z1/z.go -- +package z1 +import _ "y" +import _ "z2" + +-- z1/z_test.go -- +package z1_test +import "testing" +func Test(t *testing.T) {} + +-- z2/z.go -- +package z2 + +-- y/y.go -- +package y + +-- my/cmd/prog/prog.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/get_with_git_trace.txt b/src/cmd/go/testdata/script/get_with_git_trace.txt new file mode 100644 index 0000000000..93341a302c --- /dev/null +++ b/src/cmd/go/testdata/script/get_with_git_trace.txt @@ -0,0 +1,7 @@ +env GIT_TRACE=1 + +[!net] skip +[!exec:git] skip + +# go get should be success when GIT_TRACE set +go get golang.org/x/text diff --git a/src/cmd/go/testdata/script/goflags.txt b/src/cmd/go/testdata/script/goflags.txt new file mode 100644 index 0000000000..20de325ac2 --- /dev/null +++ b/src/cmd/go/testdata/script/goflags.txt @@ -0,0 +1,49 @@ +# GOFLAGS sets flags for commands + +env GOFLAGS='-e -f={{.Dir}} --test.benchtime=1s -count=10' +go list asdfasdfasdf # succeeds because of -e +go list runtime +stdout '[\\/]runtime$' + +env GOFLAGS=-race OLDGOARCH=$GOARCH OLDGOOS=$GOOS GOARCH=386 GOOS=linux +! go list runtime +stderr 'race is only supported on' + +env GOARCH=$OLDGOARCH GOOS=$OLDGOOS + +# go env succeeds even though -f={{.Dir}} is inappropriate +go env + +# bad flags are diagnosed +env GOFLAGS=-typoflag +! go list runtime +stderr 'unknown flag -typoflag' + +env GOFLAGS=- +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "-"' + +env GOFLAGS=-- +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "--"' + +env GOFLAGS=---oops +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "---oops"' + +env GOFLAGS=-=noname +! go list runtime +stderr '^go: parsing \$GOFLAGS: non-flag "-=noname"' + +env GOFLAGS=-f +! go list runtime +stderr '^go: flag needs an argument: -f \(from (\$GOFLAGS|%GOFLAGS%)\)$' + +env GOFLAGS=-e=asdf +! go list runtime +stderr '^go: invalid boolean value \"asdf\" for flag -e \(from (\$GOFLAGS|%GOFLAGS%)\)' + +# except in go bug (untested) and go env +go env +stdout GOFLAGS + diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt new file mode 100644 index 0000000000..939da30283 --- /dev/null +++ b/src/cmd/go/testdata/script/help.txt @@ -0,0 +1,36 @@ +# go help shows overview. +go help +stdout 'Go is a tool' +stdout 'bug.*start a bug report' + +# go help bug shows usage for bug +go help bug +stdout 'usage: go bug' +stdout 'bug report' + +# go bug help is an error (bug takes no arguments) +! go bug help +stderr 'bug takes no arguments' + +# go help mod shows mod subcommands +go help mod +stdout 'go mod ' +stdout tidy + +# go help mod tidy explains tidy +go help mod tidy +stdout 'usage: go mod tidy' + +# go mod help tidy does too +go mod help tidy +stdout 'usage: go mod tidy' + +# go mod --help doesn't print help but at least suggests it. +! go mod --help +stderr 'Run ''go help mod'' for usage.' + +# Earlier versions of Go printed the same as 'go -h' here. +# Also make sure we print the short help line. +! go vet -h +stderr 'usage: go vet' +stderr 'Run ''go help vet'' for details' diff --git a/src/cmd/go/testdata/script/install_cleans_build.txt b/src/cmd/go/testdata/script/install_cleans_build.txt new file mode 100644 index 0000000000..b8d322de62 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cleans_build.txt @@ -0,0 +1,22 @@ +# 'go install' with no arguments should clean up after go build +cd mycmd +go build +exists mycmd$exe +go install +! exists mycmd$exe + +# 'go install mycmd' does not clean up, even in the mycmd directory +go build +exists mycmd$exe +go install mycmd +exists mycmd$exe + +# 'go install mycmd' should not clean up in an unrelated current directory either +cd .. +cp mycmd/mycmd$exe mycmd$exe +go install mycmd +exists mycmd$exe + +-- mycmd/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_cross_gobin.txt b/src/cmd/go/testdata/script/install_cross_gobin.txt new file mode 100644 index 0000000000..587081f135 --- /dev/null +++ b/src/cmd/go/testdata/script/install_cross_gobin.txt @@ -0,0 +1,23 @@ +cd mycmd +go build mycmd + +# cross-compile install with implicit GOBIN=$GOPATH/bin can make subdirectory +env GOARCH=386 +[386] env GOARCH=amd64 +env GOOS=linux +go install mycmd +exists $GOPATH/bin/linux_$GOARCH/mycmd + +# cross-compile install with explicit GOBIN cannot make subdirectory +env GOBIN=$WORK/bin +! go install mycmd +! exists $GOBIN/linux_$GOARCH + +# installing standard command should still work +# (should also be mtime update only if cmd/pack is up-to-date). +! stale cmd/pack +[!short] go install cmd/pack + +-- mycmd/x.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/install_rebuild_gopath.txt b/src/cmd/go/testdata/script/install_rebuild_gopath.txt new file mode 100644 index 0000000000..d42b07004b --- /dev/null +++ b/src/cmd/go/testdata/script/install_rebuild_gopath.txt @@ -0,0 +1,28 @@ +# GOPATH with p1 in d1, p2 in d2 +env GOPATH=$WORK/d1${:}$WORK/d2 + +# build & install p1 +go install -i p1 +! stale p1 p2 + +# modify p2 - p1 should appear stale +cp $WORK/p2x.go $WORK/d2/src/p2/p2.go +stale p1 p2 + +# build & install p1 again +go install -i p1 +! stale p1 p2 + +-- $WORK/d1/src/p1/p1.go -- +package p1 +import "p2" +func F() { p2.F() } + +-- $WORK/d2/src/p2/p2.go -- +package p2 +func F() {} + +-- $WORK/p2x.go -- +package p2 +func F() {} +func G() {} diff --git a/src/cmd/go/testdata/script/install_rebuild_removed.txt b/src/cmd/go/testdata/script/install_rebuild_removed.txt new file mode 100644 index 0000000000..e7620a08ca --- /dev/null +++ b/src/cmd/go/testdata/script/install_rebuild_removed.txt @@ -0,0 +1,42 @@ +# go command should detect package staleness as source file set changes +go install mypkg +! stale mypkg + +# z.go was not compiled; removing it should NOT make mypkg stale +rm mypkg/z.go +! stale mypkg + +# y.go was compiled; removing it should make mypkg stale +rm mypkg/y.go +stale mypkg + +# go command should detect executable staleness too +go install mycmd +! stale mycmd +rm mycmd/z.go +! stale mycmd +rm mycmd/y.go +stale mycmd + +-- mypkg/x.go -- +package mypkg + +-- mypkg/y.go -- +package mypkg + +-- mypkg/z.go -- +// +build missingtag + +package mypkg + +-- mycmd/x.go -- +package main +func main() {} + +-- mycmd/y.go -- +package main + +-- mycmd/z.go -- +// +build missingtag + +package main diff --git a/src/cmd/go/testdata/script/linkname.txt b/src/cmd/go/testdata/script/linkname.txt new file mode 100644 index 0000000000..e2ec00c6ed --- /dev/null +++ b/src/cmd/go/testdata/script/linkname.txt @@ -0,0 +1,7 @@ +# check for linker name in error message about linker crash +[!gc] skip +! go build -ldflags=-crash_for_testing x.go +stderr [\\/]tool[\\/].*[\\/]link + +-- x.go -- +package main; func main() {} diff --git a/src/cmd/go/testdata/script/list_bad_import.txt b/src/cmd/go/testdata/script/list_bad_import.txt new file mode 100644 index 0000000000..ba66b0937f --- /dev/null +++ b/src/cmd/go/testdata/script/list_bad_import.txt @@ -0,0 +1,67 @@ +# This test matches mod_list_bad_import, but in GOPATH mode. +# Please keep them in sync. + +env GO111MODULE=off +cd example.com + +# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail. +# BUG: Today it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct +! stdout ^error +stdout 'incomplete' +stdout 'bad dep: .*example.com[/\\]notfound' + +# Listing with -deps should also fail. +# BUG: Today, it does not. +# ! go list -deps example.com/direct +# stderr example.com[/\\]notfound +go list -deps example.com/direct +stdout example.com/notfound + + +# Listing an otherwise-valid package that imports some *other* package with an +# unsatisfied import should also fail. +# BUG: Today, it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect +! stdout ^error +stdout incomplete +stdout 'bad dep: .*example.com[/\\]notfound' + +# Again, -deps should fail. +# BUG: Again, it does not. +# ! go list -deps example.com/indirect +# stderr example.com[/\\]notfound +go list -deps example.com/indirect +stdout example.com/notfound + + +# Listing the missing dependency directly should fail outright... +! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stderr 'no Go files in .*example.com[/\\]notfound' +! stdout error +! stdout incomplete + +# ...but listing with -e should succeed. +go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stdout error +stdout incomplete + + +# The pattern "all" should match only packages that acutally exist, +# ignoring those whose existence is merely implied by imports. +go list -e -f '{{.ImportPath}}' all +stdout example.com/direct +stdout example.com/indirect +! stdout example.com/notfound + + +-- example.com/direct/direct.go -- +package direct +import _ "example.com/notfound" + +-- example.com/indirect/indirect.go -- +package indirect +import _ "example.com/direct" + +-- example.com/notfound/README -- +This directory intentionally left blank. diff --git a/src/cmd/go/testdata/script/list_compiled_imports.txt b/src/cmd/go/testdata/script/list_compiled_imports.txt new file mode 100644 index 0000000000..e6f5abb6af --- /dev/null +++ b/src/cmd/go/testdata/script/list_compiled_imports.txt @@ -0,0 +1,29 @@ +[!cgo] skip + +# go list should report import "C" +cd x +go list -f '{{.Imports}}' +! stdout runtime/cgo +! stdout unsafe +! stdout syscall +stdout C +stdout unicode +stdout unicode/utf16 + +# go list -compiled should report imports in compiled files as well, +# adding "runtime/cgo", "unsafe", and "syscall" but not dropping "C". +go list -compiled -f '{{.Imports}}' +stdout runtime/cgo +stdout unsafe +stdout syscall +stdout C +stdout unicode +stdout unicode/utf16 + +-- x/x.go -- +package x +import "C" +import "unicode" // does not use unsafe, syscall, runtime/cgo, unicode/utf16 +-- x/x1.go -- +package x +import "unicode/utf16" // does not use unsafe, syscall, runtime/cgo, unicode diff --git a/src/cmd/go/testdata/script/list_find.txt b/src/cmd/go/testdata/script/list_find.txt new file mode 100644 index 0000000000..dbe8fb0ac9 --- /dev/null +++ b/src/cmd/go/testdata/script/list_find.txt @@ -0,0 +1,10 @@ +# go list -find should not report imports + +go list -f {{.Incomplete}} x/y/z... # should probably exit non-zero but never has +stdout true +go list -find -f '{{.Incomplete}} {{.Imports}}' x/y/z... +stdout '^false \[\]' + +-- x/y/z/z.go -- +package z +import "does/not/exist" diff --git a/src/cmd/go/testdata/script/list_std.txt b/src/cmd/go/testdata/script/list_std.txt new file mode 100644 index 0000000000..a63d74db12 --- /dev/null +++ b/src/cmd/go/testdata/script/list_std.txt @@ -0,0 +1,12 @@ +[!gc] skip + +# listing GOROOT should only find standard packages +cd $GOROOT/src +go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... +! stdout . +# TODO: ignore _/blah/go/src in output + +# our vendored packages should be reported as standard +go list std cmd +stdout golang_org/x/net/http2/hpack +stdout cmd/vendor/golang\.org/x/arch/x86/x86asm diff --git a/src/cmd/go/testdata/script/list_tags.txt b/src/cmd/go/testdata/script/list_tags.txt new file mode 100644 index 0000000000..c5dc99e9fb --- /dev/null +++ b/src/cmd/go/testdata/script/list_tags.txt @@ -0,0 +1,8 @@ +# go list supports -tags +go list -tags=thetag ./my... +stdout mypkg + +-- mypkg/x.go -- +// +build thetag + +package mypkg diff --git a/src/cmd/go/testdata/script/list_test_e.txt b/src/cmd/go/testdata/script/list_test_e.txt new file mode 100644 index 0000000000..f1473322c6 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_e.txt @@ -0,0 +1,9 @@ +# issue 25980: crash in go list -e -test +go list -e -test -f '{{.Error}}' p +stdout '^p[/\\]d_test.go:2:8: cannot find package "d" in any of:' + +-- p/d.go -- +package d +-- p/d_test.go -- +package d_test +import _ "d" diff --git a/src/cmd/go/testdata/script/list_test_imports.txt b/src/cmd/go/testdata/script/list_test_imports.txt new file mode 100644 index 0000000000..51d1ce9a69 --- /dev/null +++ b/src/cmd/go/testdata/script/list_test_imports.txt @@ -0,0 +1,19 @@ +# issue 26880: list with tests has wrong variant in imports +go list -test -f '{{.ImportPath}}:{{with .Imports}} {{join . ", "}}{{end}}' a b +cmp stdout imports.txt + +-- a/a.go -- +package a; import _ "b" +-- b/b.go -- +package b +-- b/b_test.go -- +package b +-- b/b_x_test.go -- +package b_test; import _ "a" + +-- imports.txt -- +a: b +b: +b.test: b [b.test], b_test [b.test], os, testing, testing/internal/testdeps +b [b.test]: +b_test [b.test]: a [b.test] diff --git a/src/cmd/go/testdata/script/mod_bad_domain.txt b/src/cmd/go/testdata/script/mod_bad_domain.txt new file mode 100644 index 0000000000..c9fd044cdc --- /dev/null +++ b/src/cmd/go/testdata/script/mod_bad_domain.txt @@ -0,0 +1,29 @@ +env GO111MODULE=on + +# explicit get should report errors about bad names +! go get appengine +stderr 'malformed module path "appengine": missing dot in first path element' +! go get x/y.z +stderr 'malformed module path "x/y.z": missing dot in first path element' + +# build should report all unsatisfied imports, +# but should be more definitive about non-module import paths +! go build ./useappengine +stderr 'cannot find package' +! go build ./usenonexistent +stderr 'cannot find module providing package nonexistent.rsc.io' + +# go mod vendor and go mod tidy should ignore appengine imports. +rm usenonexistent/x.go +go mod tidy +go mod vendor + +-- go.mod -- +module x + +-- useappengine/x.go -- +package useappengine +import _ "appengine" // package does not exist +-- usenonexistent/x.go -- +package usenonexistent +import _ "nonexistent.rsc.io" // domain does not exist diff --git a/src/cmd/go/testdata/script/mod_bad_filenames.txt b/src/cmd/go/testdata/script/mod_bad_filenames.txt new file mode 100644 index 0000000000..6e0c8bd302 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_bad_filenames.txt @@ -0,0 +1,11 @@ +env GO111MODULE=on + +! go get rsc.io/badfile1 rsc.io/badfile2 rsc.io/badfile3 rsc.io/badfile4 rsc.io/badfile5 +! stderr 'unzip.*badfile1' +stderr 'unzip.*badfile2[\\/]@v[\\/]v1.0.0.zip:.*malformed file path "☺.go": invalid char ''☺''' +stderr 'unzip.*badfile3[\\/]@v[\\/]v1.0.0.zip: malformed file path "x\?y.go": invalid char ''\?''' +stderr 'unzip.*badfile4[\\/]@v[\\/]v1.0.0.zip: case-insensitive file name collision: "x/Y.go" and "x/y.go"' +stderr 'unzip.*badfile5[\\/]@v[\\/]v1.0.0.zip: case-insensitive file name collision: "x/y" and "x/Y"' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_build_tags.txt b/src/cmd/go/testdata/script/mod_build_tags.txt new file mode 100644 index 0000000000..1347eaacbf --- /dev/null +++ b/src/cmd/go/testdata/script/mod_build_tags.txt @@ -0,0 +1,30 @@ +# Test that build tags are used. +# golang.org/issue/24053. + +env GO111MODULE=on + +cd x +! go list -f {{.GoFiles}} +stderr 'build constraints exclude all Go files' + +go list -f {{.GoFiles}} -tags tag1 +stdout '\[x.go\]' + +go list -f {{.GoFiles}} -tags tag2 +stdout '\[y\.go\]' + +go list -f {{.GoFiles}} -tags 'tag1 tag2' +stdout '\[x\.go y\.go\]' + +-- x/go.mod -- +module x + +-- x/x.go -- +// +build tag1 + +package y + +-- x/y.go -- +// +build tag2 + +package y diff --git a/src/cmd/go/testdata/script/mod_case.txt b/src/cmd/go/testdata/script/mod_case.txt new file mode 100644 index 0000000000..ee818c2c07 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case.txt @@ -0,0 +1,20 @@ +env GO111MODULE=on + +go get rsc.io/QUOTE +go list -m all +stdout '^rsc.io/quote v1.5.2' +stdout '^rsc.io/QUOTE v1.5.2' + +go list -f 'DIR {{.Dir}} DEPS {{.Deps}}' rsc.io/QUOTE/QUOTE +stdout 'DEPS.*rsc.io/quote' +stdout 'DIR.*!q!u!o!t!e' + +go get rsc.io/QUOTE@v1.5.3-PRE +go list -m all +stdout '^rsc.io/QUOTE v1.5.3-PRE' + +go list -f '{{.Dir}}' rsc.io/QUOTE/QUOTE +stdout '!q!u!o!t!e@v1.5.3-!p!r!e' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_case_cgo.txt b/src/cmd/go/testdata/script/mod_case_cgo.txt new file mode 100644 index 0000000000..917bce92d8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_case_cgo.txt @@ -0,0 +1,9 @@ +[!cgo] skip + +env GO111MODULE=on + +go get rsc.io/CGO +go build rsc.io/CGO + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_convert_dep.txt b/src/cmd/go/testdata/script/mod_convert_dep.txt new file mode 100644 index 0000000000..cc1083bcba --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_dep.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/Gopkg.lock -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_git.txt b/src/cmd/go/testdata/script/mod_convert_git.txt new file mode 100644 index 0000000000..5ef534a8f8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_git.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +# detect root of module tree as root of enclosing git repo +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/.git/config -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_glide.txt b/src/cmd/go/testdata/script/mod_convert_glide.txt new file mode 100644 index 0000000000..50460bbf36 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_glide.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/glide.lock -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_glockfile.txt b/src/cmd/go/testdata/script/mod_convert_glockfile.txt new file mode 100644 index 0000000000..4d9aaffab5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_glockfile.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/GLOCKFILE -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_godeps.txt b/src/cmd/go/testdata/script/mod_convert_godeps.txt new file mode 100644 index 0000000000..61fbab1124 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_godeps.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/Godeps/Godeps.json -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_tsv.txt b/src/cmd/go/testdata/script/mod_convert_tsv.txt new file mode 100644 index 0000000000..5b82d85d65 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_tsv.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/dependencies.tsv -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt b/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt new file mode 100644 index 0000000000..b45d3b69fe --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_conf.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/vendor.conf -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_json.txt b/src/cmd/go/testdata/script/mod_convert_vendor_json.txt new file mode 100644 index 0000000000..cb6e5fee15 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_json.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/vendor/vendor.json -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt b/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt new file mode 100644 index 0000000000..bcf185136b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_manifest.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/vendor/manifest -- +{} +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt b/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt new file mode 100644 index 0000000000..0cd245bace --- /dev/null +++ b/src/cmd/go/testdata/script/mod_convert_vendor_yml.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +cd $WORK/test/x +go list -m all +stdout '^m$' + +-- $WORK/test/vendor.yml -- +-- $WORK/test/x/x.go -- +package x // import "m/x" diff --git a/src/cmd/go/testdata/script/mod_doc.txt b/src/cmd/go/testdata/script/mod_doc.txt new file mode 100644 index 0000000000..223283d5f2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_doc.txt @@ -0,0 +1,34 @@ +# go doc should find module documentation + +env GO111MODULE=on + +go doc y +stdout 'Package y is.*alphabet' +stdout 'import "x/y"' +go doc x/y +stdout 'Package y is.*alphabet' +! go doc quote.Hello +stderr 'doc: symbol quote is not a type' # because quote is not in local cache +go list rsc.io/quote # now it is +go doc quote.Hello +stdout 'Hello returns a greeting' +go doc quote +stdout 'Package quote collects pithy sayings.' + +# Double-check go doc y when y is not in GOPATH/src. +env GOPATH=$WORK/altgopath +go doc x/y +stdout 'Package y is.*alphabet' +go doc y +stdout 'Package y is.*alphabet' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- y/y.go -- +// Package y is the next to last package of the alphabet. +package y + +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_domain_root.txt b/src/cmd/go/testdata/script/mod_domain_root.txt new file mode 100644 index 0000000000..e34cc29fa6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_domain_root.txt @@ -0,0 +1,12 @@ +# Module paths that are domain roots should resolve. +# (example.com not example.com/something) + +env GO111MODULE=on +go build + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "example.com" diff --git a/src/cmd/go/testdata/script/mod_download.txt b/src/cmd/go/testdata/script/mod_download.txt new file mode 100644 index 0000000000..6be6acb360 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_download.txt @@ -0,0 +1,64 @@ +env GO111MODULE=on + +# download with version should print nothing +go mod download rsc.io/quote@v1.5.0 +! stdout . + +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.0.zip + +# download -json with version should print JSON +go mod download -json 'rsc.io/quote@<=v1.5.0' +stdout '^\t"Path": "rsc.io/quote"' +stdout '^\t"Version": "v1.5.0"' +stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.info"' +stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.mod"' +stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.0.zip"' +stdout '^\t"Sum": "h1:6fJa6E\+wGadANKkUMlZ0DhXFpoKlslOQDCo259XtdIE="' # hash of testdata/mod version, not real version! +stdout '^\t"GoModSum": "h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe\+TKr0="' +! stdout '"Error"' + +# download queries above should not have added to go.mod. +go list -m all +! stdout rsc.io + +# add to go.mod so we can test non-query downloads +go mod edit -require rsc.io/quote@v1.5.2 +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# module loading will page in the info and mod files +go list -m all +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip + +# download will fetch and unpack the zip file +go mod download +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.info +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.mod +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.2.zip +exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 + +go mod download -json +stdout '^\t"Path": "rsc.io/quote"' +stdout '^\t"Version": "v1.5.2"' +stdout '^\t"Info": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.info"' +stdout '^\t"GoMod": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.mod"' +stdout '^\t"Zip": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)cache(\\\\|/)download(\\\\|/)rsc.io(\\\\|/)quote(\\\\|/)@v(\\\\|/)v1.5.2.zip"' +stdout '^\t"Dir": ".*(\\\\|/)pkg(\\\\|/)mod(\\\\|/)rsc.io(\\\\|/)quote@v1.5.2"' + +# download will follow replacements +go mod edit -require rsc.io/quote@v1.5.1 -replace rsc.io/quote@v1.5.1=rsc.io/quote@v1.5.3-pre1 +go mod download +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.3-pre1.zip + +# download will not follow replacements for explicit module queries +go mod download -json rsc.io/quote@v1.5.1 +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.5.1.zip + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_edit.txt b/src/cmd/go/testdata/script/mod_edit.txt new file mode 100644 index 0000000000..60a6f74536 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_edit.txt @@ -0,0 +1,136 @@ +env GO111MODULE=on + +# Test that go mod edits and related mod flags work. +# Also test that they can use a dummy name that isn't resolvable. golang.org/issue/24100 + +# go mod init +! go mod init +stderr 'cannot determine module path' +! exists go.mod + +go mod init x.x/y/z +stderr 'creating new go.mod: module x.x/y/z' +cmp go.mod $WORK/go.mod.init + +! go mod init +cmp go.mod $WORK/go.mod.init + +# go mod edits +go mod edit -droprequire=x.1 -require=x.1@v1.0.0 -require=x.2@v1.1.0 -droprequire=x.2 -exclude='x.1 @ v1.2.0' -exclude=x.1@v1.2.1 -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z' +cmp go.mod $WORK/go.mod.edit1 +go mod edit -droprequire=x.1 -dropexclude=x.1@v1.2.1 -dropreplace=x.1@v1.3.0 -require=x.3@v1.99.0 +cmp go.mod $WORK/go.mod.edit2 + +# go mod edit -json +go mod edit -json +cmp stdout $WORK/go.mod.json + +# go mod edit -replace +go mod edit -replace=x.1@v1.3.0=y.1/v2@v2.3.5 -replace=x.1@v1.4.0=y.1/v2@v2.3.5 +cmp go.mod $WORK/go.mod.edit3 +go mod edit -replace=x.1=y.1/v2@v2.3.6 +cmp go.mod $WORK/go.mod.edit4 +go mod edit -dropreplace=x.1 +cmp go.mod $WORK/go.mod.edit5 + +# go mod edit -fmt +cp $WORK/go.mod.badfmt go.mod +go mod edit -fmt -print # -print should avoid writing file +cmp stdout $WORK/go.mod.edit4 +cmp go.mod $WORK/go.mod.badfmt +go mod edit -fmt # without -print, should write file (and nothing to stdout) +! stdout . +cmp go.mod $WORK/go.mod.edit4 + +-- x.go -- +package x + +-- w/w.go -- +package w + +-- $WORK/go.mod.init -- +module x.x/y/z +-- $WORK/go.mod.edit1 -- +module x.x/y/z + +require x.1 v1.0.0 + +exclude ( + x.1 v1.2.0 + x.1 v1.2.1 +) + +replace ( + x.1 v1.3.0 => y.1 v1.4.0 + x.1 v1.4.0 => ../z +) +-- $WORK/go.mod.edit2 -- +module x.x/y/z + +exclude x.1 v1.2.0 + +replace x.1 v1.4.0 => ../z + +require x.3 v1.99.0 +-- $WORK/go.mod.json -- +{ + "Module": { + "Path": "x.x/y/z" + }, + "Require": [ + { + "Path": "x.3", + "Version": "v1.99.0" + } + ], + "Exclude": [ + { + "Path": "x.1", + "Version": "v1.2.0" + } + ], + "Replace": [ + { + "Old": { + "Path": "x.1", + "Version": "v1.4.0" + }, + "New": { + "Path": "../z" + } + } + ] +} +-- $WORK/go.mod.edit3 -- +module x.x/y/z + +exclude x.1 v1.2.0 + +replace ( + x.1 v1.3.0 => y.1/v2 v2.3.5 + x.1 v1.4.0 => y.1/v2 v2.3.5 +) + +require x.3 v1.99.0 +-- $WORK/go.mod.edit4 -- +module x.x/y/z + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 +-- $WORK/go.mod.edit5 -- +module x.x/y/z + +exclude x.1 v1.2.0 + +require x.3 v1.99.0 +-- $WORK/go.mod.badfmt -- +module x.x/y/z + +exclude x.1 v1.2.0 + +replace x.1 => y.1/v2 v2.3.6 + +require x.3 v1.99.0 diff --git a/src/cmd/go/testdata/script/mod_enabled.txt b/src/cmd/go/testdata/script/mod_enabled.txt new file mode 100644 index 0000000000..8eef870b02 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_enabled.txt @@ -0,0 +1,82 @@ +# GO111MODULE=auto should only trigger outside GOPATH/src +env GO111MODULE=auto + +cd $GOPATH/src/x/y/z +go env GOMOD +! stdout . # no non-empty lines +! go list -m -f {{.GoMod}} +stderr 'not using modules' + +cd $GOPATH/src/x/y/z/w +go env GOMOD +! stdout . + +cd $GOPATH/src/x/y +go env GOMOD +! stdout . + +cd $GOPATH/foo +go env GOMOD +stdout foo[/\\]go.mod +go list -m -f {{.GoMod}} +stdout foo[/\\]go.mod + +cd $GOPATH/foo/bar/baz +go env GOMOD +stdout foo[/\\]go.mod + +# GO111MODULE=on should trigger everywhere +env GO111MODULE=on + +cd $GOPATH/src/x/y/z +go env GOMOD +stdout z[/\\]go.mod + +cd $GOPATH/src/x/y/z/w +go env GOMOD +stdout z[/\\]go.mod + +cd $GOPATH/src/x/y +go env GOMOD +! stdout . +! go list -m +stderr 'cannot find main module' + +cd $GOPATH/foo +go env GOMOD +stdout foo[/\\]go.mod + +cd $GOPATH/foo/bar/baz +go env GOMOD +stdout foo[/\\]go.mod + +# GO111MODULE=off should trigger nowhere +env GO111MODULE=off + +cd $GOPATH/src/x/y/z +go env GOMOD +! stdout .+ + +cd $GOPATH/foo +go env GOMOD +! stdout .+ + +cd $GOPATH/foo/bar/baz +go env GOMOD +! stdout .+ + +# GO111MODULE=auto should ignore and warn about /tmp/go.mod +env GO111MODULE=auto +cp $GOPATH/src/x/y/z/go.mod $WORK/tmp/go.mod +mkdir $WORK/tmp/mydir +cd $WORK/tmp/mydir +go env GOMOD +! stdout .+ +stderr '^go: warning: ignoring go.mod in system temp root ' + +-- $GOPATH/src/x/y/z/go.mod -- +module x/y/z +-- $GOPATH/src/x/y/z/w/w.txt -- +-- $GOPATH/foo/go.mod -- +module example.com/mod +-- $GOPATH/foo/bar/baz/quux.txt -- diff --git a/src/cmd/go/testdata/script/mod_file_proxy.txt b/src/cmd/go/testdata/script/mod_file_proxy.txt new file mode 100644 index 0000000000..8de6d7dbb8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_file_proxy.txt @@ -0,0 +1,25 @@ +# Allow (cached) downloads for -mod=readonly. +env GO111MODULE=on +env GOPATH=$WORK/gopath1 +cd $WORK/x +go mod edit -fmt +go list -mod=readonly +env GOPROXY=file:///nonexist +go list +grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list + +# Use download cache as file:/// proxy. +[windows] stop # TODO: file://$WORK puts backslashes in the URL +env GOPATH=$WORK/gopath2 +env GOPROXY=file:///nonexist +! go list +env GOPROXY=file://$WORK/gopath1/pkg/mod/cache/download +go list +grep v1.5.1 $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/list + +-- $WORK/x/go.mod -- +module x +require rsc.io/quote v1.5.1 +-- $WORK/x/x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_find.txt b/src/cmd/go/testdata/script/mod_find.txt new file mode 100644 index 0000000000..f4ac8d01f5 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_find.txt @@ -0,0 +1,91 @@ +# Derive module path from import comment. +cd $WORK/x +exists x.go +go mod init +stderr 'module x' + +# Import comment works even with CRLF line endings. +rm go.mod +addcrlf x.go +go mod init +stderr 'module x' + +# go mod should die in GOPATH if modules are not enabled for GOPATH +cd $GOPATH/src/example.com/x/y +! go mod init +stderr 'go: modules disabled inside GOPATH/src by GO111MODULE=auto; see ''go help modules''' + +env GO111MODULE=on + +# Derive module path from location inside GOPATH. +cd $GOPATH/src/example.com/x/y +go mod init +stderr 'module example.com/x/y$' +rm go.mod + +# Module path from Godeps/Godeps.json overrides GOPATH. +cd $GOPATH/src/example.com/x/y/z +go mod init +stderr 'unexpected.com/z' +rm go.mod + +# Empty directory outside GOPATH fails. +mkdir $WORK/empty +cd $WORK/empty +! go mod init +stderr 'cannot determine module path for source directory' +rm go.mod + +# Empty directory inside GOPATH/src uses location inside GOPATH. +mkdir $GOPATH/src/empty +cd $GOPATH/src/empty +go mod init +stderr 'empty' +rm go.mod + +[!symlink] stop + +# gplink1/src/empty where gopathlink -> GOPATH +symlink $WORK/gopathlink -> gopath +cd $WORK/gopathlink/src/empty +go mod init +rm go.mod + +# GOPATH/src/link where link -> out of GOPATH +symlink $GOPATH/src/link -> $WORK/empty +cd $WORK/empty +! go mod init +cd $GOPATH/src/link +go mod init +stderr link +rm go.mod + +# GOPATH/src/empty where GOPATH itself is a symlink +env GOPATH=$WORK/gopathlink +cd $GOPATH/src/empty +go mod init +rm go.mod +cd $WORK/gopath/src/empty +go mod init +rm go.mod + +# GOPATH/src/link where GOPATH and link are both symlinks +cd $GOPATH/src/link +go mod init +stderr link +rm go.mod + +# Too hard: doesn't match unevaluated nor completely evaluated. (Only partially evaluated.) +# Whether this works depends on which OS we are running on. +# cd $WORK/gopath/src/link +# ! go mod init + +-- $WORK/x/x.go -- +package x // import "x" + +-- $GOPATH/src/example.com/x/y/y.go -- +package y +-- $GOPATH/src/example.com/x/y/z/z.go -- +package z +-- $GOPATH/src/example.com/x/y/z/Godeps/Godeps.json -- +{"ImportPath": "unexpected.com/z"} diff --git a/src/cmd/go/testdata/script/mod_fs_patterns.txt b/src/cmd/go/testdata/script/mod_fs_patterns.txt new file mode 100644 index 0000000000..d7d3e0321b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_fs_patterns.txt @@ -0,0 +1,66 @@ +# File system pattern searches should skip sub-modules and vendor directories. + +env GO111MODULE=on + +cd x + +# all packages +go list all +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# path pattern +go list m/... +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# directory pattern +go list ./... +stdout ^m$ +stdout ^m/vendor$ +! stdout vendor/ +stdout ^m/y$ +! stdout ^m/y/z + +# non-existent directory should not prompt lookups +! go build -mod=readonly example.com/nonexist +stderr 'import lookup disabled' + +! go build -mod=readonly ./nonexist +! stderr 'import lookup disabled' +stderr '^go: no such directory ./nonexist' + +! go build -mod=readonly ./go.mod +! stderr 'import lookup disabled' +stderr '^go: ./go.mod is not a directory' + +-- x/go.mod -- +module m + +-- x/x.go -- +package x + +-- x/vendor/v/v.go -- +package v +import _ "golang.org/x/crypto" + +-- x/vendor/v.go -- +package main + +-- x/y/y.go -- +package y + +-- x/y/z/go.mod -- +syntax error! + +-- x/y/z/z.go -- +package z + +-- x/y/z/w/w.go -- +package w diff --git a/src/cmd/go/testdata/script/mod_get_commit.txt b/src/cmd/go/testdata/script/mod_get_commit.txt new file mode 100644 index 0000000000..589a791fd4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_commit.txt @@ -0,0 +1,53 @@ +env GO111MODULE=on + +# @commit should resolve + +# golang.org/x/text/language@commit should not resolve with -m, +# because that's not a module path. +! go get -m golang.org/x/text/language@14c0d48 + +# ... but it should work without -m. +# because of -d, the compiler should not run +go get -d -x golang.org/x/text/language@14c0d48 +! stderr 'compile|cp|gccgo .*language\.a$' + +# go get should skip build with no Go files in root +go get golang.org/x/text@14c0d48 + +# ... and go get should skip build with -m +go get -m golang.org/x/text@14c0d48 + +# dropping -d, we should see a build. +go get -x golang.org/x/text/language@14c0d48 +stderr 'compile|cp|gccgo .*language\.a$' + +# BUG: after the build, the package should not be stale, as 'go install' would +# not do anything further. +go list -f '{{.Stale}}' golang.org/x/text/language +stdout ^true + +# install after get should not run the compiler again. +go install -x golang.org/x/text/language +! stderr 'compile|cp|gccgo .*language\.a$' + +# even with -d, we should see an error for unknown packages. +! go get -d -x golang.org/x/text/foo@14c0d48 + +# get pseudo-version should record that version +go get rsc.io/quote@v0.0.0-20180214005840-23179ee8a569 +grep 'rsc.io/quote v0.0.0-20180214005840-23179ee8a569' go.mod + +# but as commit should record as v1.5.1 +go get rsc.io/quote@23179ee8 +grep 'rsc.io/quote v1.5.1' go.mod + +# go mod edit -require does not interpret commits +go mod edit -require rsc.io/quote@23179ee +grep 'rsc.io/quote 23179ee' go.mod + +# but other commands fix them +go mod graph +grep 'rsc.io/quote v1.5.1' go.mod + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_get_downgrade.txt b/src/cmd/go/testdata/script/mod_get_downgrade.txt new file mode 100644 index 0000000000..ac814dae08 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_downgrade.txt @@ -0,0 +1,39 @@ +env GO111MODULE=on + +# downgrade sampler should downgrade quote +go get rsc.io/sampler@v1.0.0 +go list -m all +stdout 'rsc.io/quote v1.4.0' +stdout 'rsc.io/sampler v1.0.0' + +# downgrade sampler away should downgrade quote further +go get rsc.io/sampler@none +go list -m all +stdout 'rsc.io/quote v1.3.0' + +# downgrade should report inconsistencies and not change go.mod +go get rsc.io/quote@v1.5.1 +go list -m all +stdout 'rsc.io/quote v1.5.1' +stdout 'rsc.io/sampler v1.3.0' +! go get rsc.io/sampler@v1.0.0 rsc.io/quote@v1.5.2 golang.org/x/text@none +stderr 'go get: inconsistent versions:\n\trsc.io/quote@v1.5.2 requires golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c \(not golang.org/x/text@none\), rsc.io/sampler@v1.3.0 \(not rsc.io/sampler@v1.0.0\)' +go list -m all +stdout 'rsc.io/quote v1.5.1' +stdout 'rsc.io/sampler v1.3.0' + +# go get -u args should limit upgrades +cp go.mod.empty go.mod +go get -u rsc.io/quote@v1.4.0 rsc.io/sampler@v1.0.0 +go list -m all +stdout 'rsc.io/quote v1.4.0' +stdout 'rsc.io/sampler v1.0.0' +! stdout golang.org/x/text + +-- go.mod -- +module x +require rsc.io/quote v1.5.1 +-- go.mod.empty -- +module x +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_get_incompatible.txt b/src/cmd/go/testdata/script/mod_get_incompatible.txt new file mode 100644 index 0000000000..b210715a5d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_incompatible.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +go list x +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +cp go.mod2 go.mod +go get rsc.io/breaker@7307b30 +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +go get rsc.io/breaker@v2.0.0 +go list -m all +stdout 'rsc.io/breaker v2.0.0\+incompatible' + +-- go.mod -- +module x + +-- go.mod2 -- +module x +require rsc.io/breaker v1.0.0 + +-- x.go -- +package x +import "rsc.io/breaker" +var _ = breaker.XX diff --git a/src/cmd/go/testdata/script/mod_get_indirect.txt b/src/cmd/go/testdata/script/mod_get_indirect.txt new file mode 100644 index 0000000000..3ae5833834 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_indirect.txt @@ -0,0 +1,51 @@ +env GO111MODULE=on + +# get -u should find quote v1.5.2 +go get -u +go list -m all +stdout 'quote v1.5.2$' +grep 'rsc.io/quote v1.5.2$' go.mod + +# it should also update x/text later than requested by v1.5.2 +go list -m -f '{{.Path}} {{.Version}}{{if .Indirect}} // indirect{{end}}' all +stdout '^golang.org/x/text [v0-9a-f\.-]+ // indirect' +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# importing an empty module root as a package makes it direct. +# TODO(bcmills): This doesn't seem correct. Fix is in the next change. +cp $WORK/tmp/usetext.go x.go +go list -e +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# indirect tag should be removed upon seeing direct import. +cp $WORK/tmp/uselang.go x.go +go list +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod + +# indirect tag should be added by go mod tidy +cp $WORK/tmp/usequote.go x.go +go mod tidy +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# requirement should be dropped entirely if not needed +cp $WORK/tmp/uselang.go x.go +go mod tidy +! grep rsc.io/quote go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+$' go.mod + +-- go.mod -- +module x +require rsc.io/quote v1.5.1 +-- x.go -- +package x +-- $WORK/tmp/usetext.go -- +package x +import _ "golang.org/x/text" +-- $WORK/tmp/uselang.go -- +package x +import _ "golang.org/x/text/language" +-- $WORK/tmp/usequote.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_local.txt b/src/cmd/go/testdata/script/mod_get_local.txt new file mode 100644 index 0000000000..4edda993f1 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_local.txt @@ -0,0 +1,61 @@ +# Test 'go get' with a local module with a name that is not valid for network lookup. + +env GO111MODULE=on +go mod edit -fmt +cp go.mod go.mod.orig + +# 'go get -u -m' within the main module should work, even if it has a local-only name. +cp go.mod.orig go.mod +go get -u -m +grep 'rsc.io/quote.*v1.5.2' go.mod +grep 'golang.org/x/text.*v0.3.0' go.mod +cp go.mod go.mod.implicitmod + +# 'go get -u -m' with the name of the main module should be equivalent to +# 'go get -u -m' without any further arguments. +cp go.mod.orig go.mod +go get -u -m local +cmp go.mod go.mod.implicitmod + +# 'go get -u -d' in the empty root of the main module should update the +# dependencies of all packages in the module. +cp go.mod.orig go.mod +go get -u -d +cmp go.mod go.mod.implicitmod + +# 'go get -u -d .' within a package in the main module updates all dependencies +# of the main module. +# TODO: Determine whether that behavior is a bug. +# (https://golang.org/issue/26902) +cp go.mod.orig go.mod +cd uselang +go get -u -d . +cd .. +grep 'rsc.io/quote.*v1.5.2' go.mod +grep 'golang.org/x/text.*v0.3.0' go.mod +cp go.mod go.mod.dotpkg + +# 'go get -u -d' with an explicit package in the main module updates +# all dependencies of the main module. +# TODO: Determine whether that behavior is a bug. +# (https://golang.org/issue/26902) +cp go.mod.orig go.mod +go get -u -d local/uselang +cmp go.mod go.mod.dotpkg + + +-- go.mod -- +module local + +require ( + golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c + rsc.io/quote v1.3.0 +) + +-- uselang/uselang.go -- +package uselang +import _ "golang.org/x/text/language" + +-- usequote/usequote.go -- +package usequote +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_get_moved.txt b/src/cmd/go/testdata/script/mod_get_moved.txt new file mode 100644 index 0000000000..be91449155 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_moved.txt @@ -0,0 +1,37 @@ +env GO111MODULE=on + +# A 'go get' that worked at a previous version should continue to work at that version, +# even if the package was subsequently moved into a submodule. +go mod init example.com/foo +go get -d example.com/split/subpkg@v1.0.0 +go list -m all +stdout 'example.com/split v1.0.0' + +# A 'go get' that simultaneously upgrades away conflicting package defitions is not ambiguous. +go get example.com/split/subpkg@v1.1.0 + +# A 'go get' without an upgrade should find the package. +rm go.mod +go mod init example.com/foo +go get -d example.com/split/subpkg +go list -m all +stdout 'example.com/split/subpkg v1.1.0' + + +# A 'go get' that worked at a previous version should continue to work at that version, +# even if the package was subsequently moved into a parent module. +rm go.mod +go mod init example.com/foo +go get -d example.com/join/subpkg@v1.0.0 +go list -m all +stdout 'example.com/join/subpkg v1.0.0' + +# A 'go get' that simultaneously upgrades away conflicting package definitions is not ambiguous. +go get example.com/join/subpkg@v1.1.0 + +# A 'go get' without an upgrade should find the package. +rm go.mod +go mod init example.com/foo +go get -d example.com/join/subpkg@v1.1.0 +go list -m all +stdout 'example.com/join v1.1.0' diff --git a/src/cmd/go/testdata/script/mod_get_none.txt b/src/cmd/go/testdata/script/mod_get_none.txt new file mode 100644 index 0000000000..5aec209f59 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_none.txt @@ -0,0 +1,12 @@ +env GO111MODULE=on + +go mod init example.com/foo + +# 'go get bar@none' should be a no-op if module bar is not active. +go get example.com/bar@none +go list -m all +! stdout example.com/bar + +go get example.com/bar@none +go list -m all +! stdout example.com/bar diff --git a/src/cmd/go/testdata/script/mod_get_pseudo.txt b/src/cmd/go/testdata/script/mod_get_pseudo.txt new file mode 100644 index 0000000000..3945fdfa89 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_pseudo.txt @@ -0,0 +1,80 @@ +env GO111MODULE=on + +# Testing git->module converter's generation of +incompatible tags; turn off proxy. +[!net] skip +[!exec:git] skip +env GOPROXY= + +# We can resolve the @master branch without unshallowing the local repository +# (even with older gits), so try that before we do anything else. +# (This replicates https://golang.org/issue/26713 with git 2.7.4.) +go get -m github.com/rsc/legacytest@master +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$' + +# get should include incompatible tags in "latest" calculation. +go get -m github.com/rsc/legacytest@latest +go list +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.1-0.pseudo+incompatible +go get -m ...test@7303f77 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.1-0\.\d{14}-7303f7796364\+incompatible$' + +# v2.0.0+incompatible by tag+incompatible +go get -m ...test@v2.0.0+incompatible +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.0+incompatible by tag +go get -m ...test@v2.0.0 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v2.0.0+incompatible by hash (back on master) +go get -m ...test@d7ae1e4 +go list -m all +stdout '^github.com/rsc/legacytest v2\.0\.0\+incompatible$' + +# v1.2.1-0.pseudo +go get -m ...test@d2d4c3e +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.1-0\.\d{14}-d2d4c3ea6623$' + +# v1.2.0 +go get -m ...test@9f6f860 +go list -m all +stdout '^github.com/rsc/legacytest v1\.2\.0$' + +# v1.1.0-pre.0.pseudo +go get -m ...test@fb3c628 +go list -m all +stdout '^github.com/rsc/legacytest v1\.1\.0-pre\.0\.\d{14}-fb3c628075e3$' + +# v1.1.0-pre (no longer on master) +go get -m ...test@731e3b1 +go list -m all +stdout '^github.com/rsc/legacytest v1\.1\.0-pre$' + +# v1.0.1-0.pseudo +go get -m ...test@fa4f5d6 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.1-0\.\d{14}-fa4f5d6a71c6$' + +# v1.0.0 +go get -m ...test@7fff7f3 +go list -m all +stdout '^github.com/rsc/legacytest v1\.0\.0$' + +# v0.0.0-pseudo +go get -m ...test@52853eb +go list -m all +stdout '^github.com/rsc/legacytest v0\.0\.0-\d{14}-52853eb7b552$' + +-- go.mod -- +module x +-- x.go -- +package x +import "github.com/rsc/legacytest" diff --git a/src/cmd/go/testdata/script/mod_get_upgrade.txt b/src/cmd/go/testdata/script/mod_get_upgrade.txt new file mode 100644 index 0000000000..5eb5ff9657 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_upgrade.txt @@ -0,0 +1,41 @@ +env GO111MODULE=on + +go get rsc.io/quote@v1.5.1 +go list -m all +stdout 'rsc.io/quote v1.5.1' +grep 'rsc.io/quote v1.5.1$' go.mod + +# get -u should update all dependencies +go get -u +grep 'rsc.io/quote v1.5.2$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# get -u rsc.io/sampler should update only sampler's dependencies +cp go.mod-v1.5.1 go.mod +go get -u rsc.io/sampler +grep 'rsc.io/quote v1.5.1$' go.mod +grep 'golang.org/x/text [v0-9a-f\.-]+ // indirect' go.mod + +# move to a pseudo-version after any tags +go get -m rsc.io/quote@dd9747d +grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod + +# get -u should not jump off newer pseudo-version to earlier tag +go get -m -u +grep 'rsc.io/quote v0.0.0-20180628003336-dd9747d19b04' go.mod + +# move to earlier pseudo-version +go get -m rsc.io/quote@e7a685a342 +grep 'rsc.io/quote v0.0.0-20180214005133-e7a685a342c0' go.mod + +# get -u should jump off earlier pseudo-version to newer tag +go get -m -u +grep 'rsc.io/quote v1.5.2' go.mod + +-- go.mod -- +module x +require rsc.io/quote v1.1.0 + +-- go.mod-v1.5.1 -- +module x +require rsc.io/quote v1.5.1 diff --git a/src/cmd/go/testdata/script/mod_get_warning.txt b/src/cmd/go/testdata/script/mod_get_warning.txt new file mode 100644 index 0000000000..36b5434c3b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_get_warning.txt @@ -0,0 +1,10 @@ +# go get in GO111MODULE=auto should warn when not using modules and go.mod exists + +env GO111MODULE=auto +mkdir z +cd z +! go get # fails because no code in directory, not the warning +stderr 'go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;\n\tignoring ..[/\\]go.mod;\n\tsee ''go help modules''' + +-- go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_getmode_vendor.txt b/src/cmd/go/testdata/script/mod_getmode_vendor.txt new file mode 100644 index 0000000000..3dd8d1b888 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_getmode_vendor.txt @@ -0,0 +1,23 @@ +env GO111MODULE=on + +go get -m rsc.io/quote@v1.5.1 +go mod vendor +env GOPATH=$WORK/empty +env GOPROXY=file:///nonexist + +go list -mod=vendor +go list -mod=vendor -m -f '{{.Path}} {{.Version}} {{.Dir}}' all +stdout '^rsc.io/quote v1.5.1 .*vendor[\\/]rsc.io[\\/]quote$' +stdout '^golang.org/x/text v0.0.0.* .*vendor[\\/]golang.org[\\/]x[\\/]text$' + +! go list -mod=vendor -m rsc.io/quote@latest +stderr 'module lookup disabled by -mod=vendor' +! go get -mod=vendor -u +stderr 'go get: disabled by -mod=vendor' + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_go_version.txt b/src/cmd/go/testdata/script/mod_go_version.txt new file mode 100644 index 0000000000..f2de74cee8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_go_version.txt @@ -0,0 +1,61 @@ +# Test support for declaring needed Go version in module. + +env GO111MODULE=on + +go list +! go build +stderr 'module requires Go 1.999' +go build sub.1 +! go build badsub.1 +stderr 'module requires Go 1.11111' + +go build versioned.1 +go mod edit -require versioned.1@v1.1.0 +! go build versioned.1 +stderr 'module requires Go 1.99999' + +-- go.mod -- +module m +go 1.999 +require ( + sub.1 v1.0.0 + badsub.1 v1.0.0 + versioned.1 v1.0.0 +) +replace ( + sub.1 => ./sub + badsub.1 => ./badsub + versioned.1 v1.0.0 => ./versioned1 + versioned.1 v1.1.0 => ./versioned2 +) + +-- x.go -- +package x + +-- sub/go.mod -- +module m +go 1.11 + +-- sub/x.go -- +package x + +-- badsub/go.mod -- +module m +go 1.11111 + +-- badsub/x.go -- +package x + +-- versioned1/go.mod -- +module versioned +go 1.0 + +-- versioned1/x.go -- +package x + +-- versioned2/go.mod -- +module versioned +go 1.99999 + +-- versioned2/x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_gobuild_import.txt b/src/cmd/go/testdata/script/mod_gobuild_import.txt new file mode 100644 index 0000000000..932b8b66f9 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gobuild_import.txt @@ -0,0 +1,74 @@ +# go/build's Import should find modules by invoking the go command + +go build -o $WORK/testimport.exe ./testimport + +# GO111MODULE=off +env GO111MODULE=off +! exec $WORK/testimport.exe x/y/z/w . + +# GO111MODULE=auto in GOPATH/src +env GO111MODULE= +! exec $WORK/testimport.exe x/y/z/w . +env GO111MODULE=auto +! exec $WORK/testimport.exe x/y/z/w . + +# GO111MODULE=auto outside GOPATH/src +cd $GOPATH/other +env GO111MODULE= +exec $WORK/testimport.exe other/x/y/z/w . +stdout w2.go + +! exec $WORK/testimport.exe x/y/z/w . +stderr 'cannot find module providing package x/y/z/w' + +cd z +env GO111MODULE=auto +exec $WORK/testimport.exe other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on outside GOPATH/src +env GO111MODULE=on +exec $WORK/testimport.exe other/x/y/z/w . +stdout w2.go + +# GO111MODULE=on in GOPATH/src +cd $GOPATH/src +exec $WORK/testimport.exe x/y/z/w . +stdout w1.go +cd w +exec $WORK/testimport.exe x/y/z/w .. +stdout w1.go + +-- go.mod -- +module x/y/z + +-- z.go -- +package z + +-- w/w1.go -- +package w + +-- testimport/x.go -- +package main + +import ( + "fmt" + "go/build" + "log" + "os" + "strings" +) + +func main() { + p, err := build.Import(os.Args[1], os.Args[2], 0) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s\n%s\n", p.Dir, strings.Join(p.GoFiles, " ")) +} + +-- $GOPATH/other/go.mod -- +module other/x/y + +-- $GOPATH/other/z/w/w2.go -- +package w diff --git a/src/cmd/go/testdata/script/mod_gofmt_invalid.txt b/src/cmd/go/testdata/script/mod_gofmt_invalid.txt new file mode 100644 index 0000000000..21edc7dc2f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gofmt_invalid.txt @@ -0,0 +1,13 @@ +# Test for a crash in go fmt on invalid input when using modules. +# Issue 26792. + +env GO111MODULE=on +! go fmt x.go +! stderr panic + +-- go.mod -- +module x + +-- x.go -- +// Missing package declaration. +var V int diff --git a/src/cmd/go/testdata/script/mod_gopkg_unstable.txt b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt new file mode 100644 index 0000000000..d945cf35b4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_gopkg_unstable.txt @@ -0,0 +1,22 @@ +env GO111MODULE=on + +cp go.mod.empty go.mod +go get -d gopkg.in/dummy.v2-unstable + +cp x.go.txt x.go +cp go.mod.empty go.mod +go list + +[!net] skip + +env GOPROXY= +go get gopkg.in/macaroon-bakery.v2-unstable/bakery +go list -m all +stdout 'gopkg.in/macaroon-bakery.v2-unstable v2.0.0-[0-9]+-[0-9a-f]+$' + +-- go.mod.empty -- +module m + +-- x.go.txt -- +package x +import _ "gopkg.in/dummy.v2-unstable" diff --git a/src/cmd/go/testdata/script/mod_graph.txt b/src/cmd/go/testdata/script/mod_graph.txt new file mode 100644 index 0000000000..07968f531d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_graph.txt @@ -0,0 +1,10 @@ +env GO111MODULE=on + +go mod graph +stdout '^m rsc.io/quote@v1.5.2$' +stdout '^rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0$' +! stdout '^m rsc.io/sampler@v1.3.0$' + +-- go.mod -- +module m +require rsc.io/quote v1.5.2 diff --git a/src/cmd/go/testdata/script/mod_import.txt b/src/cmd/go/testdata/script/mod_import.txt new file mode 100644 index 0000000000..3985b43144 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import.txt @@ -0,0 +1,18 @@ +env GO111MODULE=on + +# latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1 +go list +go list -m all +stdout 'rsc.io/quote v1.5.2' + +# but v1.5.3-pre1 should be a known version +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$' + +-- go.mod -- +module x + +-- x.go -- +package x +import _ "rsc.io/quote" + diff --git a/src/cmd/go/testdata/script/mod_import_mod.txt b/src/cmd/go/testdata/script/mod_import_mod.txt new file mode 100644 index 0000000000..b035e3dec2 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_import_mod.txt @@ -0,0 +1,7 @@ +# Test that GOPATH/pkg/mod is excluded +env GO111MODULE=off +! go list mod/foo +stderr 'disallowed import path' + +-- mod/foo/foo.go -- +package foo diff --git a/src/cmd/go/testdata/script/mod_init_dep.txt b/src/cmd/go/testdata/script/mod_init_dep.txt new file mode 100644 index 0000000000..29c840b383 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_init_dep.txt @@ -0,0 +1,34 @@ +env GO111MODULE=on + +# modconv uses git directly to examine what old 'go get' would +[!net] skip +[!exec:git] skip + +# go build should populate go.mod from Gopkg.lock +cp go.mod1 go.mod +go build +stderr 'copying requirements from Gopkg.lock' +go list -m all +! stderr 'copying requirements from Gopkg.lock' +stdout 'rsc.io/sampler v1.0.0' + +# go list should populate go.mod from Gopkg.lock +cp go.mod1 go.mod +go list +stderr 'copying requirements from Gopkg.lock' +go list +! stderr 'copying requirements from Gopkg.lock' +go list -m all +stdout 'rsc.io/sampler v1.0.0' + +-- go.mod1 -- +module x + +-- x.go -- +package x + +-- Gopkg.lock -- +[[projects]] + name = "rsc.io/sampler" + version = "v1.0.0" + diff --git a/src/cmd/go/testdata/script/mod_install_versioned.txt b/src/cmd/go/testdata/script/mod_install_versioned.txt new file mode 100644 index 0000000000..03986d06a0 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_install_versioned.txt @@ -0,0 +1,12 @@ +env GO111MODULE=on + +go list -f '{{.Target}}' rsc.io/fortune +! stdout fortune@v1 +stdout 'fortune(\.exe)?$' + +go list -f '{{.Target}}' rsc.io/fortune/v2 +! stdout v2 +stdout 'fortune(\.exe)?$' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_internal.txt b/src/cmd/go/testdata/script/mod_internal.txt new file mode 100644 index 0000000000..e5f5a1205e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_internal.txt @@ -0,0 +1,102 @@ +env GO111MODULE=on + +# golang.org/x/internal should be importable from other golang.org/x modules. +rm go.mod +go mod init golang.org/x/anything +go build . + +# ...and their tests... +go test +stdout PASS + +# ...but that should not leak into other modules. +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +# Internal packages in the standard library should not leak into modules. +! go build ./fromstd +stderr 'use of internal package internal/testenv not allowed' + +# Packages found via standard-library vendoring should not leak. +! go build ./fromstdvendor +stderr 'use of vendored package golang_org/x/net/http/httpguts not allowed' + +env GO111MODULE=off +! go build ./fromstdvendor +stderr 'cannot find package "golang_org/x/net/http/httpguts" in any of:' +env GO111MODULE=on + +# Dependencies should be able to use their own internal modules... +rm go.mod +go mod init golang.org/notx +go build ./throughdep + +# ... but other modules should not, even if they have transitive dependencies. +! go build . +stderr 'use of internal package golang.org/x/.* not allowed' + +# And transitive dependencies still should not leak. +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +# Replacing an internal module should keep it internal to the same paths. +rm go.mod +go mod init golang.org/notx +go mod edit -replace golang.org/x/internal=./replace/golang.org/notx/internal +go build ./throughdep + +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +go mod edit -replace golang.org/x/internal=./vendor/golang.org/x/internal +go build ./throughdep + +! go build ./baddep +stderr golang.org[/\\]notx[/\\]useinternal +stderr 'use of internal package golang.org/x/.* not allowed' + +-- useinternal.go -- +package useinternal +import _ "golang.org/x/internal/subtle" + +-- useinternal_test.go -- +package useinternal_test +import ( + "testing" + _ "golang.org/x/internal/subtle" +) + +func Test(*testing.T) {} + +-- throughdep/useinternal.go -- +package throughdep +import _ "golang.org/x/useinternal" + +-- baddep/useinternal.go -- +package baddep +import _ "golang.org/notx/useinternal" + +-- fromstd/useinternal.go -- +package fromstd +import _ "internal/testenv" + +-- fromstdvendor/useinternal.go -- +package fromstdvendor +import _ "golang_org/x/net/http/httpguts" + +-- replace/golang.org/notx/internal/go.mod -- +module golang.org/x/internal + +-- replace/golang.org/notx/internal/subtle/subtle.go -- +package subtle +// Ha ha! Nothing here! + +-- vendor/golang.org/x/internal/go.mod -- +module golang.org/x/internal + +-- vendor/golang.org/x/internal/subtle/subtle.go -- +package subtle +// Ha ha! Nothing here! diff --git a/src/cmd/go/testdata/script/mod_list.txt b/src/cmd/go/testdata/script/mod_list.txt new file mode 100644 index 0000000000..c9797ea836 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list.txt @@ -0,0 +1,60 @@ +env GO111MODULE=on + +# list {{.Dir}} shows main module and go.mod but not not-yet-downloaded dependency dir. +go list -m -f '{{.Path}} {{.Main}} {{.GoMod}} {{.Dir}}' all +stdout '^x true .*[\\/]src[\\/]go.mod .*[\\/]src$' +stdout '^rsc.io/quote false .*[\\/]v1.5.2.mod $' + +# list {{.Dir}} shows dependency after download (and go list without -m downloads it) +go list -f '{{.Dir}}' rsc.io/quote +stdout '.*mod[\\/]rsc.io[\\/]quote@v1.5.2$' + +# downloaded dependencies are read-only +exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +exists -readonly $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/buggy + +# go clean -modcache can delete read-only dependencies +go clean -modcache +! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 + +# list {{.Dir}} shows replaced directories +cp go.mod2 go.mod +go list -f {{.Dir}} rsc.io/quote +go list -m -f '{{.Path}} {{.Version}} {{.Dir}}{{with .Replace}} {{.GoMod}} => {{.Version}} {{.Dir}} {{.GoMod}}{{end}}' all +stdout 'mod[\\/]rsc.io[\\/]quote@v1.5.1' +stdout 'v1.3.0.*mod[\\/]rsc.io[\\/]sampler@v1.3.1 .*[\\/]v1.3.1.mod => v1.3.1.*sampler@v1.3.1 .*[\\/]v1.3.1.mod' + +# list std should work +go list std +stdout ^math/big + +# rsc.io/quote/buggy should be listable as a package +go list rsc.io/quote/buggy + +# rsc.io/quote/buggy should not be listable as a module +go list -m -e -f '{{.Error.Err}}' nonexist rsc.io/quote/buggy +stdout '^module "nonexist" is not a known dependency' +stdout '^module "rsc.io/quote/buggy" is not a known dependency' + +! go list -m nonexist rsc.io/quote/buggy +stderr '^go list -m nonexist: module "nonexist" is not a known dependency' +stderr '^go list -m rsc.io/quote/buggy: module "rsc.io/quote/buggy" is not a known dependency' + +# Module loader does not interfere with list -e (golang.org/issue/24149). +go list -e -f '{{.Error.Err}}' database +stdout 'no Go files in ' +! go list database +stderr 'no Go files in ' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- go.mod2 -- +module x +require rsc.io/quote v1.5.1 +replace rsc.io/sampler v1.3.0 => rsc.io/sampler v1.3.1 + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_list_bad_import.txt b/src/cmd/go/testdata/script/mod_list_bad_import.txt new file mode 100644 index 0000000000..258eb6a567 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_bad_import.txt @@ -0,0 +1,73 @@ +# This test matches list_bad_import, but in module mode. +# Please keep them in sync. + +env GO111MODULE=on +cd example.com + +# Without -e, listing an otherwise-valid package with an unsatisfied direct import should fail. +# BUG: Today it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/direct +! stdout ^error +stdout 'incomplete' +stdout 'bad dep: .*example.com/notfound' + +# Listing with -deps should also fail. +# BUG: Today, it does not. +# ! go list -deps example.com/direct +# stderr example.com/notfound +go list -deps example.com/direct +stdout example.com/notfound + + +# Listing an otherwise-valid package that imports some *other* package with an +# unsatisfied import should also fail. +# BUG: Today, it succeeds. +go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}} {{range .DepsErrors}}bad dep: {{.Err}}{{end}}' example.com/indirect +! stdout ^error +stdout incomplete +stdout 'bad dep: .*example.com/notfound' + +# Again, -deps should fail. +# BUG: Again, it does not. +# ! go list -deps example.com/indirect +# stderr example.com/notfound +go list -deps example.com/indirect +stdout example.com/notfound + + +# Listing the missing dependency directly should fail outright... +! go list -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stderr 'cannot find module providing package example.com/notfound' +! stdout error +! stdout incomplete + +# ...but listing with -e should succeed. +go list -e -f '{{if .Error}}error{{end}} {{if .Incomplete}}incomplete{{end}}' example.com/notfound +stdout error +stdout incomplete + + +# The pattern "all" should match only packages that acutally exist, +# ignoring those whose existence is merely implied by imports. +go list -e -f '{{.ImportPath}} {{.Error}}' all +stdout example.com/direct +stdout example.com/indirect +# TODO: go list creates a dummy package with the import-not-found +# but really the Error belongs on example.com/direct, and this package +# should not be printed. +# ! stdout example.com/notfound + + +-- example.com/go.mod -- +module example.com + +-- example.com/direct/direct.go -- +package direct +import _ "example.com/notfound" + +-- example.com/indirect/indirect.go -- +package indirect +import _ "example.com/direct" + +-- example.com/notfound/README -- +This directory intentionally left blank. diff --git a/src/cmd/go/testdata/script/mod_list_dir.txt b/src/cmd/go/testdata/script/mod_list_dir.txt new file mode 100644 index 0000000000..800f277559 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_dir.txt @@ -0,0 +1,30 @@ +# go list with path to directory should work + +env GO111MODULE=off +go list -f '{{.ImportPath}}' $GOROOT/src/math +stdout ^math$ + +env GO111MODULE=on +go list -f '{{.ImportPath}}' $GOROOT/src/math +stdout ^math$ +go list -f '{{.ImportPath}}' . +stdout ^x$ +! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stderr '^go: no such directory.*quote@v1.5.2' +go mod download rsc.io/quote@v1.5.2 +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/quote@v1.5.2 +stdout '^rsc.io/quote$' +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0 +stdout '^rsc.io/sampler$' +go get -d rsc.io/sampler@v1.3.1 +go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.1 +stdout '^rsc.io/sampler$' +! go list -f '{{.ImportPath}}' $GOPATH/pkg/mod/rsc.io/sampler@v1.3.0 +stderr 'outside available modules' + +-- go.mod -- +module x +require rsc.io/quote v1.5.2 + +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_list_test.txt b/src/cmd/go/testdata/script/mod_list_test.txt new file mode 100644 index 0000000000..a99e4f36cd --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_test.txt @@ -0,0 +1,16 @@ +env GO111MODULE=on + +# go list -compiled -test must handle test-only packages +# golang.org/issue/27097. +go list -compiled -test +stdout '^m$' +stdout '^m\.test$' +stdout '^m \[m\.test\]$' + +-- go.mod -- +module m + +-- x_test.go -- +package x +import "testing" +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/mod_list_upgrade.txt b/src/cmd/go/testdata/script/mod_list_upgrade.txt new file mode 100644 index 0000000000..474df0dc26 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_list_upgrade.txt @@ -0,0 +1,8 @@ +env GO111MODULE=on + +go list -m -u all +stdout 'rsc.io/quote v1.2.0 \[v1\.5\.2\]' + +-- go.mod -- +module x +require rsc.io/quote v1.2.0 diff --git a/src/cmd/go/testdata/script/mod_load_badmod.txt b/src/cmd/go/testdata/script/mod_load_badmod.txt new file mode 100644 index 0000000000..68c8b3792b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_load_badmod.txt @@ -0,0 +1,26 @@ +# Unknown lines should be ignored in dependency go.mod files. +env GO111MODULE=on +go list -m all + +# ... and in replaced dependency go.mod files. +cp go.mod go.mod.usesub +go list -m all + +# ... but not in the main module. +cp go.mod.bad go.mod +! go list -m all +stderr 'unknown directive: hello' + +-- go.mod -- +module m +require rsc.io/badmod v1.0.0 +-- go.mod.bad -- +module m +hello world +-- go.mod.usesub -- +module m +require rsc.io/badmod v1.0.0 +replace rsc.io/badmod v1.0.0 => ./sub +-- sub/go.mod -- +module sub +hello world diff --git a/src/cmd/go/testdata/script/mod_local_replace.txt b/src/cmd/go/testdata/script/mod_local_replace.txt new file mode 100644 index 0000000000..19bc8f3904 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_local_replace.txt @@ -0,0 +1,23 @@ +# Test that local replacements work even with dummy module names. +# golang.org/issue/24100. + +env GO111MODULE=on + +cd x/y +go list -f '{{.Dir}}' zz +stdout x[/\\]z$ + +-- x/y/go.mod -- +module x/y +require zz v1.0.0 +replace zz v1.0.0 => ../z + +-- x/y/y.go -- +package y +import _ "zz" + +-- x/z/go.mod -- +module x/z + +-- x/z/z.go -- +package z diff --git a/src/cmd/go/testdata/script/mod_multirepo.txt b/src/cmd/go/testdata/script/mod_multirepo.txt new file mode 100644 index 0000000000..7f977e80f6 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_multirepo.txt @@ -0,0 +1,40 @@ +env GO111MODULE=on + +# initial standalone module should use no downloaded modules +go list -deps -f {{.Dir}} +! stdout 'pkg[\\/]mod' + +# v2 import should use a downloaded module +# both without an explicit go.mod entry ... +cp tmp/use_v2.go x.go +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +# ... and with one ... +cp tmp/use_v2.mod go.mod +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +# ... and even if there is a v2 module in a subdirectory. +mkdir v2 +cp x.go v2/x.go +cp tmp/v2.mod v2/go.mod +go list -deps -f {{.Dir}} +stdout 'pkg[\\/]mod[\\/]rsc.io[\\/]quote[\\/]v2@v2.0.1$' + +-- go.mod -- +module rsc.io/quote + +-- x.go -- +package quote + +-- tmp/use_v2.go -- +package quote +import _ "rsc.io/quote/v2" + +-- tmp/use_v2.mod -- +module rsc.io/quote +require rsc.io/quote/v2 v2.0.1 + +-- tmp/v2.mod -- +package rsc.io/quote/v2 diff --git a/src/cmd/go/testdata/script/mod_nomod.txt b/src/cmd/go/testdata/script/mod_nomod.txt new file mode 100644 index 0000000000..640d5a3631 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_nomod.txt @@ -0,0 +1,43 @@ +# Test go commands with no module. +env GO111MODULE=on + +# go mod edit fails unless given explicit mod file argument +! go mod edit -json +go mod edit -json x.mod + +# bug succeeds +[exec:echo] env BROWSER=echo +[exec:echo] go bug + +# commands that load the package in the current directory fail +! go build +! go fmt +! go generate +! go get +! go install +! go list +! go run x.go +! go test +! go vet + +# clean succeeds, even with -modcache +go clean -modcache + +# doc succeeds for standard library +go doc unsafe + +# env succeeds +go env + +# tool succeeds +go tool -n test2json + +# version succeeds +go version + +-- x.mod -- +module m + +-- x.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/mod_patterns.txt b/src/cmd/go/testdata/script/mod_patterns.txt new file mode 100644 index 0000000000..4fa436ba2d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_patterns.txt @@ -0,0 +1,66 @@ +env GO111MODULE=on + +cd m + +# 'go list all' should list all of the packages used (directly or indirectly) by +# the packages in the main module, but no other packages from the standard +# library or active modules. +# +# 'go list ...' should list packages in all active modules and the standard library. +# But not cmd/* - see golang.org/issue/26924. +# +# 'go list example.com/m/...' should list packages in all modules that begin with 'example.com/m/'. +# +# 'go list ./...' should list only packages in the current module, not other active modules. +# +# Warnings about unmatched patterns should only be printed once. +# +# And the go command should be able to keep track of all this! +go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz... +stdout 'example.com/m/useunicode: \[all \.\.\. example.com/m/... ./...\]' +stdout 'example.com/m/useunsafe: \[all \.\.\. example.com/m/... ./...\]' +[cgo] stdout 'example.com/m/useC: \[all \.\.\. example.com/m/... ./...\]' +[!cgo] ! stdout example.com/m/useC +stdout 'example.com/unused/useerrors: \[\.\.\.\]' # but not "all" +stdout 'example.com/m/nested/useencoding: \[\.\.\. example.com/m/...\]' # but NOT "all" or "./..." +stdout '^unicode: \[all \.\.\.\]' +stdout '^unsafe: \[all \.\.\.\]' +stdout 'index/suffixarray: \[\.\.\.\]' +! stdout cmd/pprof # golang.org/issue/26924 + +stderr -count=1 '^go: warning: "./xyz..." matched no packages$' + +env CGO_ENABLED=0 +go list -f '{{.ImportPath}}: {{.Match}}' all ... example.com/m/... ./... ./xyz... +! stdout example.com/m/useC + +-- m/go.mod -- +module example.com/m + +require example.com/unused v0.0.0 // indirect +replace example.com/unused => ../unused + +require example.com/m/nested v0.0.0 // indirect +replace example.com/m/nested => ../nested + +-- m/useC/useC.go -- +package useC +import _ "C" // "C" is a pseudo-package, not an actual one +-- m/useunicode/useunicode.go -- +package useunicode +import _ "unicode" +-- m/useunsafe/useunsafe.go -- +package useunsafe +import _ "unsafe" + +-- unused/go.mod -- +module example.com/unused +-- unused/useerrors/useerrors.go -- +package useerrors +import _ "errors" + +-- nested/go.mod -- +module example.com/m/nested +-- nested/useencoding/useencoding.go -- +package useencoding +import _ "encoding" diff --git a/src/cmd/go/testdata/script/mod_query.txt b/src/cmd/go/testdata/script/mod_query.txt new file mode 100644 index 0000000000..4baaaa89ed --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query.txt @@ -0,0 +1,24 @@ +env GO111MODULE=on + +go list -m -versions rsc.io/quote +stdout '^rsc.io/quote v1.0.0 v1.1.0 v1.2.0 v1.2.1 v1.3.0 v1.4.0 v1.5.0 v1.5.1 v1.5.2 v1.5.3-pre1$' + +# latest rsc.io/quote should be v1.5.2 not v1.5.3-pre1 +go list -m rsc.io/quote@latest +stdout 'rsc.io/quote v1.5.2$' + +go list -m rsc.io/quote@>v1.5.2 +stdout 'rsc.io/quote v1.5.3-pre1$' + +go list -m rsc.io/quote@v1.5.3 +stderr 'go list -m rsc.io/quote: no matching versions for query ">v1.5.3"' + +go list -m -e -f '{{.Error.Err}}' rsc.io/quote@>v1.5.3 +stdout 'no matching versions for query ">v1.5.3"' + +-- go.mod -- +module x +require rsc.io/quote v1.0.0 diff --git a/src/cmd/go/testdata/script/mod_query_exclude.txt b/src/cmd/go/testdata/script/mod_query_exclude.txt new file mode 100644 index 0000000000..a64a8e1086 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_query_exclude.txt @@ -0,0 +1,26 @@ +env GO111MODULE=on + +# get excluded version +cp go.mod1 go.mod +! go get rsc.io/quote@v1.5.0 +stderr 'rsc.io/quote@v1.5.0 excluded' + +# get non-excluded version +cp go.mod1 go.mod +go get rsc.io/quote@v1.5.1 +stderr 'rsc.io/quote v1.5.1' + +# get range with excluded version +cp go.mod1 go.mod +go get rsc.io/quote@>=v1.5 +go list -m ...quote +stdout 'rsc.io/quote v1.5.[1-9]' + +-- go.mod1 -- +module x +exclude rsc.io/quote v1.5.0 + +-- x.go -- +package x +import _ "rsc.io/quote" + diff --git a/src/cmd/go/testdata/script/mod_readonly.txt b/src/cmd/go/testdata/script/mod_readonly.txt new file mode 100644 index 0000000000..1b5932e441 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_readonly.txt @@ -0,0 +1,42 @@ +env GO111MODULE=on + +# -mod=readonly must not resolve missing modules nor update go.mod +# +# TODO(bcmills): 'go list' should suffice, but today it does not fail due to +# unresolved imports. When that is fixed, use 'go list' instead of 'go list all'. +env GOFLAGS=-mod=readonly +go mod edit -fmt +cp go.mod go.mod.empty +! go list all +stderr 'import lookup disabled by -mod=readonly' +cmp go.mod go.mod.empty + +# update go.mod - go get allowed +go get rsc.io/quote +grep rsc.io/quote go.mod + +# update go.mod - go mod tidy allowed +cp go.mod.empty go.mod +go mod tidy + +# -mod=readonly must succeed once go.mod is up-to-date... +go list + +# ... even if it needs downloads +go clean -modcache +go list + +# -mod=readonly should reject inconsistent go.mod files +# (ones that would be rewritten). +go mod edit -require rsc.io/sampler@v1.2.0 +cp go.mod go.mod.inconsistent +! go list +stderr 'go: updates to go.mod needed, disabled by -mod=readonly' +cmp go.mod go.mod.inconsistent + +-- go.mod -- +module m + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_replace.txt b/src/cmd/go/testdata/script/mod_replace.txt new file mode 100644 index 0000000000..5894ed69f3 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_replace.txt @@ -0,0 +1,87 @@ +env GO111MODULE=on + +go build -o a1.exe . +exec ./a1.exe +stdout 'Don''t communicate by sharing memory' + +# Modules can be replaced by local packages. +go mod edit -replace=rsc.io/quote/v3=./local/rsc.io/quote/v3 +go build -o a2.exe . +exec ./a2.exe +stdout 'Concurrency is not parallelism.' + +# The module path of the replacement doesn't need to match. +# (For example, it could be a long-running fork with its own import path.) +go mod edit -replace=rsc.io/quote/v3=./local/not-rsc.io/quote/v3 +go build -o a3.exe . +exec ./a3.exe +stdout 'Clear is better than clever.' + +# However, the same module can't be used as two different paths. +go mod edit -dropreplace=rsc.io/quote/v3 -replace=not-rsc.io/quote/v3@v3.0.0=rsc.io/quote/v3@v3.0.0 -require=not-rsc.io/quote/v3@v3.0.0 +! go build -o a4.exe . +stderr 'rsc.io/quote/v3@v3.0.0 used for two different module paths \(not-rsc.io/quote/v3 and rsc.io/quote/v3\)' + +-- go.mod -- +module quoter + +require rsc.io/quote/v3 v3.0.0 + +-- main.go -- +package main + +import ( + "fmt" + "rsc.io/quote/v3" +) + +func main() { + fmt.Println(quote.GoV3()) +} + +-- local/rsc.io/quote/v3/go.mod -- +module rsc.io/quote/v3 + +require rsc.io/sampler v1.3.0 + +-- local/rsc.io/quote/v3/quote.go -- +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package quote collects pithy sayings. +package quote + +import "rsc.io/sampler" + +// Hello returns a greeting. +func HelloV3() string { + return sampler.Hello() +} + +// Glass returns a useful phrase for world travelers. +func GlassV3() string { + // See http://www.oocities.org/nodotus/hbglass.html. + return "I can eat glass and it doesn't hurt me." +} + +// Go returns a REPLACED Go proverb. +func GoV3() string { + return "Concurrency is not parallelism." +} + +// Opt returns a optimization truth. +func OptV3() string { + // Wisdom from ken. + return "If a program is too slow, it must have a loop." +} + +-- local/not-rsc.io/quote/v3/go.mod -- +module not-rsc.io/quote/v3 + +-- local/not-rsc.io/quote/v3/quote.go -- +package quote + +func GoV3() string { + return "Clear is better than clever." +} diff --git a/src/cmd/go/testdata/script/mod_require_exclude.txt b/src/cmd/go/testdata/script/mod_require_exclude.txt new file mode 100644 index 0000000000..60f7e3fa91 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_require_exclude.txt @@ -0,0 +1,33 @@ +# build with no newer version to satisfy exclude +env GO111MODULE=on +! go list -m all +stderr 'no newer version available' + +# build with newer version available +cp go.mod2 go.mod +go list -m all +stdout 'rsc.io/quote v1.5.2' + +# build with excluded newer version +cp go.mod3 go.mod +go list -m all +stdout 'rsc.io/quote v1.5.1' + +-- x.go -- +package x +import _ "rsc.io/quote" + +-- go.mod -- +module x +exclude rsc.io/sampler latest +require rsc.io/sampler latest + +-- go.mod2 -- +module x +exclude rsc.io/quote v1.5.1 +require rsc.io/quote v1.5.1 + +-- go.mod3 -- +module x +exclude rsc.io/quote v1.5.2 +require rsc.io/quote v1.5.1 diff --git a/src/cmd/go/testdata/script/mod_run_internal.txt b/src/cmd/go/testdata/script/mod_run_internal.txt new file mode 100644 index 0000000000..653ad282be --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_internal.txt @@ -0,0 +1,46 @@ +env GO111MODULE=on + +go list -e -f '{{.Incomplete}}' runbad1.go +stdout true +! go run runbad1.go +stderr 'use of internal package m/x/internal not allowed' + +go list -e -f '{{.Incomplete}}' runbad2.go +stdout true +! go run runbad2.go +stderr 'use of internal package m/x/internal/y not allowed' + +go list -e -f '{{.Incomplete}}' runok.go +stdout false +go run runok.go + +-- go.mod -- +module m + +-- x/internal/internal.go -- +package internal + +-- x/internal/y/y.go -- +package y + +-- internal/internal.go -- +package internal + +-- internal/z/z.go -- +package z + +-- runbad1.go -- +package main +import _ "m/x/internal" +func main() {} + +-- runbad2.go -- +package main +import _ "m/x/internal/y" +func main() {} + +-- runok.go -- +package main +import _ "m/internal" +import _ "m/internal/z" +func main() {} diff --git a/src/cmd/go/testdata/script/mod_run_path.txt b/src/cmd/go/testdata/script/mod_run_path.txt new file mode 100644 index 0000000000..4369ee4131 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_run_path.txt @@ -0,0 +1,15 @@ +# Test that go run does not get confused by conflict +# between go.mod's module path and what you'd +# expect from GOPATH. golang.org/issue/26046. + +env GO111MODULE=on + +cd $GOPATH/src/example.com/hello +go run main.go + +-- $GOPATH/src/example.com/hello/go.mod -- +module example.com/hello/v2 + +-- $GOPATH/src/example.com/hello/main.go -- +package main +func main() {} diff --git a/src/cmd/go/testdata/script/mod_std_vendor.txt b/src/cmd/go/testdata/script/mod_std_vendor.txt new file mode 100644 index 0000000000..36d4ffca9e --- /dev/null +++ b/src/cmd/go/testdata/script/mod_std_vendor.txt @@ -0,0 +1,19 @@ +env GO111MODULE=on + +go list -f '{{.TestImports}}' +stdout net/http # from .TestImports + +go list -test -f '{{.Deps}}' +stdout golang_org/x/crypto # dep of .TestImports + +-- go.mod -- +module m + +-- x.go -- +package x + +-- x_test.go -- +package x +import "testing" +import _ "net/http" +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/mod_test.txt b/src/cmd/go/testdata/script/mod_test.txt new file mode 100644 index 0000000000..caeb25ada8 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_test.txt @@ -0,0 +1,119 @@ +env GO111MODULE=on + +# A test in the module's root package should work. +cd a/ +cp go.mod.empty go.mod +go test +stdout PASS + +cp go.mod.empty go.mod +go list -deps +! stdout ^testing$ + +# list all should include test dependencies, like testing +cp go.mod.empty go.mod +go list all +stdout ^testing$ +stdout ^rsc.io/quote$ +stdout ^rsc.io/testonly$ + +# list -deps -tests should also include testing +# but not deps of tests of deps (rsc.io/testonly). +go list -deps -test +stdout ^testing$ +stdout ^rsc.io/quote$ +! stdout ^rsc.io/testonly$ + +# list -test all should succeed +cp go.mod.empty go.mod +go list -test all +stdout '^testing' + +cp go.mod.empty go.mod +go test +stdout PASS + +# A test with the "_test" suffix in the module root should also work. +cd ../b/ +go test +stdout PASS + +# A test with the "_test" suffix of a *package* with a "_test" suffix should +# even work (not that you should ever do that). +cd ../c_test +go test +stdout PASS + +cd ../d_test +go test +stdout PASS + +-- a/go.mod.empty -- +module example.com/user/a + +-- a/a.go -- +package a + +-- a/a_test.go -- +package a + +import "testing" +import _ "rsc.io/quote" + +func Test(t *testing.T) {} + +-- b/go.mod -- +module example.com/user/b + +-- b/b.go -- +package b + +-- b/b_test.go -- +package b_test + +import "testing" + +func Test(t *testing.T) {} + +-- c_test/go.mod -- +module example.com/c_test + +-- c_test/umm.go -- +// Package c_test is the non-test package for its import path! +package c_test + +-- c_test/c_test_test.go -- +package c_test_test + +import "testing" + +func Test(t *testing.T) {} + +-- d_test/go.mod -- +// Package d is an ordinary package in a deceptively-named directory. +module example.com/d + +-- d_test/d.go -- +package d + +-- d_test/d_test.go -- +package d_test + +import "testing" + +func Test(t *testing.T) {} + +-- e/go.mod -- +module example.com/e_test + +-- e/wat.go -- +// Package e_test is the non-test package for its import path, +// in a deceptively-named directory! +package e_test + +-- e/e_test.go -- +package e_test_test + +import "testing" + +func Test(t *testing.T) {} diff --git a/src/cmd/go/testdata/script/mod_tidy.txt b/src/cmd/go/testdata/script/mod_tidy.txt new file mode 100644 index 0000000000..449aa073a7 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy.txt @@ -0,0 +1,64 @@ +env GO111MODULE=on + +# tidy removes unused y, but everything else is used +go mod tidy -v +stderr '^unused y.1' +! stderr '^unused [^y]' + +go list -m all +! stdout '^y' +stdout '^w.1 v1.2.0' +stdout '^z.1 v1.2.0' + +# empty tidy should not crash +cd triv +go mod tidy + +-- go.mod -- +module m + +require ( + x.1 v1.0.0 + y.1 v1.0.0 + w.1 v1.2.0 +) + +replace x.1 v1.0.0 => ./x +replace y.1 v1.0.0 => ./y +replace z.1 v1.1.0 => ./z +replace z.1 v1.2.0 => ./z +replace w.1 => ./w + +-- m.go -- +package m + +import _ "x.1" +import _ "z.1/sub" + +-- w/go.mod -- +module w + +-- w/w.go -- +package w + +-- x/go.mod -- +module x +require w.1 v1.1.0 +require z.1 v1.1.0 + +-- x/x.go -- +package x +import _ "w.1" + +-- y/go.mod -- +module y +require z.1 v1.2.0 + +-- z/go.mod -- +module z + +-- z/sub/sub.go -- +package sub + +-- triv/go.mod -- +module triv diff --git a/src/cmd/go/testdata/script/mod_tidy_quote.txt b/src/cmd/go/testdata/script/mod_tidy_quote.txt new file mode 100644 index 0000000000..423c7c246f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_quote.txt @@ -0,0 +1,26 @@ +# Check that mod tidy does not introduce repeated +# require statements when input go.mod has quoted requirements. +env GO111MODULE=on + +go mod tidy +grep -count=1 rsc.io/quote go.mod + +cp go.mod2 go.mod +go mod tidy +grep -count=1 rsc.io/quote go.mod + + +-- go.mod -- +module x + +-- x.go -- +package x +import "rsc.io/quote" +func main() { _ = quote.Hello } + +-- go.mod2 -- +module x +require ( + "rsc.io/sampler" v1.3.0 + "rsc.io/quote" v1.5.2 +) diff --git a/src/cmd/go/testdata/script/mod_tidy_sum.txt b/src/cmd/go/testdata/script/mod_tidy_sum.txt new file mode 100644 index 0000000000..5a15818543 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_tidy_sum.txt @@ -0,0 +1,33 @@ +env GO111MODULE=on + +# go.sum should list directly used modules and dependencies +go get rsc.io/quote@v1.5.2 +go mod tidy +grep rsc.io/sampler go.sum + +# go.sum should not normally lose old entries +go get rsc.io/quote@v1.0.0 +grep 'rsc.io/quote v1.0.0' go.sum +grep 'rsc.io/quote v1.5.2' go.sum +grep rsc.io/sampler go.sum + +# go mod tidy should clear dead entries from go.sum +go mod tidy +grep 'rsc.io/quote v1.0.0' go.sum +! grep 'rsc.io/quote v1.5.2' go.sum +! grep rsc.io/sampler go.sum + +# go.sum with no entries is OK to keep +# (better for version control not to delete and recreate.) +cp x.go.noimports x.go +go mod tidy +exists go.sum +! grep . go.sum + +-- go.mod -- +module x +-- x.go -- +package x +import _ "rsc.io/quote" +-- x.go.noimports -- +package x diff --git a/src/cmd/go/testdata/script/mod_upgrade_patch.txt b/src/cmd/go/testdata/script/mod_upgrade_patch.txt new file mode 100644 index 0000000000..3c27cdbf7b --- /dev/null +++ b/src/cmd/go/testdata/script/mod_upgrade_patch.txt @@ -0,0 +1,29 @@ +env GO111MODULE=on + +go list -m all +stdout '^rsc.io/quote v1.4.0' +stdout '^rsc.io/sampler v1.0.0' + +# get -u=patch rsc.io/quote should take latest quote & patch update its deps +go get -m -u=patch rsc.io/quote +go list -m all +stdout '^rsc.io/quote v1.5.2' +stdout '^rsc.io/sampler v1.3.1' +stdout '^golang.org/x/text v0.0.0-' + +# get -u=patch quote@v1.2.0 should take that version of quote & patch update its deps +go get -m -u=patch rsc.io/quote@v1.2.0 +go list -m all +stdout '^rsc.io/quote v1.2.0' +stdout '^rsc.io/sampler v1.3.1' +stdout '^golang.org/x/text v0.0.0-' + +# get -u=patch with no args applies to all deps +go get -m -u=patch +go list -m all +stdout '^rsc.io/quote v1.2.1' + +-- go.mod -- +module x +require rsc.io/quote v1.4.0 + diff --git a/src/cmd/go/testdata/script/mod_vcs_missing.txt b/src/cmd/go/testdata/script/mod_vcs_missing.txt new file mode 100644 index 0000000000..fb146b4415 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vcs_missing.txt @@ -0,0 +1,11 @@ +[exec:bzr] skip 'tests NOT having bzr' +[!net] skip + +env GO111MODULE=on +env GOPROXY= + +! go list launchpad.net/gocheck +stderr '"bzr": executable file not found' + +-- go.mod -- +module m diff --git a/src/cmd/go/testdata/script/mod_vendor.txt b/src/cmd/go/testdata/script/mod_vendor.txt new file mode 100644 index 0000000000..b3769a8504 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor.txt @@ -0,0 +1,230 @@ +env GO111MODULE=on + +go list -m all +stdout '^x v1.0.0 => ./x' +stdout '^w' + +[!short] go build +[!short] ! go build -mod=vendor + +go list -f {{.Dir}} x +stdout 'src[\\/]x' + +go mod vendor -v +stderr '^# x v1.0.0 => ./x' +stderr '^x' +stderr '^# y v1.0.0 => ./y' +stderr '^y' +stderr '^# z v1.0.0 => ./z' +stderr '^z' +! stderr '^w' + +go list -f {{.Dir}} x +stdout 'src[\\/]x' + +go list -f {{.Dir}} -m x +stdout 'src[\\/]x' + +go list -mod=vendor -f {{.Dir}} x +stdout 'src[\\/]vendor[\\/]x' + +go list -mod=vendor -f {{.Dir}} -m x +stdout 'src[\\/]vendor[\\/]x' + +go list -f {{.Dir}} -m w +stdout 'src[\\/]w' + +! go list -mod=vendor -f {{.Dir}} w +stderr 'src[\\/]vendor[\\/]w' + +! exists vendor/x/testdata +! exists vendor/a/foo/bar/b/main_test.go + +exists vendor/a/foo/AUTHORS.txt +exists vendor/a/foo/CONTRIBUTORS +exists vendor/a/foo/LICENSE +exists vendor/a/foo/PATENTS +exists vendor/a/foo/COPYING +exists vendor/a/foo/COPYLEFT +exists vendor/x/NOTICE! +exists vendor/mysite/myname/mypkg/LICENSE.txt + +! exists vendor/a/foo/licensed-to-kill +! exists vendor/w +! exists vendor/w/LICENSE +! exists vendor/x/x2 +! exists vendor/x/x2/LICENSE + +[short] stop + +go build +go build -mod=vendor +go test -mod=vendor . ./subdir +go test -mod=vendor ./... + +-- go.mod -- +module m + +require ( + a v1.0.0 + mysite/myname/mypkg v1.0.0 + w v1.0.0 // indirect + x v1.0.0 + y v1.0.0 + z v1.0.0 +) + +replace ( + a v1.0.0 => ./a + mysite/myname/mypkg v1.0.0 => ./mypkg + w v1.0.0 => ./w + x v1.0.0 => ./x + y v1.0.0 => ./y + z v1.0.0 => ./z +) + +-- a/foo/AUTHORS.txt -- +-- a/foo/CONTRIBUTORS -- +-- a/foo/LICENSE -- +-- a/foo/PATENTS -- +-- a/foo/COPYING -- +-- a/foo/COPYLEFT -- +-- a/foo/licensed-to-kill -- +-- w/LICENSE -- +-- x/NOTICE! -- +-- x/x2/LICENSE -- +-- mypkg/LICENSE.txt -- + +-- a/foo/bar/b/main.go -- +package b +-- a/foo/bar/b/main_test.go -- +package b + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/main.go -- +package c +-- a/foo/bar/c/main_test.go -- +package c + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../../../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/testdata/1 -- +-- a/foo/bar/testdata/1 -- +-- a/go.mod -- +module a +-- a/main.go -- +package a +-- a/main_test.go -- +package a + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/testdata/1 -- +-- appengine.go -- +// +build appengine + +package m + +import _ "appengine" +import _ "appengine/datastore" +-- nonexistent.go -- +// +build alternatereality + +package m + +import _ "nonexistent.rsc.io" +-- mypkg/go.mod -- +module me +-- mypkg/mydir/d.go -- +package mydir +-- subdir/v1_test.go -- +package m + +import _ "mysite/myname/mypkg/mydir" +-- testdata1.go -- +package m + +import _ "a" +-- testdata2.go -- +package m + +import _ "a/foo/bar/b" +import _ "a/foo/bar/c" +-- v1.go -- +package m + +import _ "x" +-- v2.go -- +// +build abc + +package mMmMmMm + +import _ "y" +-- v3.go -- +// +build !abc + +package m + +import _ "z" +-- v4.go -- +// +build notmytag + +package m + +import _ "x/x1" +-- w/go.mod -- +module w +-- w/w.go -- +package w +-- x/go.mod -- +module x +-- x/testdata/x.txt -- +placeholder - want directory with no go files +-- x/x.go -- +package x +-- x/x1/x1.go -- +// +build notmytag + +package x1 +-- x/x2/dummy.txt -- +dummy +-- x/x_test.go -- +package x + +import _ "w" +-- y/go.mod -- +module y +-- y/y.go -- +package y +-- z/go.mod -- +module z +-- z/z.go -- +package z diff --git a/src/cmd/go/testdata/script/mod_vendor_build.txt b/src/cmd/go/testdata/script/mod_vendor_build.txt new file mode 100644 index 0000000000..7b304dbb70 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_build.txt @@ -0,0 +1,27 @@ +env GO111MODULE=on + +# initial conditions: using sampler v1.3.0, not listed in go.mod. +go list -deps +stdout rsc.io/sampler +! grep 'rsc.io/sampler v1.3.0' go.mod + +# update to v1.3.1, now indirect in go.mod. +go get rsc.io/sampler@v1.3.1 +grep 'rsc.io/sampler v1.3.1 // indirect' go.mod +cp go.mod go.mod.good + +# vendoring can but should not need to make changes. +go mod vendor +cmp go.mod go.mod.good + +# go list -mod=vendor (or go build -mod=vendor) must not modify go.mod. +# golang.org/issue/26704 +go list -mod=vendor +cmp go.mod go.mod.good + +-- go.mod -- +module m + +-- x.go -- +package x +import _ "rsc.io/quote" diff --git a/src/cmd/go/testdata/script/mod_vendor_nodeps.txt b/src/cmd/go/testdata/script/mod_vendor_nodeps.txt new file mode 100644 index 0000000000..e9a84ca986 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_vendor_nodeps.txt @@ -0,0 +1,9 @@ +env GO111MODULE=on + +go mod vendor +stderr '^go: no dependencies to vendor' + +-- go.mod -- +module x +-- x.go -- +package x diff --git a/src/cmd/go/testdata/script/mod_verify.txt b/src/cmd/go/testdata/script/mod_verify.txt new file mode 100644 index 0000000000..50c9b4a437 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_verify.txt @@ -0,0 +1,85 @@ +env GO111MODULE=on + +# With good go.sum, verify succeeds by avoiding download. +cp go.sum.good go.sum +go mod verify +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With bad go.sum, verify succeeds by avoiding download. +cp go.sum.bad go.sum +go mod verify +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With bad go.sum, sync (which must download) fails. +# Even if the bad sum is in the old legacy go.modverify file. +rm go.sum +cp go.sum.bad go.modverify +! go mod tidy +stderr 'checksum mismatch' +! exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip + +# With good go.sum, sync works (and moves go.modverify to go.sum). +rm go.sum +cp go.sum.good go.modverify +go mod tidy +exists $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.zip +exists $GOPATH/pkg/mod/rsc.io/quote@v1.1.0/quote.go +! exists go.modverify + +# go.sum should have the new checksum for go.mod +grep '^rsc.io/quote v1.1.0/go.mod ' go.sum + +# verify should work +go mod verify + +# basic loading of module graph should detect incorrect go.mod files. +go mod graph +cp go.sum.bad2 go.sum +! go mod graph +stderr 'go.mod: checksum mismatch' + +# go.sum should be created and updated automatically. +rm go.sum +go mod graph +exists go.sum +grep '^rsc.io/quote v1.1.0/go.mod ' go.sum +! grep '^rsc.io/quote v1.1.0 ' go.sum + +go mod tidy +grep '^rsc.io/quote v1.1.0/go.mod ' go.sum +grep '^rsc.io/quote v1.1.0 ' go.sum + +# sync should ignore missing ziphash; verify should not +rm $GOPATH/pkg/mod/cache/download/rsc.io/quote/@v/v1.1.0.ziphash +go mod tidy +! go mod verify + +# Packages below module root should not be mentioned in go.sum. +rm go.sum +go mod edit -droprequire rsc.io/quote +go list rsc.io/quote/buggy # re-resolves import path and updates go.mod +grep '^rsc.io/quote v1.5.2/go.mod ' go.sum +! grep buggy go.sum + +# non-existent packages below module root should not be mentioned in go.sum +go mod edit -droprequire rsc.io/quote +! go list rsc.io/quote/morebuggy +grep '^rsc.io/quote v1.5.2/go.mod ' go.sum +! grep buggy go.sum + +-- go.mod -- +module x +require rsc.io/quote v1.1.0 + +-- x.go -- +package x +import _ "rsc.io/quote" + +-- go.sum.good -- +rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/0c= + +-- go.sum.bad -- +rsc.io/quote v1.1.0 h1:a3YaZoizPtXyv6ZsJ74oo2L4/bwOSTKMY7MAyo4O/1c= + +-- go.sum.bad2 -- +rsc.io/quote v1.1.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl1= diff --git a/src/cmd/go/testdata/script/mod_versions.txt b/src/cmd/go/testdata/script/mod_versions.txt new file mode 100644 index 0000000000..fd5e5c589d --- /dev/null +++ b/src/cmd/go/testdata/script/mod_versions.txt @@ -0,0 +1,14 @@ +# Test rejection of pkg@version in GOPATH mode. +env GO111MODULE=off +! go get rsc.io/quote@v1.5.1 +stderr 'cannot use path@version syntax in GOPATH mode' +! go build rsc.io/quote@v1.5.1 +stderr 'cannot use path@version syntax in GOPATH mode' + +env GO111MODULE=on +cd x +! go build rsc.io/quote@v1.5.1 +stderr 'can only use path@version syntax with ''go get''' + +-- x/go.mod -- +module x diff --git a/src/cmd/go/testdata/script/mod_why.txt b/src/cmd/go/testdata/script/mod_why.txt new file mode 100644 index 0000000000..4d556fc73f --- /dev/null +++ b/src/cmd/go/testdata/script/mod_why.txt @@ -0,0 +1,114 @@ +env GO111MODULE=on + +go list -test all +stdout rsc.io/quote +stdout golang.org/x/text/language + +# why a package? +go mod why golang.org/x/text/language +cmp stdout why-language.txt + +# why a module? +go mod why -m golang.org... +cmp stdout why-text-module.txt + +# why a package used only in tests? +go mod why rsc.io/testonly +cmp stdout why-testonly.txt + +# why a module used only in tests? +go mod why -m rsc.io/testonly +cmp stdout why-testonly.txt + +# test package not needed +go mod why golang.org/x/text/unused +cmp stdout why-unused.txt + +# vendor doesn't use packages used only in tests. +go mod why -vendor rsc.io/testonly +cmp stdout why-vendor.txt + +# vendor doesn't use modules used only in tests. +go mod why -vendor -m rsc.io/testonly +cmp stdout why-vendor-module.txt + +# test multiple packages +go mod why golang.org/x/text/language golang.org/x/text/unused +cmp stdout why-both.txt + +# test multiple modules +go mod why -m rsc.io/quote rsc.io/sampler +cmp stdout why-both-module.txt + +-- go.mod -- +module mymodule +require rsc.io/quote v1.5.2 + +-- x/x.go -- +package x +import _ "mymodule/z" + +-- y/y.go -- +package y + +-- y/y_test.go -- +package y +import _ "rsc.io/quote" + +-- z/z.go -- +package z +import _ "mymodule/y" + + +-- why-language.txt -- +# golang.org/x/text/language +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language +-- why-unused.txt -- +# golang.org/x/text/unused +(main module does not need package golang.org/x/text/unused) +-- why-text-module.txt -- +# golang.org/x/text +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language +-- why-testonly.txt -- +# rsc.io/testonly +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +rsc.io/sampler.test +rsc.io/testonly +-- why-vendor.txt -- +# rsc.io/testonly +(main module does not need to vendor package rsc.io/testonly) +-- why-vendor-module.txt -- +# rsc.io/testonly +(main module does not need to vendor module rsc.io/testonly) +-- why-both.txt -- +# golang.org/x/text/language +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler +golang.org/x/text/language + +# golang.org/x/text/unused +(main module does not need package golang.org/x/text/unused) +-- why-both-module.txt -- +# rsc.io/quote +mymodule/y +mymodule/y.test +rsc.io/quote + +# rsc.io/sampler +mymodule/y +mymodule/y.test +rsc.io/quote +rsc.io/sampler diff --git a/src/cmd/go/testdata/script/pattern_syntax_error.txt b/src/cmd/go/testdata/script/pattern_syntax_error.txt new file mode 100644 index 0000000000..8e6549b5c5 --- /dev/null +++ b/src/cmd/go/testdata/script/pattern_syntax_error.txt @@ -0,0 +1,10 @@ +# patterns match directories with syntax errors +! go list ./... +! go build ./... +! go install ./... + +-- mypkg/x.go -- +package mypkg + +-- mypkg/y.go -- +pkg mypackage diff --git a/src/cmd/go/testdata/script/run_hello.txt b/src/cmd/go/testdata/script/run_hello.txt new file mode 100644 index 0000000000..8c4c1c1683 --- /dev/null +++ b/src/cmd/go/testdata/script/run_hello.txt @@ -0,0 +1,7 @@ +# hello world +go run hello.go +stderr 'hello world' + +-- hello.go -- +package main +func main() { println("hello world") } diff --git a/src/cmd/go/testdata/script/test_badtest.txt b/src/cmd/go/testdata/script/test_badtest.txt new file mode 100644 index 0000000000..42fcfed2fc --- /dev/null +++ b/src/cmd/go/testdata/script/test_badtest.txt @@ -0,0 +1,30 @@ +! go test badtest/... +! stdout ^ok +stdout ^FAIL\tbadtest/badexec +stdout ^FAIL\tbadtest/badsyntax +stdout ^FAIL\tbadtest/badvar + +-- badtest/badexec/x_test.go -- +package badexec + +func init() { + panic("badexec") +} + +-- badtest/badsyntax/x.go -- +package badsyntax + +-- badtest/badsyntax/x_test.go -- +package badsyntax + +func func func func func! + +-- badtest/badvar/x.go -- +package badvar + +-- badtest/badvar/x_test.go -- +package badvar_test + +func f() { + _ = notdefined +} diff --git a/src/cmd/go/testdata/script/test_compile_binary.txt b/src/cmd/go/testdata/script/test_compile_binary.txt new file mode 100644 index 0000000000..6c01bc5729 --- /dev/null +++ b/src/cmd/go/testdata/script/test_compile_binary.txt @@ -0,0 +1,6 @@ +! go test -c compile_binary/... +stderr 'build comment' + +-- compile_binary/foo_test.go -- +//+build foo +package foo diff --git a/src/cmd/go/testdata/script/vendor_complex.txt b/src/cmd/go/testdata/script/vendor_complex.txt new file mode 100644 index 0000000000..6513451df8 --- /dev/null +++ b/src/cmd/go/testdata/script/vendor_complex.txt @@ -0,0 +1,73 @@ +# smoke test for complex build configuration +go build -o complex.exe complex +[exec:gccgo] go build -compiler=gccgo -o complex.exe complex + +-- complex/main.go -- +package main + +import ( + _ "complex/nest/sub/test12" + _ "complex/nest/sub/test23" + "complex/w" + "v" +) + +func main() { + println(v.Hello + " " + w.World) +} + +-- complex/nest/sub/test12/p.go -- +package test12 + +// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v1" + "v2" +) + +const x = v1.ComplexNestVendorV1 +const y = v2.ComplexNestSubVendorV2 + +-- complex/nest/sub/test23/p.go -- +package test23 + +// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). + +import ( + "v2" + "v3" +) + +const x = v3.ComplexNestVendorV3 +const y = v2.ComplexNestSubVendorV2 + +-- complex/nest/sub/vendor/v2/v2.go -- +package v2 + +const ComplexNestSubVendorV2 = true + +-- complex/nest/vendor/v1/v1.go -- +package v1 + +const ComplexNestVendorV1 = true + +-- complex/nest/vendor/v2/v2.go -- +package v2 + +const ComplexNestVendorV2 = true + +-- complex/nest/vendor/v3/v3.go -- +package v3 + +const ComplexNestVendorV3 = true + +-- complex/vendor/v/v.go -- +package v + +const Hello = "hello" + +-- complex/w/w.go -- +package w + +const World = "world" diff --git a/src/cmd/go/testdata/src/badtest/badexec/x_test.go b/src/cmd/go/testdata/src/badtest/badexec/x_test.go deleted file mode 100644 index 12f5051712..0000000000 --- a/src/cmd/go/testdata/src/badtest/badexec/x_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package badexec - -func init() { - panic("badexec") -} diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x.go b/src/cmd/go/testdata/src/badtest/badsyntax/x.go deleted file mode 100644 index c8a5407a5a..0000000000 --- a/src/cmd/go/testdata/src/badtest/badsyntax/x.go +++ /dev/null @@ -1 +0,0 @@ -package badsyntax diff --git a/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go b/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go deleted file mode 100644 index 5be10745d9..0000000000 --- a/src/cmd/go/testdata/src/badtest/badsyntax/x_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package badsyntax - -func func func func func! diff --git a/src/cmd/go/testdata/src/badtest/badvar/x.go b/src/cmd/go/testdata/src/badtest/badvar/x.go deleted file mode 100644 index fdd46c4c72..0000000000 --- a/src/cmd/go/testdata/src/badtest/badvar/x.go +++ /dev/null @@ -1 +0,0 @@ -package badvar diff --git a/src/cmd/go/testdata/src/badtest/badvar/x_test.go b/src/cmd/go/testdata/src/badtest/badvar/x_test.go deleted file mode 100644 index c67df01c5c..0000000000 --- a/src/cmd/go/testdata/src/badtest/badvar/x_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package badvar_test - -func f() { - _ = notdefined -} diff --git a/src/cmd/go/testdata/src/complex/main.go b/src/cmd/go/testdata/src/complex/main.go deleted file mode 100644 index c38df01948..0000000000 --- a/src/cmd/go/testdata/src/complex/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - _ "complex/nest/sub/test12" - _ "complex/nest/sub/test23" - "complex/w" - "v" -) - -func main() { - println(v.Hello + " " + w.World) -} diff --git a/src/cmd/go/testdata/src/complex/nest/sub/test12/p.go b/src/cmd/go/testdata/src/complex/nest/sub/test12/p.go deleted file mode 100644 index 94943ec1bb..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/sub/test12/p.go +++ /dev/null @@ -1,11 +0,0 @@ -package test12 - -// Check that vendor/v1 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). - -import ( - "v1" - "v2" -) - -const x = v1.ComplexNestVendorV1 -const y = v2.ComplexNestSubVendorV2 diff --git a/src/cmd/go/testdata/src/complex/nest/sub/test23/p.go b/src/cmd/go/testdata/src/complex/nest/sub/test23/p.go deleted file mode 100644 index 8801a4812a..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/sub/test23/p.go +++ /dev/null @@ -1,11 +0,0 @@ -package test23 - -// Check that vendor/v3 is used but vendor/v2 is NOT used (sub/vendor/v2 wins). - -import ( - "v2" - "v3" -) - -const x = v3.ComplexNestVendorV3 -const y = v2.ComplexNestSubVendorV2 diff --git a/src/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go b/src/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go deleted file mode 100644 index 2991871710..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/sub/vendor/v2/v2.go +++ /dev/null @@ -1,3 +0,0 @@ -package v2 - -const ComplexNestSubVendorV2 = true diff --git a/src/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go b/src/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go deleted file mode 100644 index a55f5290a9..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/vendor/v1/v1.go +++ /dev/null @@ -1,3 +0,0 @@ -package v1 - -const ComplexNestVendorV1 = true diff --git a/src/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go b/src/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go deleted file mode 100644 index ac94def4e3..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/vendor/v2/v2.go +++ /dev/null @@ -1,3 +0,0 @@ -package v2 - -const ComplexNestVendorV2 = true diff --git a/src/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go b/src/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go deleted file mode 100644 index abf99b9574..0000000000 --- a/src/cmd/go/testdata/src/complex/nest/vendor/v3/v3.go +++ /dev/null @@ -1,3 +0,0 @@ -package v3 - -const ComplexNestVendorV3 = true diff --git a/src/cmd/go/testdata/src/complex/vendor/v/v.go b/src/cmd/go/testdata/src/complex/vendor/v/v.go deleted file mode 100644 index bb20d86f25..0000000000 --- a/src/cmd/go/testdata/src/complex/vendor/v/v.go +++ /dev/null @@ -1,3 +0,0 @@ -package v - -const Hello = "hello" diff --git a/src/cmd/go/testdata/src/complex/w/w.go b/src/cmd/go/testdata/src/complex/w/w.go deleted file mode 100644 index a9c7fbb309..0000000000 --- a/src/cmd/go/testdata/src/complex/w/w.go +++ /dev/null @@ -1,3 +0,0 @@ -package w - -const World = "world" diff --git a/src/cmd/go/testdata/src/testnorun/p.go b/src/cmd/go/testdata/src/testnorun/p.go new file mode 100644 index 0000000000..71a9a561ef --- /dev/null +++ b/src/cmd/go/testdata/src/testnorun/p.go @@ -0,0 +1,5 @@ +package p + +func init() { + panic("go test must not link and run test binaries without tests") +} diff --git a/src/cmd/go/testdata/testonly2/t.go b/src/cmd/go/testdata/testonly2/t.go new file mode 100644 index 0000000000..82267d32e4 --- /dev/null +++ b/src/cmd/go/testdata/testonly2/t.go @@ -0,0 +1,6 @@ +// This package is not a test-only package, +// but it still matches the pattern ./testdata/testonly... when in cmd/go. + +package main + +func main() {} diff --git a/src/cmd/go/testdata/vendormod.txt b/src/cmd/go/testdata/vendormod.txt new file mode 100644 index 0000000000..1bdaf2abb0 --- /dev/null +++ b/src/cmd/go/testdata/vendormod.txt @@ -0,0 +1,160 @@ +generated by: go run savedir.go vendormod + +-- a/foo/AUTHORS.txt -- +-- a/foo/CONTRIBUTORS -- +-- a/foo/LICENSE -- +-- a/foo/PATENTS -- +-- a/foo/COPYING -- +-- a/foo/COPYLEFT -- +-- a/foo/licensed-to-kill -- +-- w/LICENSE -- +-- x/NOTICE! -- +-- x/x2/LICENSE -- +-- mypkg/LICENSE.txt -- +-- a/foo/bar/b/main.go -- +package b +-- a/foo/bar/b/main_test.go -- +package b + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/main.go -- +package c +-- a/foo/bar/c/main_test.go -- +package c + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("../../../testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/foo/bar/c/testdata/1 -- +-- a/foo/bar/testdata/1 -- +-- a/go.mod -- +module a +-- a/main.go -- +package a +-- a/main_test.go -- +package a + +import ( + "os" + "testing" +) + +func TestDir(t *testing.T) { + if _, err := os.Stat("./testdata/1"); err != nil { + t.Fatalf("testdata: %v", err) + } +} +-- a/testdata/1 -- +-- appengine.go -- +// +build appengine + +package m + +import _ "appengine" +import _ "appengine/datastore" +-- go.mod -- +module m + +require ( + a v1.0.0 + mysite/myname/mypkg v1.0.0 + w v1.0.0 // indirect + x v1.0.0 + y v1.0.0 + z v1.0.0 +) + +replace ( + a v1.0.0 => ./a + mysite/myname/mypkg v1.0.0 => ./mypkg + w v1.0.0 => ./w + x v1.0.0 => ./x + y v1.0.0 => ./y + z v1.0.0 => ./z +) +-- mypkg/go.mod -- +module me +-- mypkg/mydir/d.go -- +package mydir +-- subdir/v1_test.go -- +package m + +import _ "mysite/myname/mypkg/mydir" +-- testdata1.go -- +package m + +import _ "a" +-- testdata2.go -- +package m + +import _ "a/foo/bar/b" +import _ "a/foo/bar/c" +-- v1.go -- +package m + +import _ "x" +-- v2.go -- +// +build abc + +package mMmMmMm + +import _ "y" +-- v3.go -- +// +build !abc + +package m + +import _ "z" +-- v4.go -- +// +build notmytag + +package m + +import _ "x/x1" +-- w/go.mod -- +module w +-- w/w.go -- +package w +-- x/go.mod -- +module x +-- x/testdata/x.txt -- +placeholder - want directory with no go files +-- x/x.go -- +package x +-- x/x1/x1.go -- +// +build notmytag + +package x1 +-- x/x2/dummy.txt -- +dummy +-- x/x_test.go -- +package x + +import _ "w" +-- y/go.mod -- +module y +-- y/y.go -- +package y +-- z/go.mod -- +module z +-- z/z.go -- +package z diff --git a/src/cmd/go/testdata/vendormod/go.mod b/src/cmd/go/testdata/vendormod/go.mod deleted file mode 100644 index 6f71634253..0000000000 --- a/src/cmd/go/testdata/vendormod/go.mod +++ /dev/null @@ -1,16 +0,0 @@ -module m - -replace x v1.0.0 => ./x - -replace y v1.0.0 => ./y - -replace z v1.0.0 => ./z - -replace w v1.0.0 => ./w - -require ( - w v1.0.0 - x v1.0.0 - y v1.0.0 - z v1.0.0 -) diff --git a/src/cmd/go/testdata/vendormod/v1.go b/src/cmd/go/testdata/vendormod/v1.go deleted file mode 100644 index 6ca04a5aac..0000000000 --- a/src/cmd/go/testdata/vendormod/v1.go +++ /dev/null @@ -1,3 +0,0 @@ -package m - -import _ "x" diff --git a/src/cmd/go/testdata/vendormod/v2.go b/src/cmd/go/testdata/vendormod/v2.go deleted file mode 100644 index 8b089e4365..0000000000 --- a/src/cmd/go/testdata/vendormod/v2.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build abc - -package mMmMmMm - -import _ "y" diff --git a/src/cmd/go/testdata/vendormod/v3.go b/src/cmd/go/testdata/vendormod/v3.go deleted file mode 100644 index 318b5f0303..0000000000 --- a/src/cmd/go/testdata/vendormod/v3.go +++ /dev/null @@ -1,5 +0,0 @@ -// +build !abc - -package m - -import _ "z" diff --git a/src/cmd/go/testdata/vendormod/w/go.mod b/src/cmd/go/testdata/vendormod/w/go.mod deleted file mode 100644 index ce2a6c161c..0000000000 --- a/src/cmd/go/testdata/vendormod/w/go.mod +++ /dev/null @@ -1 +0,0 @@ -module w diff --git a/src/cmd/go/testdata/vendormod/w/w.go b/src/cmd/go/testdata/vendormod/w/w.go deleted file mode 100644 index a796c0b5f4..0000000000 --- a/src/cmd/go/testdata/vendormod/w/w.go +++ /dev/null @@ -1 +0,0 @@ -package w diff --git a/src/cmd/go/testdata/vendormod/x/go.mod b/src/cmd/go/testdata/vendormod/x/go.mod deleted file mode 100644 index c1914353d5..0000000000 --- a/src/cmd/go/testdata/vendormod/x/go.mod +++ /dev/null @@ -1 +0,0 @@ -module x diff --git a/src/cmd/go/testdata/vendormod/x/x.go b/src/cmd/go/testdata/vendormod/x/x.go deleted file mode 100644 index 823aafd071..0000000000 --- a/src/cmd/go/testdata/vendormod/x/x.go +++ /dev/null @@ -1 +0,0 @@ -package x diff --git a/src/cmd/go/testdata/vendormod/y/go.mod b/src/cmd/go/testdata/vendormod/y/go.mod deleted file mode 100644 index ac82a48598..0000000000 --- a/src/cmd/go/testdata/vendormod/y/go.mod +++ /dev/null @@ -1 +0,0 @@ -module y diff --git a/src/cmd/go/testdata/vendormod/y/y.go b/src/cmd/go/testdata/vendormod/y/y.go deleted file mode 100644 index 789ca715ec..0000000000 --- a/src/cmd/go/testdata/vendormod/y/y.go +++ /dev/null @@ -1 +0,0 @@ -package y diff --git a/src/cmd/go/testdata/vendormod/z/go.mod b/src/cmd/go/testdata/vendormod/z/go.mod deleted file mode 100644 index efc58fedd0..0000000000 --- a/src/cmd/go/testdata/vendormod/z/go.mod +++ /dev/null @@ -1 +0,0 @@ -module z diff --git a/src/cmd/go/testdata/vendormod/z/z.go b/src/cmd/go/testdata/vendormod/z/z.go deleted file mode 100644 index 46458cbddb..0000000000 --- a/src/cmd/go/testdata/vendormod/z/z.go +++ /dev/null @@ -1 +0,0 @@ -package z diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go index 0e7a633240..22aa643b00 100644 --- a/src/cmd/go/vendor_test.go +++ b/src/cmd/go/vendor_test.go @@ -332,7 +332,7 @@ func TestVendor12156(t *testing.T) { // Module legacy support does path rewriting very similar to vendoring. -func TestModLegacy(t *testing.T) { +func TestLegacyMod(t *testing.T) { tg := testgo(t) defer tg.cleanup() tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/modlegacy")) @@ -347,7 +347,7 @@ func TestModLegacy(t *testing.T) { tg.run("build", "old/p1", "new/p1") } -func TestModLegacyGet(t *testing.T) { +func TestLegacyModGet(t *testing.T) { testenv.MustHaveExternalNetwork(t) tg := testgo(t) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index d5b7be327a..ac6852f2e4 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -319,10 +319,7 @@ func backupFile(filename string, data []byte, perm os.FileMode) (string, error) } // write data to backup file - n, err := f.Write(data) - if err == nil && n < len(data) { - err = io.ErrShortWrite - } + _, err = f.Write(data) if err1 := f.Close(); err == nil { err = err1 } diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 237b86021b..e2a6208f87 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -85,6 +85,12 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { // the first and 2nd result should be identical if !bytes.Equal(b1.Bytes(), b2.Bytes()) { + // A known instance of gofmt not being idempotent + // (see Issue #24472) + if strings.HasSuffix(filename, "issue22662.go") { + t.Log("known gofmt idempotency bug (Issue #24472)") + return + } t.Errorf("gofmt %s not idempotent", filename) } } diff --git a/src/cmd/internal/buildid/note.go b/src/cmd/internal/buildid/note.go index 5895da906a..2d26ea9961 100644 --- a/src/cmd/internal/buildid/note.go +++ b/src/cmd/internal/buildid/note.go @@ -30,6 +30,7 @@ func ReadELFNote(filename, name string, typ int32) ([]byte, error) { if err != nil { return nil, err } + defer f.Close() for _, sect := range f.Sections { if sect.Type != elf.SHT_NOTE { continue diff --git a/src/cmd/internal/dwarf/dwarf.go b/src/cmd/internal/dwarf/dwarf.go index edb84498f9..96fb2b765b 100644 --- a/src/cmd/internal/dwarf/dwarf.go +++ b/src/cmd/internal/dwarf/dwarf.go @@ -8,6 +8,7 @@ package dwarf import ( + "cmd/internal/objabi" "errors" "fmt" "sort" @@ -1096,7 +1097,7 @@ func PutAbstractFunc(ctxt Context, s *FnState) error { // be rewritten, since it would change the offsets of the // child DIEs (which we're relying on in order for abstract // origin references to work). - fullname = s.Importpath + "." + s.Name[3:] + fullname = objabi.PathToPrefix(s.Importpath) + "." + s.Name[3:] } putattr(ctxt, s.Absfn, abbrev, DW_FORM_string, DW_CLS_STRING, int64(len(fullname)), fullname) diff --git a/src/cmd/internal/obj/arm/anames.go b/src/cmd/internal/obj/arm/anames.go index 86d35dec61..e419e3b73d 100644 --- a/src/cmd/internal/obj/arm/anames.go +++ b/src/cmd/internal/obj/arm/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p arm -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p arm; DO NOT EDIT. package arm diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index 9be0183edf..65647c37ae 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -594,8 +594,10 @@ const ( AHVC AIC AISB - ALDADDALD + ALDADDALB + ALDADDALH ALDADDALW + ALDADDALD ALDADDB ALDADDH ALDADDW @@ -774,9 +776,13 @@ const ( AMOVPSW AMOVPW ASWPD + ASWPALD ASWPW + ASWPALW ASWPH + ASWPALH ASWPB + ASWPALB ABEQ ABNE ABCS @@ -817,6 +823,8 @@ const ( AFCVTZUSW AFDIVD AFDIVS + AFLDPD + AFLDPS AFMOVD AFMOVS AFMULD @@ -825,6 +833,8 @@ const ( AFNEGS AFSQRTD AFSQRTS + AFSTPD + AFSTPS AFSUBD AFSUBS ASCVTFD diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index 0579e5362e..55e2b5bafb 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p arm64 -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p arm64; DO NOT EDIT. package arm64 @@ -96,8 +95,10 @@ var Anames = []string{ "HVC", "IC", "ISB", - "LDADDALD", + "LDADDALB", + "LDADDALH", "LDADDALW", + "LDADDALD", "LDADDB", "LDADDH", "LDADDW", @@ -276,9 +277,13 @@ var Anames = []string{ "MOVPSW", "MOVPW", "SWPD", + "SWPALD", "SWPW", + "SWPALW", "SWPH", + "SWPALH", "SWPB", + "SWPALB", "BEQ", "BNE", "BCS", @@ -319,6 +324,8 @@ var Anames = []string{ "FCVTZUSW", "FDIVD", "FDIVS", + "FLDPD", + "FLDPS", "FMOVD", "FMOVS", "FMULD", @@ -327,6 +334,8 @@ var Anames = []string{ "FNEGS", "FSQRTD", "FSQRTS", + "FSTPD", + "FSTPS", "FSUBD", "FSUBS", "SCVTFD", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index 192d65df96..7507976257 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -49,6 +49,7 @@ type ctxt7 struct { blitrl *obj.Prog elitrl *obj.Prog autosize int32 + extrasize int32 instoffset int64 pc int64 pool struct { @@ -218,8 +219,6 @@ var optab = []Optab{ {AFADDS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, {AFADDS, C_FREG, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, - {AFADDS, C_FCON, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, - {AFADDS, C_FCON, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0}, {AFMSUBD, C_FREG, C_FREG, C_FREG, C_FREG, 15, 4, 0, 0, 0}, {AFCMPS, C_FREG, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0}, {AFCMPS, C_FCON, C_FREG, C_NONE, C_NONE, 56, 4, 0, 0, 0}, @@ -339,9 +338,9 @@ var optab = []Optab{ {AFMOVS, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0}, {AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 64, 12, 0, 0, 0}, {AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 65, 12, 0, 0, 0}, - {AFMOVS, C_FCON, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVS, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0}, {AFMOVS, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, - {AFMOVD, C_FCON, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, + {AFMOVD, C_FCON, C_NONE, C_NONE, C_FREG, 55, 4, 0, 0, 0}, {AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 54, 4, 0, 0, 0}, {AFMOVS, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0}, {AFMOVS, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0}, @@ -519,12 +518,16 @@ var optab = []Optab{ {AMOVH, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, {AMOVB, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, {AMOVBU, C_ROFF, C_NONE, C_NONE, C_REG, 98, 4, 0, 0, 0}, + {AFMOVS, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0}, + {AFMOVD, C_ROFF, C_NONE, C_NONE, C_FREG, 98, 4, 0, 0, 0}, /* store with extended register offset */ {AMOVD, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, {AMOVW, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, {AMOVH, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, {AMOVB, C_REG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AFMOVS, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, + {AFMOVD, C_FREG, C_NONE, C_NONE, C_ROFF, 99, 4, 0, 0, 0}, /* pre/post-indexed/signed-offset load/store register pair (unscaled, signed 10-bit quad-aligned and long offset) */ @@ -773,7 +776,8 @@ func span7(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { ctxt.Diag("arm64 ops not initialized, call arm64.buildop first") } - c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset&0xffffffff) + 8} + c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym, autosize: int32(p.To.Offset & 0xffffffff), extrasize: int32(p.To.Offset >> 32)} + p.To.Offset &= 0xffffffff // extrasize is no longer needed bflag := 1 pc := int64(0) @@ -1432,7 +1436,8 @@ func (c *ctxt7) aclass(a *obj.Addr) int { // a.Offset is still relative to pseudo-SP. a.Reg = obj.REG_NONE } - c.instoffset = int64(c.autosize) + a.Offset + // The frame top 8 or 16 bytes are for FP + c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize) return autoclass(c.instoffset) case obj.NAME_PARAM: @@ -1532,7 +1537,8 @@ func (c *ctxt7) aclass(a *obj.Addr) int { // a.Offset is still relative to pseudo-SP. a.Reg = obj.REG_NONE } - c.instoffset = int64(c.autosize) + a.Offset + // The frame top 8 or 16 bytes are for FP + c.instoffset = int64(c.autosize) + a.Offset - int64(c.extrasize) case obj.NAME_PARAM: if a.Reg == REGSP { @@ -2008,11 +2014,17 @@ func buildop(ctxt *obj.Link) { oprangeset(AMOVZW, t) case ASWPD: + oprangeset(ASWPALD, t) oprangeset(ASWPB, t) oprangeset(ASWPH, t) oprangeset(ASWPW, t) - oprangeset(ALDADDALD, t) + oprangeset(ASWPALB, t) + oprangeset(ASWPALH, t) + oprangeset(ASWPALW, t) + oprangeset(ALDADDALB, t) + oprangeset(ALDADDALH, t) oprangeset(ALDADDALW, t) + oprangeset(ALDADDALD, t) oprangeset(ALDADDB, t) oprangeset(ALDADDH, t) oprangeset(ALDADDW, t) @@ -2185,14 +2197,21 @@ func buildop(ctxt *obj.Link) { AWORD, ADWORD, obj.ARET, - obj.ATEXT, - ASTP, - ASTPW, - ALDP: + obj.ATEXT: break + case ALDP: + oprangeset(AFLDPD, t) + + case ASTP: + oprangeset(AFSTPD, t) + + case ASTPW: + oprangeset(AFSTPS, t) + case ALDPW: oprangeset(ALDPSW, t) + oprangeset(AFLDPS, t) case AERET: oprangeset(AWFE, t) @@ -2440,6 +2459,9 @@ func buildop(ctxt *obj.Link) { } } +// chipfloat7() checks if the immediate constants available in FMOVS/FMOVD instructions. +// For details of the range of constants available, see +// http://infocenter.arm.com/help/topic/com.arm.doc.dui0473m/dom1359731199385.html. func (c *ctxt7) chipfloat7(e float64) int { ei := math.Float64bits(e) l := uint32(int32(ei)) @@ -2536,11 +2558,11 @@ func (c *ctxt7) checkShiftAmount(p *obj.Prog, a *obj.Addr) { if amount != 1 && amount != 0 { c.ctxt.Diag("invalid index shift amount: %v", p) } - case AMOVW, AMOVWU: + case AMOVW, AMOVWU, AFMOVS: if amount != 2 && amount != 0 { c.ctxt.Diag("invalid index shift amount: %v", p) } - case AMOVD: + case AMOVD, AFMOVD: if amount != 3 && amount != 0 { c.ctxt.Diag("invalid index shift amount: %v", p) } @@ -2744,7 +2766,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case 13: /* addop $vcon, [R], R (64 bit literal); cmp $lcon,R -> addop $lcon,R, ZR */ o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) - if !(o1 != 0) { + if o1 == 0 { break } rt := int(p.To.Reg) @@ -3005,7 +3027,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case 28: /* logop $vcon, [R], R (64 bit literal) */ o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) - if !(o1 != 0) { + if o1 == 0 { break } rt := int(p.To.Reg) @@ -3150,7 +3172,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case 34: /* mov $lacon,R */ o1 = c.omovlit(AMOVD, p, &p.From, REGTMP) - if !(o1 != 0) { + if o1 == 0 { break } o2 = c.opxrrr(p, AADD, false) @@ -3264,10 +3286,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { } switch p.As { case ABFI: - o1 = c.opbfm(p, ABFM, 64-r, s-1, rf, rt) + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, ABFM, r, s-1, rf, rt) case ABFIW: - o1 = c.opbfm(p, ABFMW, 32-r, s-1, rf, rt) + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, ABFMW, r, s-1, rf, rt) case ABFXIL: o1 = c.opbfm(p, ABFM, r, r+s-1, rf, rt) @@ -3276,10 +3304,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 = c.opbfm(p, ABFMW, r, r+s-1, rf, rt) case ASBFIZ: - o1 = c.opbfm(p, ASBFM, 64-r, s-1, rf, rt) + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, ASBFM, r, s-1, rf, rt) case ASBFIZW: - o1 = c.opbfm(p, ASBFMW, 32-r, s-1, rf, rt) + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, ASBFMW, r, s-1, rf, rt) case ASBFX: o1 = c.opbfm(p, ASBFM, r, r+s-1, rf, rt) @@ -3288,10 +3322,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 = c.opbfm(p, ASBFMW, r, r+s-1, rf, rt) case AUBFIZ: - o1 = c.opbfm(p, AUBFM, 64-r, s-1, rf, rt) + if r != 0 { + r = 64 - r + } + o1 = c.opbfm(p, AUBFM, r, s-1, rf, rt) case AUBFIZW: - o1 = c.opbfm(p, AUBFMW, 32-r, s-1, rf, rt) + if r != 0 { + r = 32 - r + } + o1 = c.opbfm(p, AUBFMW, r, s-1, rf, rt) case AUBFX: o1 = c.opbfm(p, AUBFM, r, r+s-1, rf, rt) @@ -3365,21 +3405,21 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { rt := p.RegTo2 rb := p.To.Reg switch p.As { - case ASWPD, ALDADDALD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit + case ASWPD, ASWPALD, ALDADDALD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit o1 = 3 << 30 - case ASWPW, ALDADDALW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit + case ASWPW, ASWPALW, ALDADDALW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit o1 = 2 << 30 - case ASWPH, ALDADDH, ALDANDH, ALDEORH, ALDORH: // 16-bit + case ASWPH, ASWPALH, ALDADDALH, ALDADDH, ALDANDH, ALDEORH, ALDORH: // 16-bit o1 = 1 << 30 - case ASWPB, ALDADDB, ALDANDB, ALDEORB, ALDORB: // 8-bit + case ASWPB, ASWPALB, ALDADDALB, ALDADDB, ALDANDB, ALDEORB, ALDORB: // 8-bit o1 = 0 << 30 default: c.ctxt.Diag("illegal instruction: %v\n", p) } switch p.As { - case ASWPD, ASWPW, ASWPH, ASWPB: + case ASWPD, ASWPW, ASWPH, ASWPB, ASWPALD, ASWPALW, ASWPALH, ASWPALB: o1 |= 0x20 << 10 - case ALDADDALD, ALDADDALW, ALDADDD, ALDADDW, ALDADDH, ALDADDB: + case ALDADDALD, ALDADDALW, ALDADDALH, ALDADDALB, ALDADDD, ALDADDW, ALDADDH, ALDADDB: o1 |= 0x00 << 10 case ALDANDD, ALDANDW, ALDANDH, ALDANDB: o1 |= 0x04 << 10 @@ -3389,7 +3429,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { o1 |= 0x0c << 10 } switch p.As { - case ALDADDALD, ALDADDALW: + case ALDADDALD, ALDADDALW, ALDADDALH, ALDADDALB, ASWPALD, ASWPALW, ASWPALH, ASWPALB: o1 |= 3 << 22 } o1 |= 0x1c1<<21 | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31) @@ -3447,19 +3487,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { case 54: /* floating point arith */ o1 = c.oprrr(p, p.As) - - var rf int - if p.From.Type == obj.TYPE_CONST { - rf = c.chipfloat7(p.From.Val.(float64)) - if rf < 0 || true { - c.ctxt.Diag("invalid floating-point immediate\n%v", p) - rf = 0 - } - - rf |= (1 << 3) - } else { - rf = int(p.From.Reg) - } + rf := int(p.From.Reg) rt := int(p.To.Reg) r := int(p.Reg) if (o1&(0x1F<<24)) == (0x1E<<24) && (o1&(1<<11)) == 0 { /* monadic */ @@ -3470,6 +3498,18 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { } o1 |= (uint32(rf&31) << 16) | (uint32(r&31) << 5) | uint32(rt&31) + case 55: /* floating-point constant */ + var rf int + o1 = 0xf<<25 | 1<<21 | 1<<12 + rf = c.chipfloat7(p.From.Val.(float64)) + if rf < 0 { + c.ctxt.Diag("invalid floating-point immediate\n%v", p) + } + if p.As == AFMOVD { + o1 |= 1 << 22 + } + o1 |= (uint32(rf&0xff) << 13) | uint32(p.To.Reg&31) + case 56: /* floating point compare */ o1 = c.oprrr(p, p.As) @@ -6138,13 +6178,26 @@ func (c *ctxt7) opextr(p *obj.Prog, a obj.As, v int32, rn int, rm int, rt int) u /* genrate instruction encoding for LDP/LDPW/LDPSW/STP/STPW */ func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uint32) uint32 { var ret uint32 + // check offset switch p.As { + case AFLDPD, AFSTPD: + if vo < -512 || vo > 504 || vo%8 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 8 + ret = 1<<30 | 1<<26 case ALDP, ASTP: if vo < -512 || vo > 504 || vo%8 != 0 { c.ctxt.Diag("invalid offset %v\n", p) } vo /= 8 ret = 2 << 30 + case AFLDPS, AFSTPS: + if vo < -256 || vo > 252 || vo%4 != 0 { + c.ctxt.Diag("invalid offset %v\n", p) + } + vo /= 4 + ret = 1 << 26 case ALDPW, ASTPW: if vo < -256 || vo > 252 || vo%4 != 0 { c.ctxt.Diag("invalid offset %v\n", p) @@ -6160,6 +6213,22 @@ func (c *ctxt7) opldpstp(p *obj.Prog, o *Optab, vo int32, rbase, rl, rh, ldp uin default: c.ctxt.Diag("invalid instruction %v\n", p) } + // check register pair + switch p.As { + case AFLDPD, AFLDPS, AFSTPD, AFSTPS: + if rl < REG_F0 || REG_F31 < rl || rh < REG_F0 || REG_F31 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + case ALDP, ALDPW, ALDPSW: + if rl < REG_R0 || REG_R30 < rl || rh < REG_R0 || REG_R30 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + case ASTP, ASTPW: + if rl < REG_R0 || REG_R31 < rl || rh < REG_R0 || REG_R31 < rh { + c.ctxt.Diag("invalid register pair %v\n", p) + } + } + // other conditional flag bits switch o.scond { case C_XPOST: ret |= 1 << 23 diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index 0d832387d7..4476dad071 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -254,7 +254,11 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { switch p.As { case AFMOVS: if p.From.Type == obj.TYPE_FCONST { - f32 := float32(p.From.Val.(float64)) + f64 := p.From.Val.(float64) + f32 := float32(f64) + if c.chipfloat7(f64) > 0 { + break + } if math.Float32bits(f32) == 0 { p.From.Type = obj.TYPE_REG p.From.Reg = REGZERO @@ -269,6 +273,9 @@ func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { case AFMOVD: if p.From.Type == obj.TYPE_FCONST { f64 := p.From.Val.(float64) + if c.chipfloat7(f64) > 0 { + break + } if math.Float64bits(f64) == 0 { p.From.Type = obj.TYPE_REG p.From.Reg = REGZERO @@ -542,22 +549,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { c.autosize += 8 } - if c.autosize != 0 && c.autosize&(16-1) != 0 { - // The frame includes an LR. - // If the frame size is 8, it's only an LR, - // so there's no potential for breaking references to - // local variables by growing the frame size, - // because there are no local variables. - // But otherwise, if there is a non-empty locals section, - // the author of the code is responsible for making sure - // that the frame size is 8 mod 16. - if c.autosize == 8 { - c.autosize += 8 - c.cursym.Func.Locals += 8 + if c.autosize != 0 { + extrasize := int32(0) + if c.autosize%16 == 8 { + // Allocate extra 8 bytes on the frame top to save FP + extrasize = 8 + } else if c.autosize&(16-1) == 0 { + // Allocate extra 16 bytes to save FP for the old frame whose size is 8 mod 16 + extrasize = 16 } else { - c.ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, c.autosize-8) + c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8) } + c.autosize += extrasize + c.cursym.Func.Locals += extrasize + + // low 32 bits for autosize + // high 32 bits for extrasize + p.To.Offset = int64(c.autosize) | int64(extrasize)<<32 + } else { + // NOFRAME + p.To.Offset = 0 } + if c.autosize == 0 && c.cursym.Func.Text.Mark&LEAF == 0 { if c.ctxt.Debugvlog { c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func.Text.From.Sym.Name) @@ -565,9 +578,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { c.cursym.Func.Text.Mark |= LEAF } - // FP offsets need an updated p.To.Offset. - p.To.Offset = int64(c.autosize) - 8 - if cursym.Func.Text.Mark&LEAF != 0 { cursym.Set(obj.AttrLeaf, true) if p.From.Sym.NoFrame() { @@ -631,6 +641,26 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { q1.Spadj = aoffset } + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + q1 = obj.Appendp(q1, c.newprog) + q1.Pos = p.Pos + q1.As = AMOVD + q1.From.Type = obj.TYPE_REG + q1.From.Reg = REGFP + q1.To.Type = obj.TYPE_MEM + q1.To.Reg = REGSP + q1.To.Offset = -8 + + q1 = obj.Appendp(q1, c.newprog) + q1.Pos = p.Pos + q1.As = ASUB + q1.From.Type = obj.TYPE_CONST + q1.From.Offset = 8 + q1.Reg = REGSP + q1.To.Type = obj.TYPE_REG + q1.To.Reg = REGFP + } + if c.cursym.Func.Text.From.Sym.Wrapper() { // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame // @@ -753,9 +783,30 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.To.Type = obj.TYPE_REG p.To.Reg = REGSP p.Spadj = -c.autosize + + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + p = obj.Appendp(p, c.newprog) + p.As = ASUB + p.From.Type = obj.TYPE_CONST + p.From.Offset = 8 + p.Reg = REGSP + p.To.Type = obj.TYPE_REG + p.To.Reg = REGFP + } } } else { /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ + + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + p.As = AMOVD + p.From.Type = obj.TYPE_MEM + p.From.Reg = REGSP + p.From.Offset = -8 + p.To.Type = obj.TYPE_REG + p.To.Reg = REGFP + p = obj.Appendp(p, c.newprog) + } + aoffset := c.autosize if aoffset > 0xF0 { @@ -814,7 +865,6 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.Spadj = int32(+p.From.Offset) } } - break case obj.AGETCALLERPC: if cursym.Leaf() { @@ -828,6 +878,112 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.From.Type = obj.TYPE_MEM p.From.Reg = REGSP } + + case obj.ADUFFCOPY: + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + // ADR ret_addr, R27 + // STP (FP, R27), -24(SP) + // SUB 24, SP, FP + // DUFFCOPY + // ret_addr: + // SUB 8, SP, FP + + q1 := p + // copy DUFFCOPY from q1 to q4 + q4 := obj.Appendp(p, c.newprog) + q4.Pos = p.Pos + q4.As = obj.ADUFFCOPY + q4.To = p.To + + q1.As = AADR + q1.From.Type = obj.TYPE_BRANCH + q1.To.Type = obj.TYPE_REG + q1.To.Reg = REG_R27 + + q2 := obj.Appendp(q1, c.newprog) + q2.Pos = p.Pos + q2.As = ASTP + q2.From.Type = obj.TYPE_REGREG + q2.From.Reg = REGFP + q2.From.Offset = int64(REG_R27) + q2.To.Type = obj.TYPE_MEM + q2.To.Reg = REGSP + q2.To.Offset = -24 + + // maintaine FP for DUFFCOPY + q3 := obj.Appendp(q2, c.newprog) + q3.Pos = p.Pos + q3.As = ASUB + q3.From.Type = obj.TYPE_CONST + q3.From.Offset = 24 + q3.Reg = REGSP + q3.To.Type = obj.TYPE_REG + q3.To.Reg = REGFP + + q5 := obj.Appendp(q4, c.newprog) + q5.Pos = p.Pos + q5.As = ASUB + q5.From.Type = obj.TYPE_CONST + q5.From.Offset = 8 + q5.Reg = REGSP + q5.To.Type = obj.TYPE_REG + q5.To.Reg = REGFP + q1.Pcond = q5 + p = q5 + } + + case obj.ADUFFZERO: + if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) { + // ADR ret_addr, R27 + // STP (FP, R27), -24(SP) + // SUB 24, SP, FP + // DUFFZERO + // ret_addr: + // SUB 8, SP, FP + + q1 := p + // copy DUFFZERO from q1 to q4 + q4 := obj.Appendp(p, c.newprog) + q4.Pos = p.Pos + q4.As = obj.ADUFFZERO + q4.To = p.To + + q1.As = AADR + q1.From.Type = obj.TYPE_BRANCH + q1.To.Type = obj.TYPE_REG + q1.To.Reg = REG_R27 + + q2 := obj.Appendp(q1, c.newprog) + q2.Pos = p.Pos + q2.As = ASTP + q2.From.Type = obj.TYPE_REGREG + q2.From.Reg = REGFP + q2.From.Offset = int64(REG_R27) + q2.To.Type = obj.TYPE_MEM + q2.To.Reg = REGSP + q2.To.Offset = -24 + + // maintaine FP for DUFFZERO + q3 := obj.Appendp(q2, c.newprog) + q3.Pos = p.Pos + q3.As = ASUB + q3.From.Type = obj.TYPE_CONST + q3.From.Offset = 24 + q3.Reg = REGSP + q3.To.Type = obj.TYPE_REG + q3.To.Reg = REGFP + + q5 := obj.Appendp(q4, c.newprog) + q5.Pos = p.Pos + q5.As = ASUB + q5.From.Type = obj.TYPE_CONST + q5.From.Offset = 8 + q5.Reg = REGSP + q5.To.Type = obj.TYPE_REG + q5.To.Reg = REGFP + q1.Pcond = q5 + p = q5 + } } } } diff --git a/src/cmd/internal/obj/mips/anames.go b/src/cmd/internal/obj/mips/anames.go index cb0d56847e..d588d131bc 100644 --- a/src/cmd/internal/obj/mips/anames.go +++ b/src/cmd/internal/obj/mips/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p mips -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p mips; DO NOT EDIT. package mips diff --git a/src/cmd/internal/obj/plist.go b/src/cmd/internal/obj/plist.go index 0658cc7311..a8675055d9 100644 --- a/src/cmd/internal/obj/plist.go +++ b/src/cmd/internal/obj/plist.go @@ -119,9 +119,6 @@ func (ctxt *Link) InitTextSym(s *LSym, flag int) { ctxt.Diag("InitTextSym double init for %s", s.Name) } s.Func = new(FuncInfo) - if s.Func.Text != nil { - ctxt.Diag("duplicate TEXT for %s", s.Name) - } if s.OnList() { ctxt.Diag("symbol %s listed multiple times", s.Name) } diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go index 16a27591c7..c04ce27e46 100644 --- a/src/cmd/internal/obj/ppc64/anames.go +++ b/src/cmd/internal/obj/ppc64/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p ppc64 -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p ppc64; DO NOT EDIT. package ppc64 diff --git a/src/cmd/internal/obj/s390x/a.out.go b/src/cmd/internal/obj/s390x/a.out.go index babcd2af01..9ee02a2d0d 100644 --- a/src/cmd/internal/obj/s390x/a.out.go +++ b/src/cmd/internal/obj/s390x/a.out.go @@ -271,6 +271,9 @@ const ( // find leftmost one AFLOGR + // population count + APOPCNT + // integer bitwise AAND AANDW diff --git a/src/cmd/internal/obj/s390x/anames.go b/src/cmd/internal/obj/s390x/anames.go index 2c621a5cbe..2d6ea5abb4 100644 --- a/src/cmd/internal/obj/s390x/anames.go +++ b/src/cmd/internal/obj/s390x/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p s390x -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p s390x; DO NOT EDIT. package s390x @@ -46,6 +45,7 @@ var Anames = []string{ "MOVDLT", "MOVDNE", "FLOGR", + "POPCNT", "AND", "ANDW", "OR", diff --git a/src/cmd/internal/obj/s390x/asmz.go b/src/cmd/internal/obj/s390x/asmz.go index 52cfc0e1e6..359610c41d 100644 --- a/src/cmd/internal/obj/s390x/asmz.go +++ b/src/cmd/internal/obj/s390x/asmz.go @@ -246,6 +246,9 @@ var optab = []Optab{ // find leftmost one Optab{AFLOGR, C_REG, C_NONE, C_NONE, C_REG, 8, 0}, + // population count + Optab{APOPCNT, C_REG, C_NONE, C_NONE, C_REG, 9, 0}, + // compare Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 0}, Optab{ACMP, C_REG, C_NONE, C_NONE, C_LCON, 71, 0}, @@ -427,7 +430,7 @@ func spanz(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { changed := true loop := 0 for changed { - if loop > 10 { + if loop > 100 { c.ctxt.Diag("stuck in spanz loop") break } @@ -2849,6 +2852,9 @@ func (c *ctxtz) asmout(p *obj.Prog, asm *[]byte) { // FLOGR also writes a mask to p.To.Reg+1. zRRE(op_FLOGR, uint32(p.To.Reg), uint32(p.From.Reg), asm) + case 9: // population count + zRRE(op_POPCNT, uint32(p.To.Reg), uint32(p.From.Reg), asm) + case 10: // subtract reg [reg] reg r := int(p.Reg) diff --git a/src/cmd/internal/obj/stringer.go b/src/cmd/internal/obj/stringer.go index 1c7a962e57..f67b89091c 100644 --- a/src/cmd/internal/obj/stringer.go +++ b/src/cmd/internal/obj/stringer.go @@ -93,8 +93,7 @@ func main() { } } -const header = `// Generated by stringer -i %s -o %s -p %s -// Do not edit. +const header = `// Code generated by stringer -i %s -o %s -p %s; DO NOT EDIT. package %s diff --git a/src/cmd/internal/obj/wasm/anames.go b/src/cmd/internal/obj/wasm/anames.go index 745f0d773a..369de3092d 100644 --- a/src/cmd/internal/obj/wasm/anames.go +++ b/src/cmd/internal/obj/wasm/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i a.out.go -o anames.go -p wasm -// Do not edit. +// Code generated by stringer -i a.out.go -o anames.go -p wasm; DO NOT EDIT. package wasm diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go index 149864be7b..ba47524201 100644 --- a/src/cmd/internal/obj/x86/anames.go +++ b/src/cmd/internal/obj/x86/anames.go @@ -1,5 +1,4 @@ -// Generated by stringer -i aenum.go -o anames.go -p x86 -// Do not edit. +// Code generated by stringer -i aenum.go -o anames.go -p x86; DO NOT EDIT. package x86 diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index a47e2f93a1..ffd1c04d39 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -76,7 +76,7 @@ func init() { } func Framepointer_enabled(goos, goarch string) bool { - return framepointer_enabled != 0 && goarch == "amd64" && goos != "nacl" + return framepointer_enabled != 0 && (goarch == "amd64" && goos != "nacl" || goarch == "arm64" && goos == "linux") } func addexp(s string) { diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go index 7d5162a1e8..a48a9df5d6 100644 --- a/src/cmd/internal/objfile/elf.go +++ b/src/cmd/internal/objfile/elf.go @@ -114,7 +114,7 @@ func (f *elfFile) goarch() string { func (f *elfFile) loadAddress() (uint64, error) { for _, p := range f.elf.Progs { - if p.Type == elf.PT_LOAD { + if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 { return p.Vaddr, nil } } diff --git a/src/cmd/internal/objfile/pe.go b/src/cmd/internal/objfile/pe.go index 80db6f0f18..259b59a4f4 100644 --- a/src/cmd/internal/objfile/pe.go +++ b/src/cmd/internal/objfile/pe.go @@ -190,6 +190,9 @@ func (f *peFile) goarch() string { if _, err := findPESymbol(f.pe, "_rt0_amd64_windows"); err == nil { return "amd64" } + if _, err := findPESymbol(f.pe, "_rt0_arm_windows"); err == nil { + return "arm" + } return "" } diff --git a/src/cmd/internal/sys/supported.go b/src/cmd/internal/sys/supported.go new file mode 100644 index 0000000000..22dec702a5 --- /dev/null +++ b/src/cmd/internal/sys/supported.go @@ -0,0 +1,29 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sys + +// RaceDetectorSupported reports whether goos/goarch supports the race +// detector. There is a copy of this function in cmd/dist/test.go. +func RaceDetectorSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "ppc64le" + case "darwin", "freebsd", "netbsd", "windows": + return goarch == "amd64" + default: + return false + } +} + +// MSanSupported reports whether goos/goarch supports the memory +// sanitizer option. There is a copy of this function in cmd/dist/test.go. +func MSanSupported(goos, goarch string) bool { + switch goos { + case "linux": + return goarch == "amd64" || goarch == "arm64" + default: + return false + } +} diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go index 1a54a1c3bb..f8052136be 100644 --- a/src/cmd/internal/test2json/test2json.go +++ b/src/cmd/internal/test2json/test2json.go @@ -147,7 +147,7 @@ var ( fourSpace = []byte(" ") skipLinePrefix = []byte("? \t") - skipLineSuffix = []byte(" [no test files]\n") + skipLineSuffix = []byte("\t[no test files]\n") ) // handleInputLine handles a single whole test output line. @@ -166,7 +166,7 @@ func (c *converter) handleInputLine(line []byte) { return } - // Special case for entirely skipped test binary: "? \tpkgname\t0.001s [no test files]\n" is only line. + // Special case for entirely skipped test binary: "? \tpkgname\t[no test files]\n" is only line. // Report it as plain output but remember to say skip in the final summary. if bytes.HasPrefix(line, skipLinePrefix) && bytes.HasSuffix(line, skipLineSuffix) && len(c.report) == 0 { c.result = "skip" diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go index af274444f3..e922fe2db9 100644 --- a/src/cmd/link/internal/amd64/asm.go +++ b/src/cmd/link/internal/amd64/asm.go @@ -139,7 +139,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt) + r.Add += int64(targ.Plt()) } return true @@ -164,7 +164,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { r.Type = objabi.R_PCREL r.Sym = ctxt.Syms.Lookup(".got", 0) r.Add += 4 - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) return true case 256 + objabi.RelocType(elf.R_X86_64_64): @@ -190,13 +190,12 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) r.Type = objabi.R_PCREL return true } fallthrough - // fall through case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1, 512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1, 512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1, @@ -224,7 +223,6 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } fallthrough - // fall through case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1: if targ.Type != sym.SDYNIMPORT { ld.Errorf(s, "unexpected GOT reloc for non-dynamic symbol %s", targ.Name) @@ -232,7 +230,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { addgotsym(ctxt, targ) r.Type = objabi.R_PCREL r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) return true } @@ -251,7 +249,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // Build a PLT entry and change the relocation target to that entry. addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) return true case objabi.R_ADDR: @@ -259,7 +257,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if ctxt.HeadType == objabi.Hsolaris { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt) + r.Add += int64(targ.Plt()) return true } // The code is asking for the address of an external @@ -268,7 +266,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { addgotsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) return true } @@ -412,7 +410,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { } case objabi.R_PCREL: if r.Siz == 4 { - if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC { + if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType() == elf.STT_FUNC { ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32) } else { ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32) @@ -532,8 +530,8 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, secto return true } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { - return false +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { @@ -569,7 +567,7 @@ func elfsetupplt(ctxt *ld.Link) { } func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt >= 0 { + if s.Plt() >= 0 { return } @@ -608,7 +606,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_JMP_SLOT))) rela.AddUint64(ctxt.Arch, 0) - s.Plt = int32(plt.Size - 16) + s.SetPlt(int32(plt.Size - 16)) } else if ctxt.HeadType == objabi.Hdarwin { // To do lazy symbol lookup right, we're supposed // to tell the dynamic loader which library each @@ -626,29 +624,29 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) // jmpq *got+size(IP) - s.Plt = int32(plt.Size) + s.SetPlt(int32(plt.Size)) plt.AddUint8(0xff) plt.AddUint8(0x25) - plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got)) + plt.AddPCRelPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got())) } else { ld.Errorf(s, "addpltsym: unsupported binary format") } } func addgotsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Got >= 0 { + if s.Got() >= 0 { return } ld.Adddynsym(ctxt, s) got := ctxt.Syms.Lookup(".got", 0) - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) got.AddUint64(ctxt.Arch, 0) if ctxt.IsELF { rela := ctxt.Syms.Lookup(".rela", 0) - rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got)) + rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_X86_64_GLOB_DAT))) rela.AddUint64(ctxt.Arch, 0) } else if ctxt.HeadType == objabi.Hdarwin { diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go index f0a510f1f0..efcd41d72b 100644 --- a/src/cmd/link/internal/arm/asm.go +++ b/src/cmd/link/internal/arm/asm.go @@ -132,7 +132,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(braddoff(int32(r.Add), targ.Plt/4)) + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) } return true @@ -150,7 +150,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { r.Type = objabi.R_CONST // write r->add during relocsym r.Sym = nil - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) return true case 256 + objabi.RelocType(elf.R_ARM_GOT_PREL): // GOT(nil) + A - nil @@ -162,7 +162,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { r.Type = objabi.R_PCREL r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got) + 4 + r.Add += int64(targ.Got()) + 4 return true case 256 + objabi.RelocType(elf.R_ARM_GOTOFF): // R_ARM_GOTOFF32 @@ -182,7 +182,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(braddoff(int32(r.Add), targ.Plt/4)) + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) } return true @@ -216,7 +216,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(braddoff(int32(r.Add), targ.Plt/4)) + r.Add = int64(braddoff(int32(r.Add), targ.Plt()/4)) } return true @@ -235,7 +235,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) return true case objabi.R_ADDR: @@ -411,6 +411,35 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se return true } +func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool { + rs := r.Xsym + + if rs.Dynid < 0 { + ld.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", r.Type, sym.RelocName(arch, r.Type), rs.Name, rs.Type, rs.Type) + return false + } + + out.Write32(uint32(sectoff)) + out.Write32(uint32(rs.Dynid)) + + var v uint32 + switch r.Type { + default: + // unsupported relocation type + return false + + case objabi.R_DWARFSECREF: + v = ld.IMAGE_REL_ARM_SECREL + + case objabi.R_ADDR: + v = ld.IMAGE_REL_ARM_ADDR32 + } + + out.Write16(uint16(v)) + + return true +} + // sign extend a 24-bit integer func signext24(x int64) int32 { return (int32(x) << 8) >> 8 @@ -568,7 +597,7 @@ func gentrampdyn(arch *sys.Arch, tramp, target *sym.Symbol, offset int64) { } } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { switch r.Type { case objabi.R_CALLARM: @@ -602,20 +631,17 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { ld.Errorf(s, "direct call too far %d", r.Xadd/4) } - *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4)))) - return true + return int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4)))), true } - return false + return -1, false } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true // The following three arch specific relocations are only for generation of // Linux/ARM ELF's PLT entry (3 assembler instruction) @@ -623,16 +649,11 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { if ld.Symaddr(ctxt.Syms.Lookup(".got.plt", 0)) < ld.Symaddr(ctxt.Syms.Lookup(".plt", 0)) { ld.Errorf(s, ".got.plt should be placed after .plt section.") } - *val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20)) - return true + return 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add)) >> 20)), true case objabi.R_PLT1: // add ip, ip, #0xYY000 - *val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12)) - - return true + return 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+4)) >> 12)), true case objabi.R_PLT2: // ldr pc, [ip, #0xZZZ]! - *val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8))) - - return true + return 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ctxt.Syms.Lookup(".plt", 0))+int64(r.Off))+r.Add+8))), true case objabi.R_CALLARM: // bl XXXXXX or b YYYYYY // r.Add is the instruction // low 24-bit encodes the target address @@ -640,12 +661,10 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { if t > 0x7fffff || t < -0x800000 { ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t) } - *val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t))) - - return true + return int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&t))), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { @@ -659,7 +678,7 @@ func addpltreloc(ctxt *ld.Link, plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, r.Off = int32(plt.Size) r.Siz = 4 r.Type = typ - r.Add = int64(s.Got) - 8 + r.Add = int64(s.Got()) - 8 plt.Attr |= sym.AttrReachable plt.Size += 4 @@ -667,7 +686,7 @@ func addpltreloc(ctxt *ld.Link, plt *sym.Symbol, got *sym.Symbol, s *sym.Symbol, } func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt >= 0 { + if s.Plt() >= 0 { return } @@ -682,7 +701,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { } // .got entry - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) // In theory, all GOT should point to the first PLT entry, // Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's @@ -690,14 +709,14 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { got.AddAddrPlus(ctxt.Arch, plt, 0) // .plt entry, this depends on the .got entry - s.Plt = int32(plt.Size) + s.SetPlt(int32(plt.Size)) addpltreloc(ctxt, plt, got, s, objabi.R_PLT0) // add lr, pc, #0xXX00000 addpltreloc(ctxt, plt, got, s, objabi.R_PLT1) // add lr, lr, #0xYY000 addpltreloc(ctxt, plt, got, s, objabi.R_PLT2) // ldr pc, [lr, #0xZZZ]! // rel - rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got)) + rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_JUMP_SLOT))) } else { @@ -706,12 +725,12 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { } func addgotsyminternal(ctxt *ld.Link, s *sym.Symbol) { - if s.Got >= 0 { + if s.Got() >= 0 { return } got := ctxt.Syms.Lookup(".got", 0) - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) got.AddAddrPlus(ctxt.Arch, s, 0) @@ -722,18 +741,18 @@ func addgotsyminternal(ctxt *ld.Link, s *sym.Symbol) { } func addgotsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Got >= 0 { + if s.Got() >= 0 { return } ld.Adddynsym(ctxt, s) got := ctxt.Syms.Lookup(".got", 0) - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) got.AddUint32(ctxt.Arch, 0) if ctxt.IsELF { rel := ctxt.Syms.Lookup(".rel", 0) - rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got)) + rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_ARM_GLOB_DAT))) } else { ld.Errorf(s, "addgotsym: unsupported binary format") @@ -809,6 +828,10 @@ func asmb(ctxt *ld.Link) { case objabi.Hdarwin: symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(*ld.FlagRound))) + uint64(machlink)) + + case objabi.Hwindows: + symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen) + symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN)) } ctxt.Out.SeekSet(int64(symo)) @@ -838,6 +861,11 @@ func asmb(ctxt *ld.Link) { ctxt.Out.Flush() } + case objabi.Hwindows: + if ctxt.Debugvlog != 0 { + ctxt.Logf("%5.2f dwarf\n", ld.Cputime()) + } + case objabi.Hdarwin: if ctxt.LinkMode == ld.LinkExternal { ld.Machoemitreloc(ctxt) @@ -870,6 +898,9 @@ func asmb(ctxt *ld.Link) { case objabi.Hdarwin: ld.Asmbmacho(ctxt) + + case objabi.Hwindows: + ld.Asmbpe(ctxt) } ctxt.Out.Flush() diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go index 788be68522..77716bb954 100644 --- a/src/cmd/link/internal/arm/obj.go +++ b/src/cmd/link/internal/arm/obj.go @@ -57,6 +57,7 @@ func Init() (*sys.Arch, ld.Arch) { Elfsetupplt: elfsetupplt, Gentext: gentext, Machoreloc1: machoreloc1, + PEreloc1: pereloc1, Linuxdynld: "/lib/ld-linux.so.3", // 2 for OABI, 3 for EABI Freebsddynld: "/usr/libexec/ld-elf.so.1", @@ -130,6 +131,10 @@ func archinit(ctxt *ld.Link) { if *ld.FlagRound == -1 { *ld.FlagRound = 4096 } + + case objabi.Hwindows: /* PE executable */ + // ld.HEADR, ld.FlagTextAddr, ld.FlagDataAddr and ld.FlagRound are set in ld.Peinit + return } if *ld.FlagDataAddr != 0 && *ld.FlagRound != 0 { diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 5b3b9e5880..770590fd35 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -234,19 +234,19 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se return true } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { switch r.Type { default: - return false + return val, false case objabi.R_ARM64_GOTPCREL: var o1, o2 uint32 if ctxt.Arch.ByteOrder == binary.BigEndian { - o1 = uint32(*val >> 32) - o2 = uint32(*val) + o1 = uint32(val >> 32) + o2 = uint32(val) } else { - o1 = uint32(*val) - o2 = uint32(*val >> 32) + o1 = uint32(val) + o2 = uint32(val >> 32) } // Any relocation against a function symbol is redirected to // be against a local symbol instead (see putelfsym in @@ -264,9 +264,9 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { r.Type = objabi.R_ADDRARM64 } if ctxt.Arch.ByteOrder == binary.BigEndian { - *val = int64(o1)<<32 | int64(o2) + val = int64(o1)<<32 | int64(o2) } else { - *val = int64(o2)<<32 | int64(o1) + val = int64(o2)<<32 | int64(o1) } fallthrough case objabi.R_ADDRARM64: @@ -294,11 +294,11 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { var o0, o1 uint32 if ctxt.Arch.ByteOrder == binary.BigEndian { - o0 = uint32(*val >> 32) - o1 = uint32(*val) + o0 = uint32(val >> 32) + o1 = uint32(val) } else { - o0 = uint32(*val) - o1 = uint32(*val >> 32) + o0 = uint32(val) + o1 = uint32(val >> 32) } // Mach-O wants the addend to be encoded in the instruction // Note that although Mach-O supports ARM64_RELOC_ADDEND, it @@ -311,30 +311,28 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { // when laid out, the instruction order must always be o1, o2. if ctxt.Arch.ByteOrder == binary.BigEndian { - *val = int64(o0)<<32 | int64(o1) + val = int64(o0)<<32 | int64(o1) } else { - *val = int64(o1)<<32 | int64(o0) + val = int64(o1)<<32 | int64(o0) } } - return true + return val, true case objabi.R_CALLARM64, objabi.R_ARM64_TLS_LE, objabi.R_ARM64_TLS_IE: r.Done = false r.Xsym = r.Sym r.Xadd = r.Add - return true + return val, true } } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true case objabi.R_ADDRARM64: t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff) if t >= 1<<32 || t < -1<<32 { @@ -344,11 +342,11 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { var o0, o1 uint32 if ctxt.Arch.ByteOrder == binary.BigEndian { - o0 = uint32(*val >> 32) - o1 = uint32(*val) + o0 = uint32(val >> 32) + o1 = uint32(val) } else { - o0 = uint32(*val) - o1 = uint32(*val >> 32) + o0 = uint32(val) + o1 = uint32(val >> 32) } o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5) @@ -356,11 +354,9 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { // when laid out, the instruction order must always be o1, o2. if ctxt.Arch.ByteOrder == binary.BigEndian { - *val = int64(o0)<<32 | int64(o1) - } else { - *val = int64(o1)<<32 | int64(o0) + return int64(o0)<<32 | int64(o1), true } - return true + return int64(o1)<<32 | int64(o0), true case objabi.R_ARM64_TLS_LE: r.Done = false if ctxt.HeadType != objabi.Hlinux { @@ -372,18 +368,16 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { if v < 0 || v >= 32678 { ld.Errorf(s, "TLS offset out of range %d", v) } - *val |= v << 5 - return true + return val | (v << 5), true case objabi.R_CALLARM64: t := (ld.Symaddr(r.Sym) + r.Add) - (s.Value + int64(r.Off)) if t >= 1<<27 || t < -1<<27 { ld.Errorf(s, "program too large, call relocation distance = %d", t) } - *val |= (t >> 2) & 0x03ffffff - return true + return val | ((t >> 2) & 0x03ffffff), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go index ae7554c929..f41e30d6e7 100644 --- a/src/cmd/link/internal/ld/ar.go +++ b/src/cmd/link/internal/ld/ar.go @@ -105,7 +105,8 @@ func hostArchive(ctxt *Link, name string) { for any { var load []uint64 for _, s := range ctxt.Syms.Allsym { - for _, r := range s.R { + for i := range s.R { + r := &s.R[i] // Copying sym.Reloc has measurable impact on performance if r.Sym != nil && r.Sym.Type == sym.SXREF { if off := armap[r.Sym.Name]; off != 0 && !loaded[off] { load = append(load, off) diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index 18fbea62ee..77b03b67f9 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -60,7 +60,7 @@ func (mode *BuildMode) Set(s string) error { } case "windows": switch objabi.GOARCH { - case "amd64", "386": + case "amd64", "386", "arm": default: return badmode() } diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index c337c5e7ed..ee98aef20d 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -111,7 +111,20 @@ func trampoline(ctxt *Link, s *sym.Symbol) { } -// resolve relocations in s. +// relocsym resolve relocations in "s". The main loop walks through +// the list of relocations attached to "s" and resolves them where +// applicable. Relocations are often architecture-specific, requiring +// calls into the 'archreloc' and/or 'archrelocvariant' functions for +// the architecture. When external linking is in effect, it may not be +// possible to completely resolve the address/offset for a symbol, in +// which case the goal is to lay the groundwork for turning a given +// relocation into an external reloc (to be applied by the external +// linker). For more on how relocations work in general, see +// +// "Linkers and Loaders", by John R. Levine (Morgan Kaufmann, 1999), ch. 7 +// +// This is a performance-critical function for the linker; be careful +// to avoid introducing unnecessary allocations in the main loop. func relocsym(ctxt *Link, s *sym.Symbol) { for ri := int32(0); ri < int32(len(s.R)); ri++ { r := &s.R[ri] @@ -198,7 +211,9 @@ func relocsym(ctxt *Link, s *sym.Symbol) { case 8: o = int64(ctxt.Arch.ByteOrder.Uint64(s.P[off:])) } - if !thearch.Archreloc(ctxt, r, s, &o) { + if offset, ok := thearch.Archreloc(ctxt, r, s, o); ok { + o = offset + } else { Errorf(s, "unknown reloc to %v: %d (%s)", r.Sym.Name, r.Type, sym.RelocName(ctxt.Arch, r.Type)) } case objabi.R_TLS_LE: @@ -531,28 +546,32 @@ func windynrelocsym(ctxt *Link, s *sym.Symbol) { } Errorf(s, "dynamic relocation to unreachable symbol %s", targ.Name) } - if r.Sym.Plt == -2 && r.Sym.Got != -2 { // make dynimport JMP table for PE object files. - targ.Plt = int32(rel.Size) + if r.Sym.Plt() == -2 && r.Sym.Got() != -2 { // make dynimport JMP table for PE object files. + targ.SetPlt(int32(rel.Size)) r.Sym = rel - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) // jmp *addr - if ctxt.Arch.Family == sys.I386 { + switch ctxt.Arch.Family { + default: + Errorf(s, "unsupported arch %v", ctxt.Arch.Family) + return + case sys.I386: rel.AddUint8(0xff) rel.AddUint8(0x25) rel.AddAddr(ctxt.Arch, targ) rel.AddUint8(0x90) rel.AddUint8(0x90) - } else { + case sys.AMD64: rel.AddUint8(0xff) rel.AddUint8(0x24) rel.AddUint8(0x25) rel.AddAddrPlus4(targ, 0) rel.AddUint8(0x90) } - } else if r.Sym.Plt >= 0 { + } else if r.Sym.Plt() >= 0 { r.Sym = rel - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) } } } @@ -770,7 +789,8 @@ func Datblk(ctxt *Link, addr int64, size int64) { if ctxt.LinkMode != LinkExternal { continue } - for _, r := range sym.R { + for i := range sym.R { + r := &sym.R[i] // Copying sym.Reloc has measurable impact on performance rsname := "" if r.Sym != nil { rsname = r.Sym.Name @@ -1582,7 +1602,7 @@ func (ctxt *Link) dodata() { datap = append(datap, data[symn]...) } - dwarfgeneratedebugsyms(ctxt) + dwarfGenerateDebugSyms(ctxt) var i int for ; i < len(dwarfp); i++ { @@ -2177,7 +2197,14 @@ func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte { binary.BigEndian.PutUint64(sizeBytes[:], uint64(total)) buf.Write(sizeBytes[:]) - z := zlib.NewWriter(&buf) + // Using zlib.BestSpeed achieves very nearly the same + // compression levels of zlib.DefaultCompression, but takes + // substantially less time. This is important because DWARF + // compression can be a significant fraction of link time. + z, err := zlib.NewWriterLevel(&buf, zlib.BestSpeed) + if err != nil { + log.Fatalf("NewWriterLevel failed: %s", err) + } for _, sym := range syms { if _, err := z.Write(sym.P); err != nil { log.Fatalf("compression failed: %s", err) diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index ce0fe1f7a1..df989cc944 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -190,7 +190,9 @@ func (d *deadcodepass) mark(s, parent *sym.Symbol) { fmt.Printf("%s -> %s\n", p, s.Name) } s.Attr |= sym.AttrReachable - s.Reachparent = parent + if d.ctxt.Reachparent != nil { + d.ctxt.Reachparent[s] = parent + } d.markQueue = append(d.markQueue, s) } @@ -243,8 +245,8 @@ func (d *deadcodepass) init() { // but we do keep the symbols it refers to. exports := d.ctxt.Syms.ROLookup("go.plugin.exports", 0) if exports != nil { - for _, r := range exports.R { - d.mark(r.Sym, nil) + for i := range exports.R { + d.mark(exports.R[i].Sym, nil) } } } diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 830d81d446..959fc8290c 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -21,6 +21,7 @@ import ( "cmd/link/internal/sym" "fmt" "log" + "sort" "strings" ) @@ -451,7 +452,6 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie { case objabi.KindChan: die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_CHANTYPE, name, 0) - newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0) s := decodetypeChanElem(ctxt.Arch, gotype) newrefattr(die, dwarf.DW_AT_go_elem, defgotype(ctxt, s)) // Save elem type for synthesizechantypes. We could synthesize here @@ -462,7 +462,6 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie { die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_FUNCTYPE, name, 0) newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0) dotypedef(ctxt, &dwtypes, name, die) - newrefattr(die, dwarf.DW_AT_type, mustFind(ctxt, "void")) nfields := decodetypeFuncInCount(ctxt.Arch, gotype) for i := 0; i < nfields; i++ { s := decodetypeFuncInType(ctxt.Arch, gotype, i) @@ -483,7 +482,6 @@ func newtype(ctxt *Link, gotype *sym.Symbol) *dwarf.DWDie { case objabi.KindInterface: die = newdie(ctxt, &dwtypes, dwarf.DW_ABRV_IFACETYPE, name, 0) dotypedef(ctxt, &dwtypes, name, die) - newattr(die, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, bytesize, 0) nfields := int(decodetypeIfaceMethodCount(ctxt.Arch, gotype)) var s *sym.Symbol if nfields == 0 { @@ -831,6 +829,16 @@ func synthesizechantypes(ctxt *Link, die *dwarf.DWDie) { } } +func dwarfDefineGlobal(ctxt *Link, s *sym.Symbol, str string, v int64, gotype *sym.Symbol) { + dv := newdie(ctxt, &dwglobals, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) + newabslocexprattr(dv, v, s) + if s.Version == 0 { + newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) + } + dt := defgotype(ctxt, gotype) + newrefattr(dv, dwarf.DW_AT_type, dt) +} + // For use with pass.c::genasmsym func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, gotype *sym.Symbol) { if strings.HasPrefix(str, "go.string.") { @@ -840,32 +848,24 @@ func defdwsymb(ctxt *Link, s *sym.Symbol, str string, t SymbolType, v int64, got return } - if strings.HasPrefix(str, "type.") && str != "type.*" && !strings.HasPrefix(str, "type..") { - defgotype(ctxt, s) - return - } - - var dv *dwarf.DWDie - - var dt *sym.Symbol switch t { - default: - return - case DataSym, BSSSym: - dv = newdie(ctxt, &dwglobals, dwarf.DW_ABRV_VARIABLE, str, int(s.Version)) - newabslocexprattr(dv, v, s) - if s.Version == 0 { - newattr(dv, dwarf.DW_AT_external, dwarf.DW_CLS_FLAG, 1, 0) + switch s.Type { + case sym.SDATA, sym.SNOPTRDATA, sym.STYPE, sym.SBSS, sym.SNOPTRBSS, sym.STLSBSS: + // ok + case sym.SRODATA: + if gotype != nil { + defgotype(ctxt, gotype) + } + return + default: + return } - fallthrough + + dwarfDefineGlobal(ctxt, s, str, v, gotype) case AutoSym, ParamSym, DeletedAutoSym: - dt = defgotype(ctxt, gotype) - } - - if dv != nil { - newrefattr(dv, dwarf.DW_AT_type, dt) + defgotype(ctxt, gotype) } } @@ -878,27 +878,17 @@ type compilationUnit struct { dwinfo *dwarf.DWDie // CU root DIE funcDIEs []*sym.Symbol // Function DIE subtrees absFnDIEs []*sym.Symbol // Abstract function DIE subtrees + rangeSyms []*sym.Symbol // symbols for debug_range } -// getCompilationUnits divides the symbols in ctxt.Textp by package. -func getCompilationUnits(ctxt *Link) []*compilationUnit { - units := []*compilationUnit{} - index := make(map[*sym.Library]*compilationUnit) +// calcCompUnitRanges calculates the PC ranges of the compilation units. +func calcCompUnitRanges(ctxt *Link) { var prevUnit *compilationUnit for _, s := range ctxt.Textp { if s.FuncInfo == nil { continue } - unit := index[s.Lib] - if unit == nil { - unit = &compilationUnit{lib: s.Lib} - if s := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+s.Lib.Pkg, 0); s != nil { - importInfoSymbol(ctxt, s) - unit.consts = s - } - units = append(units, unit) - index[s.Lib] = unit - } + unit := ctxt.compUnitByPackage[s.Lib] // Update PC ranges. // @@ -913,7 +903,6 @@ func getCompilationUnits(ctxt *Link) []*compilationUnit { } unit.pcs[len(unit.pcs)-1].End = s.Value - unit.lib.Textp[0].Value + s.Size } - return units } func movetomodule(parent *dwarf.DWDie) { @@ -1064,63 +1053,16 @@ func getCompilationDir() string { func importInfoSymbol(ctxt *Link, dsym *sym.Symbol) { dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable dsym.Type = sym.SDWARFINFO - for _, r := range dsym.R { + for i := range dsym.R { + r := &dsym.R[i] // Copying sym.Reloc has measurable impact on performance if r.Type == objabi.R_DWARFSECREF && r.Sym.Size == 0 { - if ctxt.BuildMode == BuildModeShared { - // These type symbols may not be present in BuildModeShared. Skip. - continue - } n := nameFromDIESym(r.Sym) defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0)) } } } -// For the specified function, collect symbols corresponding to any -// "abstract" subprogram DIEs referenced. The first case of interest -// is a concrete subprogram DIE, which will refer to its corresponding -// abstract subprogram DIE, and then there can be references from a -// non-abstract subprogram DIE to the abstract subprogram DIEs for any -// functions inlined into this one. -// -// A given abstract subprogram DIE can be referenced in numerous -// places (even within the same DIE), so it is important to make sure -// it gets imported and added to the absfuncs lists only once. - -func collectAbstractFunctions(ctxt *Link, fn *sym.Symbol, dsym *sym.Symbol, absfuncs []*sym.Symbol) []*sym.Symbol { - - var newabsfns []*sym.Symbol - - // Walk the relocations on the primary subprogram DIE and look for - // references to abstract funcs. - for _, reloc := range dsym.R { - candsym := reloc.Sym - if reloc.Type != objabi.R_DWARFSECREF { - continue - } - if !strings.HasPrefix(candsym.Name, dwarf.InfoPrefix) { - continue - } - if !strings.HasSuffix(candsym.Name, dwarf.AbstractFuncSuffix) { - continue - } - if candsym.Attr.OnList() { - continue - } - candsym.Attr |= sym.AttrOnList - newabsfns = append(newabsfns, candsym) - } - - // Import any new symbols that have turned up. - for _, absdsym := range newabsfns { - importInfoSymbol(ctxt, absdsym) - absfuncs = append(absfuncs, absdsym) - } - - return absfuncs -} - -func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbol) (dwinfo *dwarf.DWDie, funcs []*sym.Symbol, absfuncs []*sym.Symbol) { +func writelines(ctxt *Link, unit *compilationUnit, ls *sym.Symbol) (dwinfo *dwarf.DWDie) { var dwarfctxt dwarf.Context = dwctxt{ctxt} is_stmt := uint8(1) // initially = recommended default_is_stmt = 1, tracks is_stmt toggles. @@ -1131,7 +1073,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo lang := dwarf.DW_LANG_Go - dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, lib.Pkg, 0) + dwinfo = newdie(ctxt, &dwroot, dwarf.DW_ABRV_COMPUNIT, unit.lib.Pkg, 0) newattr(dwinfo, dwarf.DW_AT_language, dwarf.DW_CLS_CONSTANT, int64(lang), 0) newattr(dwinfo, dwarf.DW_AT_stmt_list, dwarf.DW_CLS_PTR, ls.Size, ls) // OS X linker requires compilation dir or absolute path in comp unit name to output debug info. @@ -1140,7 +1082,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // the linker directory. If we move CU construction into the // compiler, this should happen naturally. newattr(dwinfo, dwarf.DW_AT_comp_dir, dwarf.DW_CLS_STRING, int64(len(compDir)), compDir) - producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+lib.Pkg, 0) + producerExtra := ctxt.Syms.Lookup(dwarf.CUInfoPrefix+"producer."+unit.lib.Pkg, 0) producer := "Go cmd/compile " + objabi.Version if len(producerExtra.P) > 0 { // We put a semicolon before the flags to clearly @@ -1184,7 +1126,8 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // Create the file table. fileNums maps from global file // indexes (created by numberfile) to CU-local indexes. fileNums := make(map[int]int) - for _, s := range textp { // textp has been dead-code-eliminated already. + for _, s := range unit.lib.Textp { // textp has been dead-code-eliminated already. + dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) for _, f := range s.FuncInfo.File { if _, ok := fileNums[int(f.Value)]; ok { continue @@ -1196,26 +1139,21 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo ls.AddUint8(0) ls.AddUint8(0) } - - // Look up the .debug_info sym for the function. We do this - // now so that we can walk the sym's relocations to discover - // files that aren't mentioned in S.FuncInfo.File (for - // example, files mentioned only in an inlined subroutine). - dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - importInfoSymbol(ctxt, dsym) - for ri := range dsym.R { + for ri := 0; ri < len(dsym.R); ri++ { r := &dsym.R[ri] if r.Type != objabi.R_DWARFFILEREF { continue } - _, ok := fileNums[int(r.Sym.Value)] - if !ok { - fileNums[int(r.Sym.Value)] = len(fileNums) + 1 - Addstring(ls, r.Sym.Name) - ls.AddUint8(0) - ls.AddUint8(0) - ls.AddUint8(0) + // A file that is only mentioned in an inlined subroutine will appear + // as a R_DWARFFILEREF but not in s.FuncInfo.File + if _, ok := fileNums[int(r.Sym.Value)]; ok { + continue } + fileNums[int(r.Sym.Value)] = len(fileNums) + 1 + Addstring(ls, r.Sym.Name) + ls.AddUint8(0) + ls.AddUint8(0) + ls.AddUint8(0) } } @@ -1228,7 +1166,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo dwarf.Uleb128put(dwarfctxt, ls, 1+int64(ctxt.Arch.PtrSize)) ls.AddUint8(dwarf.DW_LNE_set_address) - s := textp[0] + s := unit.lib.Textp[0] pc := s.Value line := 1 file := 1 @@ -1237,19 +1175,12 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo var pcfile Pciter var pcline Pciter var pcstmt Pciter - for i, s := range textp { - dsym := ctxt.Syms.Lookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - funcs = append(funcs, dsym) - absfuncs = collectAbstractFunctions(ctxt, s, dsym, absfuncs) - + for i, s := range unit.lib.Textp { finddebugruntimepath(s) - isStmtsSym := ctxt.Syms.ROLookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) - pctostmtData := sym.Pcdata{P: isStmtsSym.P} - pciterinit(ctxt, &pcfile, &s.FuncInfo.Pcfile) pciterinit(ctxt, &pcline, &s.FuncInfo.Pcline) - pciterinit(ctxt, &pcstmt, &pctostmtData) + pciterinit(ctxt, &pcstmt, &sym.Pcdata{P: s.FuncInfo.IsStmtSym.P}) if pcstmt.done != 0 { // Assembly files lack a pcstmt section, we assume that every instruction @@ -1313,7 +1244,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo pciternext(&pcline) } } - if is_stmt == 0 && i < len(textp)-1 { + if is_stmt == 0 && i < len(unit.lib.Textp)-1 { // If there is more than one function, ensure default value is established. is_stmt = 1 ls.AddUint8(uint8(dwarf.DW_LNS_negate_stmt)) @@ -1334,7 +1265,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo // DIE flavors (ex: variables) then those DIEs would need to // be included below. missing := make(map[int]interface{}) - for _, f := range funcs { + for _, f := range unit.funcDIEs { for ri := range f.R { r := &f.R[ri] if r.Type != objabi.R_DWARFFILEREF { @@ -1365,7 +1296,7 @@ func writelines(ctxt *Link, lib *sym.Library, textp []*sym.Symbol, ls *sym.Symbo } } - return dwinfo, funcs, absfuncs + return dwinfo } // writepcranges generates the DW_AT_ranges table for compilation unit cu. @@ -1517,24 +1448,6 @@ func writeframes(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { return syms } -func writeranges(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { - for _, s := range ctxt.Textp { - rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version)) - if rangeSym == nil || rangeSym.Size == 0 { - continue - } - rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable - rangeSym.Type = sym.SDWARFRANGE - // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused. - if ctxt.HeadType == objabi.Hdarwin { - fn := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version)) - removeDwarfAddrListBaseAddress(ctxt, fn, rangeSym, false) - } - syms = append(syms, rangeSym) - } - return syms -} - /* * Walk DWarfDebugInfoEntries, and emit .debug_info */ @@ -1673,24 +1586,15 @@ func writegdbscript(ctxt *Link, syms []*sym.Symbol) []*sym.Symbol { var prototypedies map[string]*dwarf.DWDie -/* - * This is the main entry point for generating dwarf. After emitting - * the mandatory debug_abbrev section, it calls writelines() to set up - * the per-compilation unit part of the DIE tree, while simultaneously - * emitting the debug_line section. When the final tree contains - * forward references, it will write the debug_info section in 2 - * passes. - * - */ -func dwarfgeneratedebugsyms(ctxt *Link) { +func dwarfEnabled(ctxt *Link) bool { if *FlagW { // disable dwarf - return + return false } if *FlagS && ctxt.HeadType != objabi.Hdarwin { - return + return false } if ctxt.HeadType == objabi.Hplan9 || ctxt.HeadType == objabi.Hjs { - return + return false } if ctxt.LinkMode == LinkExternal { @@ -1699,14 +1603,27 @@ func dwarfgeneratedebugsyms(ctxt *Link) { case ctxt.HeadType == objabi.Hdarwin: case ctxt.HeadType == objabi.Hwindows: default: - return + return false } } - if ctxt.Debugvlog != 0 { - ctxt.Logf("%5.2f dwarf\n", Cputime()) + return true +} + +// dwarfGenerateDebugInfo generated debug info entries for all types, +// variables and functions in the program. +// Along with dwarfGenerateDebugSyms they are the two main entry points into +// dwarf generation: dwarfGenerateDebugInfo does all the work that should be +// done before symbol names are mangled while dwarfgeneratedebugsyms does +// all the work that can only be done after addresses have been assigned to +// text symbols. +func dwarfGenerateDebugInfo(ctxt *Link) { + if !dwarfEnabled(ctxt) { + return } + ctxt.compUnitByPackage = make(map[*sym.Library]*compilationUnit) + // Forctxt.Diagnostic messages. newattr(&dwtypes, dwarf.DW_AT_name, dwarf.DW_CLS_STRING, int64(len("dwtypes")), "dwtypes") @@ -1749,12 +1666,84 @@ func dwarfgeneratedebugsyms(ctxt *Link) { defgotype(ctxt, lookupOrDiag(ctxt, typ)) } + // Create DIEs for global variables and the types they use. genasmsym(ctxt, defdwsymb) + for _, lib := range ctxt.Library { + if len(lib.Textp) == 0 { + continue + } + unit := &compilationUnit{lib: lib} + if s := ctxt.Syms.ROLookup(dwarf.ConstInfoPrefix+lib.Pkg, 0); s != nil { + importInfoSymbol(ctxt, s) + unit.consts = s + } + ctxt.compUnits = append(ctxt.compUnits, unit) + ctxt.compUnitByPackage[lib] = unit + + // Scan all functions in this compilation unit, create DIEs for all + // referenced types, create the file table for debug_line, find all + // referenced abstract functions. + // Collect all debug_range symbols in unit.rangeSyms + for _, s := range lib.Textp { // textp has been dead-code-eliminated already. + dsym := ctxt.Syms.ROLookup(dwarf.InfoPrefix+s.Name, int(s.Version)) + dsym.Attr |= sym.AttrNotInSymbolTable | sym.AttrReachable + dsym.Type = sym.SDWARFINFO + unit.funcDIEs = append(unit.funcDIEs, dsym) + + rangeSym := ctxt.Syms.ROLookup(dwarf.RangePrefix+s.Name, int(s.Version)) + if rangeSym != nil && rangeSym.Size > 0 { + rangeSym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable + rangeSym.Type = sym.SDWARFRANGE + // LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused. + if ctxt.HeadType == objabi.Hdarwin { + removeDwarfAddrListBaseAddress(ctxt, dsym, rangeSym, false) + } + unit.rangeSyms = append(unit.rangeSyms, rangeSym) + } + + for ri := 0; ri < len(dsym.R); ri++ { + r := &dsym.R[ri] + if r.Type == objabi.R_DWARFSECREF { + rsym := r.Sym + if strings.HasPrefix(rsym.Name, dwarf.InfoPrefix) && strings.HasSuffix(rsym.Name, dwarf.AbstractFuncSuffix) && !rsym.Attr.OnList() { + // abstract function + rsym.Attr |= sym.AttrOnList + unit.absFnDIEs = append(unit.absFnDIEs, rsym) + importInfoSymbol(ctxt, rsym) + } else if rsym.Size == 0 { + // a type we do not have a DIE for + n := nameFromDIESym(rsym) + defgotype(ctxt, ctxt.Syms.Lookup("type."+n, 0)) + } + } + } + } + } + + synthesizestringtypes(ctxt, dwtypes.Child) + synthesizeslicetypes(ctxt, dwtypes.Child) + synthesizemaptypes(ctxt, dwtypes.Child) + synthesizechantypes(ctxt, dwtypes.Child) +} + +// dwarfGenerateDebugSyms constructs debug_line, debug_frame, debug_loc, +// debug_pubnames and debug_pubtypes. It also writes out the debug_info +// section using symbols generated in dwarfGenerateDebugInfo. +func dwarfGenerateDebugSyms(ctxt *Link) { + if !dwarfEnabled(ctxt) { + return + } + + if ctxt.Debugvlog != 0 { + ctxt.Logf("%5.2f dwarf\n", Cputime()) + } + abbrev := writeabbrev(ctxt) syms := []*sym.Symbol{abbrev} - units := getCompilationUnits(ctxt) + calcCompUnitRanges(ctxt) + sort.Sort(compilationUnitByStartPC(ctxt.compUnits)) // Write per-package line and range tables and start their CU DIEs. debugLine := ctxt.Syms.Lookup(".debug_line", 0) @@ -1763,16 +1752,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { debugRanges.Type = sym.SDWARFRANGE debugRanges.Attr |= sym.AttrReachable syms = append(syms, debugLine) - for _, u := range units { - u.dwinfo, u.funcDIEs, u.absFnDIEs = writelines(ctxt, u.lib, u.lib.Textp, debugLine) + for _, u := range ctxt.compUnits { + u.dwinfo = writelines(ctxt, u, debugLine) writepcranges(ctxt, u.dwinfo, u.lib.Textp[0], u.pcs, debugRanges) } - synthesizestringtypes(ctxt, dwtypes.Child) - synthesizeslicetypes(ctxt, dwtypes.Child) - synthesizemaptypes(ctxt, dwtypes.Child) - synthesizechantypes(ctxt, dwtypes.Child) - // newdie adds DIEs to the *beginning* of the parent's DIE list. // Now that we're done creating DIEs, reverse the trees so DIEs // appear in the order they were created. @@ -1785,7 +1769,7 @@ func dwarfgeneratedebugsyms(ctxt *Link) { // Need to reorder symbols so sym.SDWARFINFO is after all sym.SDWARFSECT // (but we need to generate dies before writepub) - infosyms := writeinfo(ctxt, nil, units, abbrev) + infosyms := writeinfo(ctxt, nil, ctxt.compUnits, abbrev) syms = writeframes(ctxt, syms) syms = writepub(ctxt, ".debug_pubnames", ispubname, syms) @@ -1794,9 +1778,11 @@ func dwarfgeneratedebugsyms(ctxt *Link) { // Now we're done writing SDWARFSECT symbols, so we can write // other SDWARF* symbols. syms = append(syms, infosyms...) - syms = collectlocs(ctxt, syms, units) + syms = collectlocs(ctxt, syms, ctxt.compUnits) syms = append(syms, debugRanges) - syms = writeranges(ctxt, syms) + for _, unit := range ctxt.compUnits { + syms = append(syms, unit.rangeSyms...) + } dwarfp = syms } @@ -1804,7 +1790,8 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy empty := true for _, u := range units { for _, fn := range u.funcDIEs { - for _, reloc := range fn.R { + for i := range fn.R { + reloc := &fn.R[i] // Copying sym.Reloc has measurable impact on performance if reloc.Type == objabi.R_DWARFSECREF && strings.HasPrefix(reloc.Sym.Name, dwarf.LocPrefix) { reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable syms = append(syms, reloc.Sym) @@ -2006,3 +1993,12 @@ func dwarfcompress(ctxt *Link) { } Segdwarf.Length = pos - Segdwarf.Vaddr } + +type compilationUnitByStartPC []*compilationUnit + +func (v compilationUnitByStartPC) Len() int { return len(v) } +func (v compilationUnitByStartPC) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +func (v compilationUnitByStartPC) Less(i, j int) bool { + return v[i].lib.Textp[0].Value < v[j].lib.Textp[0].Value +} diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go index b4e328bc2a..157bebbb41 100644 --- a/src/cmd/link/internal/ld/dwarf_test.go +++ b/src/cmd/link/internal/ld/dwarf_test.go @@ -24,7 +24,8 @@ import ( const ( DefaultOpt = "-gcflags=" NoOpt = "-gcflags=-l -N" - OptInl4 = "-gcflags=all=-l=4" + OptInl4 = "-gcflags=-l=4" + OptAllInl4 = "-gcflags=all=-l=4" ) func TestRuntimeTypesPresent(t *testing.T) { @@ -610,7 +611,9 @@ func main() { // Note: this is a build with "-l=4", as opposed to "-l -N". The // test is intended to verify DWARF that is only generated when - // the inliner is active. + // the inliner is active. We're only going to look at the DWARF for + // main.main, however, hence we build with "-gcflags=-l=4" as opposed + // to "-gcflags=all=-l=4". f := gobuild(t, dir, prog, OptInl4) d, err := f.DWARF() @@ -794,6 +797,10 @@ func abstractOriginSanity(t *testing.T, gopathdir string, flags string) { func TestAbstractOriginSanity(t *testing.T) { testenv.MustHaveGoBuild(t) + if testing.Short() { + t.Skip("skipping test in short mode.") + } + if runtime.GOOS == "plan9" { t.Skip("skipping on plan9; no DWARF symbol table in executables") } @@ -803,7 +810,7 @@ func TestAbstractOriginSanity(t *testing.T) { if wd, err := os.Getwd(); err == nil { gopathdir := filepath.Join(wd, "testdata", "httptest") - abstractOriginSanity(t, gopathdir, OptInl4) + abstractOriginSanity(t, gopathdir, OptAllInl4) } else { t.Fatalf("os.Getwd() failed %v", err) } @@ -830,23 +837,47 @@ func TestAbstractOriginSanityIssue25459(t *testing.T) { } } -func TestRuntimeTypeAttr(t *testing.T) { +func TestAbstractOriginSanityIssue26237(t *testing.T) { + testenv.MustHaveGoBuild(t) + + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; no DWARF symbol table in executables") + } + if runtime.GOOS == "solaris" || runtime.GOOS == "darwin" { + t.Skip("skipping on solaris and darwin, pending resolution of issue #23168") + } + if wd, err := os.Getwd(); err == nil { + gopathdir := filepath.Join(wd, "testdata", "issue26237") + abstractOriginSanity(t, gopathdir, DefaultOpt) + } else { + t.Fatalf("os.Getwd() failed %v", err) + } +} + +func TestRuntimeTypeAttrInternal(t *testing.T) { testenv.MustHaveGoBuild(t) if runtime.GOOS == "plan9" { t.Skip("skipping on plan9; no DWARF symbol table in executables") } - // Explicitly test external linking, for dsymutil compatility on Darwin. - for _, flags := range []string{"-ldflags=-linkmode=internal", "-ldflags=-linkmode=external"} { - t.Run("flags="+flags, func(t *testing.T) { - if runtime.GOARCH == "ppc64" && strings.Contains(flags, "external") { - t.Skip("-linkmode=external not supported on ppc64") - } + testRuntimeTypeAttr(t, "-ldflags=-linkmode=internal") +} - testRuntimeTypeAttr(t, flags) - }) +// External linking requires a host linker (https://golang.org/src/cmd/cgo/doc.go l.732) +func TestRuntimeTypeAttrExternal(t *testing.T) { + testenv.MustHaveGoBuild(t) + testenv.MustHaveCGO(t) + + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9; no DWARF symbol table in executables") } + + // Explicitly test external linking, for dsymutil compatibility on Darwin. + if runtime.GOARCH == "ppc64" { + t.Skip("-linkmode=external not supported on ppc64") + } + testRuntimeTypeAttr(t, "-ldflags=-linkmode=external") } func testRuntimeTypeAttr(t *testing.T, flags string) { diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 877e4bfd5f..f61a290e42 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1030,11 +1030,11 @@ func elfdynhash(ctxt *Link) { continue } - if sy.Dynimpvers != "" { - need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib, sy.Dynimpvers) + if sy.Dynimpvers() != "" { + need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib(), sy.Dynimpvers()) } - name := sy.Extname + name := sy.Extname() hc := elfhash(name) b := hc % uint32(nbucket) @@ -2254,7 +2254,7 @@ func elfadddynsym(ctxt *Link, s *sym.Symbol) { d := ctxt.Syms.Lookup(".dynsym", 0) - name := s.Extname + name := s.Extname() d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name))) /* type */ @@ -2287,8 +2287,8 @@ func elfadddynsym(ctxt *Link, s *sym.Symbol) { /* size of object */ d.AddUint64(ctxt.Arch, uint64(s.Size)) - if ctxt.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib != "" && !seenlib[s.Dynimplib] { - Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib))) + if ctxt.Arch.Family == sys.AMD64 && !s.Attr.CgoExportDynamic() && s.Dynimplib() != "" && !seenlib[s.Dynimplib()] { + Elfwritedynent(ctxt, ctxt.Syms.Lookup(".dynamic", 0), DT_NEEDED, uint64(Addstring(ctxt.Syms.Lookup(".dynstr", 0), s.Dynimplib()))) } } else { s.Dynid = int32(Nelfsym) @@ -2297,7 +2297,7 @@ func elfadddynsym(ctxt *Link, s *sym.Symbol) { d := ctxt.Syms.Lookup(".dynsym", 0) /* name */ - name := s.Extname + name := s.Extname() d.AddUint32(ctxt.Arch, uint32(Addstring(ctxt.Syms.Lookup(".dynstr", 0), name))) diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go index 8d50332c7c..f2dd799922 100644 --- a/src/cmd/link/internal/ld/go.go +++ b/src/cmd/link/internal/ld/go.go @@ -155,9 +155,9 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { } s := ctxt.Syms.Lookup(local, 0) if s.Type == 0 || s.Type == sym.SXREF || s.Type == sym.SHOSTOBJ { - s.Dynimplib = lib - s.Extname = remote - s.Dynimpvers = q + s.SetDynimplib(lib) + s.SetExtname(remote) + s.SetDynimpvers(q) if s.Type != sym.SHOSTOBJ { s.Type = sym.SDYNIMPORT } @@ -198,18 +198,17 @@ func loadcgo(ctxt *Link, file string, pkg string, p string) { // export overrides import, for openbsd/cgo. // see issue 4878. - if s.Dynimplib != "" { - s.Dynimplib = "" - s.Extname = "" - s.Dynimpvers = "" + if s.Dynimplib() != "" { + s.ResetDyninfo() + s.SetExtname("") s.Type = 0 } if !s.Attr.CgoExport() { - s.Extname = remote + s.SetExtname(remote) dynexp = append(dynexp, s) - } else if s.Extname != remote { - fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote) + } else if s.Extname() != remote { + fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname(), remote) nerrors++ return } @@ -277,7 +276,7 @@ func Adddynsym(ctxt *Link, s *sym.Symbol) { if ctxt.IsELF { elfadddynsym(ctxt, s) } else if ctxt.HeadType == objabi.Hdarwin { - Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname) + Errorf(s, "adddynsym: missed symbol (Extname=%s)", s.Extname()) } else if ctxt.HeadType == objabi.Hwindows { // already taken care of } else { @@ -294,7 +293,7 @@ func fieldtrack(ctxt *Link) { s.Attr |= sym.AttrNotInSymbolTable if s.Attr.Reachable() { buf.WriteString(s.Name[9:]) - for p := s.Reachparent; p != nil; p = p.Reachparent { + for p := ctxt.Reachparent[s]; p != nil; p = ctxt.Reachparent[p] { buf.WriteString("\t") buf.WriteString(p.Name) } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 6cd4f47709..919fa08f21 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -91,28 +91,47 @@ import ( // THE SOFTWARE. type Arch struct { - Funcalign int - Maxalign int - Minalign int - Dwarfregsp int - Dwarfreglr int - Linuxdynld string - Freebsddynld string - Netbsddynld string - Openbsddynld string - Dragonflydynld string - Solarisdynld string - Adddynrel func(*Link, *sym.Symbol, *sym.Reloc) bool - Archinit func(*Link) - Archreloc func(*Link, *sym.Reloc, *sym.Symbol, *int64) bool - Archrelocvariant func(*Link, *sym.Reloc, *sym.Symbol, int64) int64 - Trampoline func(*Link, *sym.Reloc, *sym.Symbol) - Asmb func(*Link) - Elfreloc1 func(*Link, *sym.Reloc, int64) bool - Elfsetupplt func(*Link) - Gentext func(*Link) - Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool - PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool + Funcalign int + Maxalign int + Minalign int + Dwarfregsp int + Dwarfreglr int + Linuxdynld string + Freebsddynld string + Netbsddynld string + Openbsddynld string + Dragonflydynld string + Solarisdynld string + Adddynrel func(*Link, *sym.Symbol, *sym.Reloc) bool + Archinit func(*Link) + // Archreloc is an arch-specific hook that assists in + // relocation processing (invoked by 'relocsym'); it handles + // target-specific relocation tasks. Here "rel" is the current + // relocation being examined, "sym" is the symbol containing the + // chunk of data to which the relocation applies, and "off" is the + // contents of the to-be-relocated data item (from sym.P). Return + // value is the appropriately relocated value (to be written back + // to the same spot in sym.P) and a boolean indicating + // success/failure (a failing value indicates a fatal error). + Archreloc func(link *Link, rel *sym.Reloc, sym *sym.Symbol, + offset int64) (relocatedOffset int64, success bool) + // Archrelocvariant is a second arch-specific hook used for + // relocation processing; it handles relocations where r.Type is + // insufficient to describe the relocation (r.Variant != + // sym.RV_NONE). Here "rel" is the relocation being applied, "sym" + // is the symbol containing the chunk of data to which the + // relocation applies, and "off" is the contents of the + // to-be-relocated data item (from sym.P). Return is an updated + // offset value. + Archrelocvariant func(link *Link, rel *sym.Reloc, sym *sym.Symbol, + offset int64) (relocatedOffset int64) + Trampoline func(*Link, *sym.Reloc, *sym.Symbol) + Asmb func(*Link) + Elfreloc1 func(*Link, *sym.Reloc, int64) bool + Elfsetupplt func(*Link) + Gentext func(*Link) + Machoreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool + PEreloc1 func(*sys.Arch, *OutBuf, *sym.Symbol, *sym.Reloc, int64) bool // TLSIEtoLE converts a TLS Initial Executable relocation to // a TLS Local Executable relocation. @@ -416,7 +435,7 @@ func (ctxt *Link) loadlib() { // cgo_import_static and cgo_import_dynamic, // then we want to make it cgo_import_dynamic // now. - if s.Extname != "" && s.Dynimplib != "" && !s.Attr.CgoExport() { + if s.Extname() != "" && s.Dynimplib() != "" && !s.Attr.CgoExport() { s.Type = sym.SDYNIMPORT } else { s.Type = 0 @@ -503,7 +522,8 @@ func (ctxt *Link) loadlib() { // objects, try to read them from the libgcc file. any := false for _, s := range ctxt.Syms.Allsym { - for _, r := range s.R { + for i := range s.R { + r := &s.R[i] // Copying sym.Reloc has measurable impact on performance if r.Sym != nil && r.Sym.Type == sym.SXREF && r.Sym.Name != ".got" { any = true break @@ -557,27 +577,6 @@ func (ctxt *Link) loadlib() { } } - // If type. symbols are visible in the symbol table, rename them - // using a SHA-1 prefix. This reduces binary size (the full - // string of a type symbol can be multiple kilobytes) and removes - // characters that upset external linkers. - // - // Keep the type.. prefix, which parts of the linker (like the - // DWARF generator) know means the symbol is not decodable. - // - // Leave type.runtime. symbols alone, because other parts of - // the linker manipulates them, and also symbols whose names - // would not be shortened by this process. - if typeSymbolMangling(ctxt) { - *FlagW = true // disable DWARF generation - for _, s := range ctxt.Syms.Allsym { - newName := typeSymbolMangle(s.Name) - if newName != s.Name { - ctxt.Syms.Rename(s.Name, newName, int(s.Version)) - } - } - } - // If package versioning is required, generate a hash of the // packages used in the link. if ctxt.BuildMode == BuildModeShared || ctxt.BuildMode == BuildModePlugin || ctxt.CanUsePlugins() { @@ -637,23 +636,38 @@ func (ctxt *Link) loadlib() { } } -// typeSymbolMangling reports whether the linker should shorten the -// names of symbols that represent Go types. +// mangleTypeSym shortens the names of symbols that represent Go types +// if they are visible in the symbol table. // // As the names of these symbols are derived from the string of // the type, they can run to many kilobytes long. So we shorten // them using a SHA-1 when the name appears in the final binary. +// This also removes characters that upset external linkers. // // These are the symbols that begin with the prefix 'type.' and // contain run-time type information used by the runtime and reflect // packages. All Go binaries contain these symbols, but only only // those programs loaded dynamically in multiple parts need these // symbols to have entries in the symbol table. -func typeSymbolMangling(ctxt *Link) bool { - return ctxt.BuildMode == BuildModeShared || ctxt.linkShared || ctxt.BuildMode == BuildModePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil +func (ctxt *Link) mangleTypeSym() { + if ctxt.BuildMode != BuildModeShared && !ctxt.linkShared && ctxt.BuildMode != BuildModePlugin && ctxt.Syms.ROLookup("plugin.Open", 0) == nil { + return + } + + for _, s := range ctxt.Syms.Allsym { + newName := typeSymbolMangle(s.Name) + if newName != s.Name { + ctxt.Syms.Rename(s.Name, newName, int(s.Version), ctxt.Reachparent) + } + } } // typeSymbolMangle mangles the given symbol name into something shorter. +// +// Keep the type.. prefix, which parts of the linker (like the +// DWARF generator) know means the symbol is not decodable. +// Leave type.runtime. symbols alone, because other parts of +// the linker manipulates them. func typeSymbolMangle(name string) string { if !strings.HasPrefix(name, "type.") { return name @@ -1263,7 +1277,26 @@ func (ctxt *Link) hostlink() { } } - argv = append(argv, ldflag...) + // clang, unlike GCC, passes -rdynamic to the linker + // even when linking with -static, causing a linker + // error when using GNU ld. So take out -rdynamic if + // we added it. We do it in this order, rather than + // only adding -rdynamic later, so that -*extldflags + // can override -rdynamic without using -static. + checkStatic := func(arg string) { + if ctxt.IsELF && arg == "-static" { + for i := range argv { + if argv[i] == "-rdynamic" { + argv[i] = "-static" + } + } + } + } + + for _, p := range ldflag { + argv = append(argv, p) + checkStatic(p) + } // When building a program with the default -buildmode=exe the // gc compiler generates code requires DT_TEXTREL in a @@ -1284,20 +1317,7 @@ func (ctxt *Link) hostlink() { for _, p := range strings.Fields(*flagExtldflags) { argv = append(argv, p) - - // clang, unlike GCC, passes -rdynamic to the linker - // even when linking with -static, causing a linker - // error when using GNU ld. So take out -rdynamic if - // we added it. We do it in this order, rather than - // only adding -rdynamic later, so that -*extldflags - // can override -rdynamic without using -static. - if ctxt.IsELF && p == "-static" { - for i := range argv { - if argv[i] == "-rdynamic" { - argv[i] = "-static" - } - } - } + checkStatic(p) } if ctxt.HeadType == objabi.Hwindows { // use gcc linker script to work around gcc bug @@ -1360,7 +1380,12 @@ func linkerFlagSupported(linker, flag string) bool { } }) - cmd := exec.Command(linker, flag, "trivial.c") + var flags []string + flags = append(flags, ldflag...) + flags = append(flags, strings.Fields(*flagExtldflags)...) + flags = append(flags, flag, "trivial.c") + + cmd := exec.Command(linker, flags...) cmd.Dir = *flagTmpdir cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...) out, err := cmd.CombinedOutput() @@ -1681,7 +1706,7 @@ func ldshlibsyms(ctxt *Link, shlib string) { continue } lsym.Type = sym.SDYNIMPORT - lsym.ElfType = elf.ST_TYPE(elfsym.Info) + lsym.SetElfType(elf.ST_TYPE(elfsym.Info)) lsym.Size = int64(elfsym.Size) if elfsym.Section != elf.SHN_UNDEF { // Set .File for the library that actually defines the symbol. @@ -1790,6 +1815,10 @@ func (ctxt *Link) dostkcheck() { ch.up = nil ch.limit = objabi.StackLimit - callsize(ctxt) + if objabi.GOARCH == "arm64" { + // need extra 8 bytes below SP to save FP + ch.limit -= 8 + } // Check every function, but do the nosplit functions in a first pass, // to make the printed failure chains as short as possible. @@ -2087,7 +2116,7 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6 if !s.Attr.Reachable() { continue } - put(ctxt, s, s.Extname, UndefinedSym, 0, nil) + put(ctxt, s, s.Extname(), UndefinedSym, 0, nil) case sym.STLSBSS: if ctxt.LinkMode == LinkExternal { diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 2e66cf857c..48b92724b6 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -86,6 +86,12 @@ type Link struct { // unresolvedSymSet is a set of erroneous unresolved references. // Used to avoid duplicated error messages. unresolvedSymSet map[unresolvedSymKey]bool + + // Used to implement field tracking. + Reachparent map[*sym.Symbol]*sym.Symbol + + compUnits []*compilationUnit // DWARF compilation units + compUnitByPackage map[*sym.Library]*compilationUnit } type unresolvedSymKey struct { diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 8315de5152..b935814ff0 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -724,7 +724,7 @@ func (x machoscmp) Less(i, j int) bool { return k1 < k2 } - return s1.Extname < s2.Extname + return s1.Extname() < s2.Extname() } func machogenasmsym(ctxt *Link) { @@ -763,7 +763,7 @@ func machoShouldExport(ctxt *Link, s *sym.Symbol) bool { if !ctxt.DynlinkingGo() || s.Attr.Local() { return false } - if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname, objabi.PathToPrefix(*flagPluginPath)) { + if ctxt.BuildMode == BuildModePlugin && strings.HasPrefix(s.Extname(), objabi.PathToPrefix(*flagPluginPath)) { return true } if strings.HasPrefix(s.Name, "go.itab.") { @@ -798,13 +798,13 @@ func machosymtab(ctxt *Link) { // symbols like crosscall2 are in pclntab and end up // pointing at the host binary, breaking unwinding. // See Issue #18190. - cexport := !strings.Contains(s.Extname, ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s)) + cexport := !strings.Contains(s.Extname(), ".") && (ctxt.BuildMode != BuildModePlugin || onlycsymbol(s)) if cexport || export { symstr.AddUint8('_') } // replace "·" as ".", because DTrace cannot handle it. - Addstring(symstr, strings.Replace(s.Extname, "·", ".", -1)) + Addstring(symstr, strings.Replace(s.Extname(), "·", ".", -1)) if s.Type == sym.SDYNIMPORT || s.Type == sym.SHOSTOBJ { symtab.AddUint8(0x01) // type N_EXT, external symbol diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index d7929d59fd..905380a1db 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -34,6 +34,7 @@ import ( "bufio" "cmd/internal/objabi" "cmd/internal/sys" + "cmd/link/internal/sym" "flag" "log" "os" @@ -144,6 +145,10 @@ func Main(arch *sys.Arch, theArch Arch) { } } + if objabi.Fieldtrack_enabled != 0 { + ctxt.Reachparent = make(map[*sym.Symbol]*sym.Symbol) + } + startProfile() if ctxt.BuildMode == BuildModeUnset { ctxt.BuildMode = BuildModeExe @@ -203,9 +208,11 @@ func Main(arch *sys.Arch, theArch Arch) { ctxt.dostrdata() deadcode(ctxt) + dwarfGenerateDebugInfo(ctxt) if objabi.Fieldtrack_enabled != 0 { fieldtrack(ctxt) } + ctxt.mangleTypeSym() ctxt.callgraph() ctxt.doelf() diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index 85acb7a11b..db269c78e5 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -54,41 +54,45 @@ var ( ) const ( - IMAGE_FILE_MACHINE_I386 = 0x14c - IMAGE_FILE_MACHINE_AMD64 = 0x8664 - IMAGE_FILE_RELOCS_STRIPPED = 0x0001 - IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 - IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 - IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 - IMAGE_FILE_32BIT_MACHINE = 0x0100 - IMAGE_FILE_DEBUG_STRIPPED = 0x0200 - IMAGE_SCN_CNT_CODE = 0x00000020 - IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 - IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 - IMAGE_SCN_MEM_EXECUTE = 0x20000000 - IMAGE_SCN_MEM_READ = 0x40000000 - IMAGE_SCN_MEM_WRITE = 0x80000000 - IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 - IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 - IMAGE_SCN_ALIGN_32BYTES = 0x600000 - IMAGE_DIRECTORY_ENTRY_EXPORT = 0 - IMAGE_DIRECTORY_ENTRY_IMPORT = 1 - IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 - IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 - IMAGE_DIRECTORY_ENTRY_SECURITY = 4 - IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 - IMAGE_DIRECTORY_ENTRY_DEBUG = 6 - IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 - IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 - IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 - IMAGE_DIRECTORY_ENTRY_TLS = 9 - IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 - IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 - IMAGE_DIRECTORY_ENTRY_IAT = 12 - IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 - IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 - IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 - IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 + IMAGE_FILE_MACHINE_I386 = 0x14c + IMAGE_FILE_MACHINE_AMD64 = 0x8664 + IMAGE_FILE_MACHINE_ARM = 0x1c0 + IMAGE_FILE_MACHINE_ARMNT = 0x1c4 + IMAGE_FILE_RELOCS_STRIPPED = 0x0001 + IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002 + IMAGE_FILE_LINE_NUMS_STRIPPED = 0x0004 + IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020 + IMAGE_FILE_32BIT_MACHINE = 0x0100 + IMAGE_FILE_DEBUG_STRIPPED = 0x0200 + IMAGE_SCN_CNT_CODE = 0x00000020 + IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040 + IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080 + IMAGE_SCN_MEM_EXECUTE = 0x20000000 + IMAGE_SCN_MEM_READ = 0x40000000 + IMAGE_SCN_MEM_WRITE = 0x80000000 + IMAGE_SCN_MEM_DISCARDABLE = 0x2000000 + IMAGE_SCN_LNK_NRELOC_OVFL = 0x1000000 + IMAGE_SCN_ALIGN_32BYTES = 0x600000 + IMAGE_DIRECTORY_ENTRY_EXPORT = 0 + IMAGE_DIRECTORY_ENTRY_IMPORT = 1 + IMAGE_DIRECTORY_ENTRY_RESOURCE = 2 + IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3 + IMAGE_DIRECTORY_ENTRY_SECURITY = 4 + IMAGE_DIRECTORY_ENTRY_BASERELOC = 5 + IMAGE_DIRECTORY_ENTRY_DEBUG = 6 + IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7 + IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7 + IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8 + IMAGE_DIRECTORY_ENTRY_TLS = 9 + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11 + IMAGE_DIRECTORY_ENTRY_IAT = 12 + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13 + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14 + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2 + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3 + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 + IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 0x0100 ) // TODO(crawshaw): add these constants to debug/pe. @@ -109,6 +113,15 @@ const ( IMAGE_REL_AMD64_ADDR32 = 0x0002 IMAGE_REL_AMD64_REL32 = 0x0004 IMAGE_REL_AMD64_SECREL = 0x000B + + IMAGE_REL_ARM_ABSOLUTE = 0x0000 + IMAGE_REL_ARM_ADDR32 = 0x0001 + IMAGE_REL_ARM_ADDR32NB = 0x0002 + IMAGE_REL_ARM_BRANCH24 = 0x0003 + IMAGE_REL_ARM_BRANCH11 = 0x0004 + IMAGE_REL_ARM_SECREL = 0x000F + + IMAGE_REL_BASED_HIGHLOW = 3 ) // Copyright 2009 The Go Authors. All rights reserved. @@ -477,6 +490,8 @@ func (f *peFile) addInitArray(ctxt *Link) *peSection { size = 4 case "amd64": size = 8 + case "arm": + size = 4 } sect := f.addSection(".ctors", size, size) sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ @@ -487,7 +502,7 @@ func (f *peFile) addInitArray(ctxt *Link) *peSection { init_entry := ctxt.Syms.Lookup(*flagEntrySymbol, 0) addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr switch objabi.GOARCH { - case "386": + case "386", "arm": ctxt.Out.Write32(uint32(addr)) case "amd64": ctxt.Out.Write64(addr) @@ -592,6 +607,8 @@ dwarfLoop: ctxt.Out.Write16(IMAGE_REL_I386_DIR32) case "amd64": ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64) + case "arm": + ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32) } return 1 }) @@ -743,6 +760,8 @@ func (f *peFile) writeFileHeader(arch *sys.Arch, out *OutBuf, linkmode LinkMode) fh.Machine = IMAGE_FILE_MACHINE_AMD64 case sys.I386: fh.Machine = IMAGE_FILE_MACHINE_I386 + case sys.ARM: + fh.Machine = IMAGE_FILE_MACHINE_ARMNT } fh.NumberOfSections = uint16(len(f.sections)) @@ -754,7 +773,14 @@ func (f *peFile) writeFileHeader(arch *sys.Arch, out *OutBuf, linkmode LinkMode) if linkmode == LinkExternal { fh.Characteristics = IMAGE_FILE_LINE_NUMS_STRIPPED } else { - fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED + switch arch.Family { + default: + Exitf("write COFF(ext): unknown PE architecture: %v", arch.Family) + case sys.AMD64, sys.I386: + fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED | IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED + case sys.ARM: + fh.Characteristics = IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_DEBUG_STRIPPED + } } if pe64 != 0 { var oh64 pe.OptionalHeader64 @@ -831,6 +857,12 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) { oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI } + switch ctxt.Arch.Family { + case sys.ARM: + oh64.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT + oh.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | IMAGE_DLLCHARACTERISTICS_NX_COMPAT + } + // Disable stack growth as we don't want Windows to // fiddle with the thread stack limits, which we set // ourselves to circumvent the stack checks in the @@ -845,15 +877,18 @@ func (f *peFile) writeOptionalHeader(ctxt *Link) { // and system calls even in "pure" Go code are actually C // calls that may need more stack than we think. // - // The default stack reserve size affects only the main + // The default stack reserve size directly affects only the main // thread, ctrlhandler thread, and profileloop thread. For // these, it must be greater than the stack size assumed by // externalthreadhandler. // - // For other threads we specify stack size in runtime explicitly. - // For these, the reserve must match STACKSIZE in - // runtime/cgo/gcc_windows_{386,amd64}.c and the correspondent - // CreateThread parameter in runtime.newosproc. + // For other threads, the runtime explicitly asks the kernel + // to use the default stack size so that all stacks are + // consistent. + // + // At thread start, in minit, the runtime queries the OS for + // the actual stack bounds so that the stack size doesn't need + // to be hard-coded into the runtime. oh64.SizeOfStackReserve = 0x00200000 if !iscgo { oh64.SizeOfStackCommit = 0x00001000 @@ -986,7 +1021,7 @@ func initdynimport(ctxt *Link) *Dll { continue } for d = dr; d != nil; d = d.next { - if d.name == s.Dynimplib { + if d.name == s.Dynimplib() { m = new(Imp) break } @@ -994,7 +1029,7 @@ func initdynimport(ctxt *Link) *Dll { if d == nil { d = new(Dll) - d.name = s.Dynimplib + d.name = s.Dynimplib() d.next = dr dr = d m = new(Imp) @@ -1005,14 +1040,15 @@ func initdynimport(ctxt *Link) *Dll { // of uinptrs this function consumes. Store the argsize and discard // the %n suffix if any. m.argsize = -1 - if i := strings.IndexByte(s.Extname, '%'); i >= 0 { + extName := s.Extname() + if i := strings.IndexByte(extName, '%'); i >= 0 { var err error - m.argsize, err = strconv.Atoi(s.Extname[i+1:]) + m.argsize, err = strconv.Atoi(extName[i+1:]) if err != nil { Errorf(s, "failed to parse stdcall decoration: %v", err) } m.argsize *= ctxt.Arch.PtrSize - s.Extname = s.Extname[:i] + s.SetExtname(extName[:i]) } m.s = s @@ -1026,7 +1062,7 @@ func initdynimport(ctxt *Link) *Dll { for m = d.ms; m != nil; m = m.next { m.s.Type = sym.SDATA m.s.Grow(int64(ctxt.Arch.PtrSize)) - dynName := m.s.Extname + dynName := m.s.Extname() // only windows/386 requires stdcall decoration if ctxt.Arch.Family == sys.I386 && m.argsize >= 0 { dynName += fmt.Sprintf("@%d", m.argsize) @@ -1097,7 +1133,7 @@ func addimports(ctxt *Link, datsect *peSection) { for m := d.ms; m != nil; m = m.next { m.off = uint64(pefile.nextSectOffset) + uint64(ctxt.Out.Offset()) - uint64(startoff) ctxt.Out.Write16(0) // hint - strput(ctxt.Out, m.s.Extname) + strput(ctxt.Out, m.s.Extname()) } } @@ -1182,7 +1218,7 @@ type byExtname []*sym.Symbol func (s byExtname) Len() int { return len(s) } func (s byExtname) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s byExtname) Less(i, j int) bool { return s[i].Extname < s[j].Extname } +func (s byExtname) Less(i, j int) bool { return s[i].Extname() < s[j].Extname() } func initdynexport(ctxt *Link) { nexport = 0 @@ -1207,7 +1243,7 @@ func addexports(ctxt *Link) { size := binary.Size(&e) + 10*nexport + len(*flagOutfile) + 1 for i := 0; i < nexport; i++ { - size += len(dexport[i].Extname) + 1 + size += len(dexport[i].Extname()) + 1 } if nexport == 0 { @@ -1251,7 +1287,7 @@ func addexports(ctxt *Link) { for i := 0; i < nexport; i++ { out.Write32(uint32(v)) - v += len(dexport[i].Extname) + 1 + v += len(dexport[i].Extname()) + 1 } // put EXPORT Ordinal Table @@ -1263,11 +1299,167 @@ func addexports(ctxt *Link) { out.WriteStringN(*flagOutfile, len(*flagOutfile)+1) for i := 0; i < nexport; i++ { - out.WriteStringN(dexport[i].Extname, len(dexport[i].Extname)+1) + out.WriteStringN(dexport[i].Extname(), len(dexport[i].Extname())+1) } sect.pad(out, uint32(size)) } +// peBaseRelocEntry represents a single relocation entry. +type peBaseRelocEntry struct { + typeOff uint16 + rel *sym.Reloc + sym *sym.Symbol // For debug +} + +// peBaseRelocBlock represents a Base Relocation Block. A block +// is a collection of relocation entries in a page, where each +// entry describes a single relocation. +// The block page RVA (Relative Virtual Address) is the index +// into peBaseRelocTable.blocks. +type peBaseRelocBlock struct { + entries []peBaseRelocEntry +} + +// pePages is a type used to store the list of pages for which there +// are base relocation blocks. This is defined as a type so that +// it can be sorted. +type pePages []uint32 + +func (p pePages) Len() int { return len(p) } +func (p pePages) Swap(i, j int) { p[i], p[j] = p[j], p[i] } +func (p pePages) Less(i, j int) bool { return p[i] < p[j] } + +// A PE base relocation table is a list of blocks, where each block +// contains relocation information for a single page. The blocks +// must be emitted in order of page virtual address. +// See https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format#the-reloc-section-image-only +type peBaseRelocTable struct { + blocks map[uint32]peBaseRelocBlock + + // pePages is a list of keys into blocks map. + // It is stored separately for ease of sorting. + pages pePages +} + +func (rt *peBaseRelocTable) init(ctxt *Link) { + rt.blocks = make(map[uint32]peBaseRelocBlock) +} + +func (rt *peBaseRelocTable) addentry(ctxt *Link, s *sym.Symbol, r *sym.Reloc) { + // pageSize is the size in bytes of a page + // described by a base relocation block. + const pageSize = 0x1000 + const pageMask = pageSize - 1 + + addr := s.Value + int64(r.Off) - int64(PEBASE) + page := uint32(addr &^ pageMask) + off := uint32(addr & pageMask) + + b, ok := rt.blocks[page] + if !ok { + rt.pages = append(rt.pages, page) + } + + e := peBaseRelocEntry{ + typeOff: uint16(off & 0xFFF), + rel: r, + sym: s, + } + + // Set entry type + switch r.Siz { + default: + Exitf("unsupported relocation size %d\n", r.Siz) + case 4: + e.typeOff |= uint16(IMAGE_REL_BASED_HIGHLOW << 12) + } + + b.entries = append(b.entries, e) + rt.blocks[page] = b +} + +func (rt *peBaseRelocTable) write(ctxt *Link) { + out := ctxt.Out + + // sort the pages array + sort.Sort(rt.pages) + + for _, p := range rt.pages { + b := rt.blocks[p] + const sizeOfPEbaseRelocBlock = 8 // 2 * sizeof(uint32) + blockSize := uint32(sizeOfPEbaseRelocBlock + len(b.entries)*2) + out.Write32(p) + out.Write32(blockSize) + + for _, e := range b.entries { + out.Write16(e.typeOff) + } + } +} + +func addPEBaseRelocSym(ctxt *Link, s *sym.Symbol, rt *peBaseRelocTable) { + for ri := 0; ri < len(s.R); ri++ { + r := &s.R[ri] + + if r.Sym == nil { + continue + } + if !r.Sym.Attr.Reachable() { + continue + } + if r.Type >= 256 { + continue + } + if r.Siz == 0 { // informational relocation + continue + } + if r.Type == objabi.R_DWARFFILEREF { + continue + } + + switch r.Type { + default: + case objabi.R_ADDR: + rt.addentry(ctxt, s, r) + } + } +} + +func addPEBaseReloc(ctxt *Link) { + // We only generate base relocation table for ARM (and ... ARM64), x86, and AMD64 are marked as legacy + // archs and can use fixed base with no base relocation information + switch ctxt.Arch.Family { + default: + return + case sys.ARM: + } + + var rt peBaseRelocTable + rt.init(ctxt) + + // Get relocation information + for _, s := range ctxt.Textp { + addPEBaseRelocSym(ctxt, s, &rt) + } + for _, s := range datap { + addPEBaseRelocSym(ctxt, s, &rt) + } + + // Write relocation information + startoff := ctxt.Out.Offset() + rt.write(ctxt) + size := ctxt.Out.Offset() - startoff + + // Add a PE section and pad it at the end + rsect := pefile.addSection(".reloc", int(size), int(size)) + rsect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE + rsect.checkOffset(startoff) + rsect.pad(ctxt.Out, uint32(size)) + + pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = rsect.virtualAddress + pefile.dataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = rsect.virtualSize +} + func (ctxt *Link) dope() { /* relocation table */ rel := ctxt.Syms.Lookup(".rel", 0) @@ -1323,7 +1515,7 @@ func Asmbpe(ctxt *Link) { switch ctxt.Arch.Family { default: Exitf("unknown PE architecture: %v", ctxt.Arch.Family) - case sys.AMD64, sys.I386: + case sys.AMD64, sys.I386, sys.ARM: } t := pefile.addSection(".text", int(Segtext.Length), int(Segtext.Length)) @@ -1377,6 +1569,7 @@ func Asmbpe(ctxt *Link) { if ctxt.LinkMode != LinkExternal { addimports(ctxt, d) addexports(ctxt) + addPEBaseReloc(ctxt) } pefile.writeSymbolTableAndStringTable(ctxt) addpersrc(ctxt) diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 88d476710b..2a04ef3824 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -93,7 +93,7 @@ func putelfsym(ctxt *Link, x *sym.Symbol, s string, t SymbolType, addr int64, go case UndefinedSym: // ElfType is only set for symbols read from Go shared libraries, but // for other symbols it is left as STT_NOTYPE which is fine. - typ = int(x.ElfType) + typ = int(x.ElfType()) case TLSSym: typ = STT_TLS diff --git a/src/cmd/link/internal/ld/testdata/issue26237/src/b.dir/b.go b/src/cmd/link/internal/ld/testdata/issue26237/src/b.dir/b.go new file mode 100644 index 0000000000..ca577490bc --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue26237/src/b.dir/b.go @@ -0,0 +1,16 @@ +package b + +var q int + +func Top(x int) int { + q += 1 + if q != x { + return 3 + } + return 4 +} + +func OOO(x int) int { + defer func() { q += x & 7 }() + return Top(x + 1) +} diff --git a/src/cmd/link/internal/ld/testdata/issue26237/src/main/main.go b/src/cmd/link/internal/ld/testdata/issue26237/src/main/main.go new file mode 100644 index 0000000000..6fdaa0bfa1 --- /dev/null +++ b/src/cmd/link/internal/ld/testdata/issue26237/src/main/main.go @@ -0,0 +1,16 @@ +package main + +import ( + "fmt" + + b "b.dir" +) + +var skyx int + +func main() { + skyx += b.OOO(skyx) + if b.Top(1) == 99 { + fmt.Printf("Beware the Jabberwock, my son!\n") + } +} diff --git a/src/cmd/link/internal/loadelf/ldelf.go b/src/cmd/link/internal/loadelf/ldelf.go index 301c2ce116..d85d91948a 100644 --- a/src/cmd/link/internal/loadelf/ldelf.go +++ b/src/cmd/link/internal/loadelf/ldelf.go @@ -805,7 +805,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i s.Type = sect.sym.Type s.Attr |= sym.AttrSubSymbol if !s.Attr.CgoExportDynamic() { - s.Dynimplib = "" // satisfy dynimport + s.SetDynimplib("") // satisfy dynimport } s.Value = int64(elfsym.value) s.Size = int64(elfsym.size) @@ -820,7 +820,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i if elfobj.machine == ElfMachPower64 { flag := int(elfsym.other) >> 5 if 2 <= flag && flag <= 6 { - s.Localentry = 1 << uint(flag-2) + s.SetLocalentry(1 << uint(flag-2)) } else if flag == 7 { return errorf("%v: invalid sym.other 0x%x", s, elfsym.other) } diff --git a/src/cmd/link/internal/loadmacho/ldmacho.go b/src/cmd/link/internal/loadmacho/ldmacho.go index e6b0f70e38..85aa606ff5 100644 --- a/src/cmd/link/internal/loadmacho/ldmacho.go +++ b/src/cmd/link/internal/loadmacho/ldmacho.go @@ -644,7 +644,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, pkg string, length i s.Outer = outer s.Value = int64(machsym.value - sect.addr) if !s.Attr.CgoExportDynamic() { - s.Dynimplib = "" // satisfy dynimport + s.SetDynimplib("") // satisfy dynimport } if outer.Type == sym.STEXT { if s.Attr.External() && !s.Attr.DuplicateOK() { diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go index c8fae37898..ac07d5c35d 100644 --- a/src/cmd/link/internal/loadpe/ldpe.go +++ b/src/cmd/link/internal/loadpe/ldpe.go @@ -101,6 +101,19 @@ const ( IMAGE_REL_AMD64_SREL32 = 0x000E IMAGE_REL_AMD64_PAIR = 0x000F IMAGE_REL_AMD64_SSPAN32 = 0x0010 + IMAGE_REL_ARM_ABSOLUTE = 0x0000 + IMAGE_REL_ARM_ADDR32 = 0x0001 + IMAGE_REL_ARM_ADDR32NB = 0x0002 + IMAGE_REL_ARM_BRANCH24 = 0x0003 + IMAGE_REL_ARM_BRANCH11 = 0x0004 + IMAGE_REL_ARM_SECTION = 0x000E + IMAGE_REL_ARM_SECREL = 0x000F + IMAGE_REL_ARM_MOV32 = 0x0010 + IMAGE_REL_THUMB_MOV32 = 0x0011 + IMAGE_REL_THUMB_BRANCH20 = 0x0012 + IMAGE_REL_THUMB_BRANCH24 = 0x0014 + IMAGE_REL_THUMB_BLX23 = 0x0015 + IMAGE_REL_ARM_PAIR = 0x0016 ) // TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe. @@ -241,30 +254,56 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng rp.Sym = gosym rp.Siz = 4 rp.Off = int32(r.VirtualAddress) - switch r.Type { + switch arch.Family { default: - return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) + return nil, nil, fmt.Errorf("%s: unsupported arch %v", pn, arch.Family) + case sys.I386, sys.AMD64: + switch r.Type { + default: + return nil, nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, sectsyms[rsect], r.Type) - case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, - IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 - IMAGE_REL_AMD64_ADDR32NB: - rp.Type = objabi.R_PCREL + case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32, + IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32 + IMAGE_REL_AMD64_ADDR32NB: + rp.Type = objabi.R_PCREL - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) + rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: - rp.Type = objabi.R_ADDR + case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32: + rp.Type = objabi.R_ADDR - // load addend from image - rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) + // load addend from image + rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) - case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 - rp.Siz = 8 + case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64 + rp.Siz = 8 - rp.Type = objabi.R_ADDR + rp.Type = objabi.R_ADDR - // load addend from image - rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:])) + // load addend from image + rp.Add = int64(binary.LittleEndian.Uint64(sectdata[rsect][rp.Off:])) + } + + case sys.ARM: + switch r.Type { + default: + return nil, nil, fmt.Errorf("%s: %v: unknown ARM relocation type %v", pn, sectsyms[rsect], r.Type) + + case IMAGE_REL_ARM_SECREL: + rp.Type = objabi.R_PCREL + + rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) + + case IMAGE_REL_ARM_ADDR32: + rp.Type = objabi.R_ADDR + + rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) + + case IMAGE_REL_ARM_BRANCH24: + rp.Type = objabi.R_CALLARM + + rp.Add = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rp.Off:]))) + } } // ld -r could generate multiple section symbols for the @@ -319,7 +358,7 @@ func Load(arch *sys.Arch, syms *sym.Symbols, input *bio.Reader, pkg string, leng if pesym.SectionNumber == 0 { // extern if s.Type == sym.SDYNIMPORT { - s.Plt = -2 // flag for dynimport in PE object files. + s.SetPlt(-2) // flag for dynimport in PE object files. } if s.Type == sym.SXREF && pesym.Value > 0 { // global data s.Type = sym.SNOPTRDATA @@ -440,7 +479,7 @@ func readpesym(arch *sys.Arch, syms *sym.Symbols, f *pe.File, pesym *pe.COFFSymb s.Type = sym.SXREF } if strings.HasPrefix(symname, "__imp_") { - s.Got = -2 // flag for __imp_ + s.SetGot(-2) // flag for __imp_ } return s, nil diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go index 306d53f571..8409e43afc 100644 --- a/src/cmd/link/internal/mips/asm.go +++ b/src/cmd/link/internal/mips/asm.go @@ -82,23 +82,25 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se return false } -func applyrel(arch *sys.Arch, r *sym.Reloc, s *sym.Symbol, val *int64, t int64) { +func applyrel(arch *sys.Arch, r *sym.Reloc, s *sym.Symbol, val int64, t int64) int64 { o := arch.ByteOrder.Uint32(s.P[r.Off:]) switch r.Type { case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSTLS: - *val = int64(o&0xffff0000 | uint32(t)&0xffff) + return int64(o&0xffff0000 | uint32(t)&0xffff) case objabi.R_ADDRMIPSU: - *val = int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff) + return int64(o&0xffff0000 | uint32((t+(1<<15))>>16)&0xffff) case objabi.R_CALLMIPS, objabi.R_JMPMIPS: - *val = int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000) + return int64(o&0xfc000000 | uint32(t>>2)&^0xfc000000) + default: + return val } } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { switch r.Type { default: - return false + return val, false case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: r.Done = false @@ -114,28 +116,23 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { ld.Errorf(s, "missing section for %s", rs.Name) } r.Xsym = rs - applyrel(ctxt.Arch, r, s, val, r.Xadd) - return true + return applyrel(ctxt.Arch, r, s, val, r.Xadd), true case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS: r.Done = false r.Xsym = r.Sym r.Xadd = r.Add - applyrel(ctxt.Arch, r, s, val, r.Add) - return true + return applyrel(ctxt.Arch, r, s, val, r.Add), true } } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: t := ld.Symaddr(r.Sym) + r.Add - applyrel(ctxt.Arch, r, s, val, t) - return true + return applyrel(ctxt.Arch, r, s, val, t), true case objabi.R_CALLMIPS, objabi.R_JMPMIPS: t := ld.Symaddr(r.Sym) + r.Add @@ -148,19 +145,17 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t) } - applyrel(ctxt.Arch, r, s, val, t) - return true + return applyrel(ctxt.Arch, r, s, val, t), true case objabi.R_ADDRMIPSTLS: // thread pointer is at 0x7000 offset from the start of TLS data area t := ld.Symaddr(r.Sym) + r.Add - 0x7000 if t < -32768 || t >= 32678 { ld.Errorf(s, "TLS offset out of range %d", t) } - applyrel(ctxt.Arch, r, s, val, t) - return true + return applyrel(ctxt.Arch, r, s, val, t), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go index 295a0aafae..51eba596dc 100644 --- a/src/cmd/link/internal/mips64/asm.go +++ b/src/cmd/link/internal/mips64/asm.go @@ -99,11 +99,11 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se return false } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { switch r.Type { default: - return false + return val, false case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: r.Done = false @@ -121,34 +121,30 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { } r.Xsym = rs - return true + return val, true case objabi.R_ADDRMIPSTLS, objabi.R_CALLMIPS, objabi.R_JMPMIPS: r.Done = false r.Xsym = r.Sym r.Xadd = r.Add - return true + return val, true } } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true case objabi.R_ADDRMIPS, objabi.R_ADDRMIPSU: t := ld.Symaddr(r.Sym) + r.Add o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) if r.Type == objabi.R_ADDRMIPS { - *val = int64(o1&0xffff0000 | uint32(t)&0xffff) - } else { - *val = int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff) + return int64(o1&0xffff0000 | uint32(t)&0xffff), true } - return true + return int64(o1&0xffff0000 | uint32((t+1<<15)>>16)&0xffff), true case objabi.R_ADDRMIPSTLS: // thread pointer is at 0x7000 offset from the start of TLS data area t := ld.Symaddr(r.Sym) + r.Add - 0x7000 @@ -156,18 +152,16 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { ld.Errorf(s, "TLS offset out of range %d", t) } o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) - *val = int64(o1&0xffff0000 | uint32(t)&0xffff) - return true + return int64(o1&0xffff0000 | uint32(t)&0xffff), true case objabi.R_CALLMIPS, objabi.R_JMPMIPS: // Low 26 bits = (S + A) >> 2 t := ld.Symaddr(r.Sym) + r.Add o1 := ctxt.Arch.ByteOrder.Uint32(s.P[r.Off:]) - *val = int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000) - return true + return int64(o1&0xfc000000 | uint32(t>>2)&^0xfc000000), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { diff --git a/src/cmd/link/internal/objfile/objfile.go b/src/cmd/link/internal/objfile/objfile.go index 67868be2a1..e3800de304 100644 --- a/src/cmd/link/internal/objfile/objfile.go +++ b/src/cmd/link/internal/objfile/objfile.go @@ -318,6 +318,8 @@ overwrite: pc.InlTree[i].Func = r.readSymIndex() } + s.FuncInfo.IsStmtSym = r.syms.Lookup(dwarf.IsStmtPrefix+s.Name, int(s.Version)) + s.Lib = r.lib if !dupok { if s.Attr.OnList() { diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go index 11fdf1fb05..9445fbebcb 100644 --- a/src/cmd/link/internal/ppc64/asm.go +++ b/src/cmd/link/internal/ppc64/asm.go @@ -236,7 +236,7 @@ func gencallstub(ctxt *ld.Link, abicase int, stub *sym.Symbol, targ *sym.Symbol) r.Off = int32(stub.Size) r.Sym = plt - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) r.Siz = 2 if ctxt.Arch.ByteOrder == binary.BigEndian { r.Off += int32(r.Siz) @@ -247,7 +247,7 @@ func gencallstub(ctxt *ld.Link, abicase int, stub *sym.Symbol, targ *sym.Symbol) r = stub.AddRel() r.Off = int32(stub.Size) r.Sym = plt - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) r.Siz = 2 if ctxt.Arch.ByteOrder == binary.BigEndian { r.Off += int32(r.Siz) @@ -280,7 +280,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { // callee. Hence, we need to go to the local entry // point. (If we don't do this, the callee will try // to use r12 to compute r2.) - r.Add += int64(r.Sym.Localentry) * 4 + r.Add += int64(r.Sym.Localentry()) * 4 if targ.Type == sym.SDYNIMPORT { // Should have been handled in elfsetupplt @@ -474,14 +474,14 @@ func symtoc(ctxt *ld.Link, s *sym.Symbol) int64 { return toc.Value } -func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) int64 { var o1, o2 uint32 if ctxt.Arch.ByteOrder == binary.BigEndian { - o1 = uint32(*val >> 32) - o2 = uint32(*val) + o1 = uint32(val >> 32) + o2 = uint32(val) } else { - o1 = uint32(*val) - o2 = uint32(*val >> 32) + o1 = uint32(val) + o2 = uint32(val >> 32) } // We are spreading a 31-bit address across two instructions, putting the @@ -510,15 +510,13 @@ func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool } o2 |= uint32(t) & 0xfffc default: - return false + return -1 } if ctxt.Arch.ByteOrder == binary.BigEndian { - *val = int64(o1)<<32 | int64(o2) - } else { - *val = int64(o2)<<32 | int64(o1) + return int64(o1)<<32 | int64(o2) } - return true + return int64(o2)<<32 | int64(o1) } // resolve direct jump relocation r in s, and add trampoline if necessary @@ -623,17 +621,17 @@ func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, o arch.ByteOrder.PutUint32(tramp.P[12:], o4) } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { switch r.Type { default: - return false + return val, false case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE: r.Done = false // check Outer is nil, Type is TLSBSS? r.Xadd = r.Add r.Xsym = r.Sym - return true + return val, true case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS, objabi.R_ADDRPOWER_TOCREL, @@ -655,24 +653,22 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { } r.Xsym = rs - return true + return val, true case objabi.R_CALLPOWER: r.Done = false r.Xsym = r.Sym r.Xadd = r.Add - return true + return val, true } } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS: - return archrelocaddr(ctxt, r, s, val) + return archrelocaddr(ctxt, r, s, val), true case objabi.R_CALLPOWER: // Bits 6 through 29 = (S + A - P) >> 2 @@ -686,12 +682,10 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { if int64(int32(t<<6)>>6) != t { ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t) } - *val |= int64(uint32(t) &^ 0xfc000003) - return true + return val | int64(uint32(t)&^0xfc000003), true case objabi.R_POWER_TOC: // S + A - .TOC. - *val = ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s) + return ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s), true - return true case objabi.R_POWER_TLS_LE: // The thread pointer points 0x7000 bytes after the start of the // thread local storage area as documented in section "3.7.2 TLS @@ -701,11 +695,10 @@ func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { if int64(int16(v)) != v { ld.Errorf(s, "TLS offset out of range %d", v) } - *val = (*val &^ 0xffff) | (v & 0xffff) - return true + return (val &^ 0xffff) | (v & 0xffff), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { @@ -800,7 +793,7 @@ overflow: } func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt >= 0 { + if s.Plt() >= 0 { return } @@ -832,11 +825,11 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { // JMP_SLOT dynamic relocation for it. // // TODO(austin): ABI v1 is different - s.Plt = int32(plt.Size) + s.SetPlt(int32(plt.Size)) plt.Size += 8 - rela.AddAddrPlus(ctxt.Arch, plt, int64(s.Plt)) + rela.AddAddrPlus(ctxt.Arch, plt, int64(s.Plt())) rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_PPC64_JMP_SLOT))) rela.AddUint64(ctxt.Arch, 0) } else { diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go index 634ba98dd3..88199f3a56 100644 --- a/src/cmd/link/internal/s390x/asm.go +++ b/src/cmd/link/internal/s390x/asm.go @@ -157,7 +157,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt) + r.Add += int64(targ.Plt()) } return true @@ -168,7 +168,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt) + r.Add += int64(targ.Plt()) } return true @@ -224,7 +224,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { r.Type = objabi.R_PCREL r.Variant = sym.RV_390_DBL r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) r.Add += int64(r.Siz) return true } @@ -285,7 +285,7 @@ func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool { case objabi.R_PCRELDBL, objabi.R_CALL: isdbl = true } - if r.Xsym.Type == sym.SDYNIMPORT && (r.Xsym.ElfType == elf.STT_FUNC || r.Type == objabi.R_CALL) { + if r.Xsym.Type == sym.SDYNIMPORT && (r.Xsym.ElfType() == elf.STT_FUNC || r.Type == objabi.R_CALL) { if isdbl { switch r.Siz { case 2: @@ -384,21 +384,19 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se return false } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { - return false + return val, false } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { @@ -419,7 +417,7 @@ func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 } func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt >= 0 { + if s.Plt() >= 0 { return } @@ -474,7 +472,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_JMP_SLOT))) rela.AddUint64(ctxt.Arch, 0) - s.Plt = int32(plt.Size - 32) + s.SetPlt(int32(plt.Size - 32)) } else { ld.Errorf(s, "addpltsym: unsupported binary format") @@ -482,18 +480,18 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { } func addgotsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Got >= 0 { + if s.Got() >= 0 { return } ld.Adddynsym(ctxt, s) got := ctxt.Syms.Lookup(".got", 0) - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) got.AddUint64(ctxt.Arch, 0) if ctxt.IsELF { rela := ctxt.Syms.Lookup(".rela", 0) - rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got)) + rela.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_390_GLOB_DAT))) rela.AddUint64(ctxt.Arch, 0) } else { diff --git a/src/cmd/link/internal/sym/reloc.go b/src/cmd/link/internal/sym/reloc.go index fc62c385f4..da696d327b 100644 --- a/src/cmd/link/internal/sym/reloc.go +++ b/src/cmd/link/internal/sym/reloc.go @@ -83,11 +83,11 @@ func RelocName(arch *sys.Arch, r objabi.RelocType) string { case sys.I386: return elf.R_386(nr).String() case sys.MIPS, sys.MIPS64: - // return elf.R_MIPS(nr).String() + return elf.R_MIPS(nr).String() case sys.PPC64: - // return elf.R_PPC64(nr).String() + return elf.R_PPC64(nr).String() case sys.S390X: - // return elf.R_390(nr).String() + return elf.R_390(nr).String() default: panic("unreachable") } diff --git a/src/cmd/link/internal/sym/sizeof_test.go b/src/cmd/link/internal/sym/sizeof_test.go new file mode 100644 index 0000000000..da4602a161 --- /dev/null +++ b/src/cmd/link/internal/sym/sizeof_test.go @@ -0,0 +1,39 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !nacl + +package sym + +import ( + "reflect" + "testing" + "unsafe" +) + +// Assert that the size of important structures do not change unexpectedly. + +func TestSizeof(t *testing.T) { + const nbit = unsafe.Sizeof(uintptr(0)) * 8 + const _64bit = nbit == 64 + + var tests = []struct { + val interface{} // type as a value + _32bit uintptr // size on 32bit platforms + _64bit uintptr // size on 64bit platforms + }{ + {Symbol{}, 108, 176}, + } + + for _, tt := range tests { + want := tt._32bit + if _64bit { + want = tt._64bit + } + got := reflect.TypeOf(tt.val).Size() + if want != got { + t.Errorf("%d bit unsafe.Sizeof(%T) = %d, want %d", nbit, tt.val, got, want) + } + } +} diff --git a/src/cmd/link/internal/sym/symbol.go b/src/cmd/link/internal/sym/symbol.go index b3ff6c4e19..a6c2aaea77 100644 --- a/src/cmd/link/internal/sym/symbol.go +++ b/src/cmd/link/internal/sym/symbol.go @@ -15,30 +15,20 @@ import ( // Symbol is an entry in the symbol table. type Symbol struct { Name string - Extname string Type SymKind Version int16 Attr Attribute - Localentry uint8 Dynid int32 - Plt int32 - Got int32 Align int32 Elfsym int32 LocalElfsym int32 Value int64 Size int64 - // ElfType is set for symbols read from shared libraries by ldshlibsyms. It - // is not set for symbols defined by the packages being linked or by symbols - // read by ldelf (and so is left as elf.STT_NOTYPE). - ElfType elf.SymType Sub *Symbol Outer *Symbol Gotype *Symbol - Reachparent *Symbol File string - Dynimplib string - Dynimpvers string + auxinfo *AuxSymbol Sect *Section FuncInfo *FuncInfo Lib *Library // Package defining this symbol @@ -47,6 +37,20 @@ type Symbol struct { R []Reloc } +// AuxSymbol contains less-frequently used sym.Symbol fields. +type AuxSymbol struct { + extname string + dynimplib string + dynimpvers string + localentry uint8 + plt int32 + got int32 + // ElfType is set for symbols read from shared libraries by ldshlibsyms. It + // is not set for symbols defined by the packages being linked or by symbols + // read by ldelf (and so is left as elf.STT_NOTYPE). + elftype elf.SymType +} + func (s *Symbol) String() string { if s.Version == 0 { return s.Name @@ -265,6 +269,132 @@ func (s *Symbol) setUintXX(arch *sys.Arch, off int64, v uint64, wid int64) int64 return off + wid } +func (s *Symbol) makeAuxInfo() { + if s.auxinfo == nil { + s.auxinfo = &AuxSymbol{extname: s.Name, plt: -1, got: -1} + } +} + +func (s *Symbol) Extname() string { + if s.auxinfo == nil { + return s.Name + } + return s.auxinfo.extname +} + +func (s *Symbol) SetExtname(n string) { + if s.auxinfo == nil { + if s.Name == n { + return + } + s.makeAuxInfo() + } + s.auxinfo.extname = n +} + +func (s *Symbol) Dynimplib() string { + if s.auxinfo == nil { + return "" + } + return s.auxinfo.dynimplib +} + +func (s *Symbol) Dynimpvers() string { + if s.auxinfo == nil { + return "" + } + return s.auxinfo.dynimpvers +} + +func (s *Symbol) SetDynimplib(lib string) { + if s.auxinfo == nil { + s.makeAuxInfo() + } + s.auxinfo.dynimplib = lib +} + +func (s *Symbol) SetDynimpvers(vers string) { + if s.auxinfo == nil { + s.makeAuxInfo() + } + s.auxinfo.dynimpvers = vers +} + +func (s *Symbol) ResetDyninfo() { + if s.auxinfo != nil { + s.auxinfo.dynimplib = "" + s.auxinfo.dynimpvers = "" + } +} + +func (s *Symbol) Localentry() uint8 { + if s.auxinfo == nil { + return 0 + } + return s.auxinfo.localentry +} + +func (s *Symbol) SetLocalentry(val uint8) { + if s.auxinfo == nil { + if val != 0 { + return + } + s.makeAuxInfo() + } + s.auxinfo.localentry = val +} + +func (s *Symbol) Plt() int32 { + if s.auxinfo == nil { + return -1 + } + return s.auxinfo.plt +} + +func (s *Symbol) SetPlt(val int32) { + if s.auxinfo == nil { + if val == -1 { + return + } + s.makeAuxInfo() + } + s.auxinfo.plt = val +} + +func (s *Symbol) Got() int32 { + if s.auxinfo == nil { + return -1 + } + return s.auxinfo.got +} + +func (s *Symbol) SetGot(val int32) { + if s.auxinfo == nil { + if val == -1 { + return + } + s.makeAuxInfo() + } + s.auxinfo.got = val +} + +func (s *Symbol) ElfType() elf.SymType { + if s.auxinfo == nil { + return elf.STT_NOTYPE + } + return s.auxinfo.elftype +} + +func (s *Symbol) SetElfType(val elf.SymType) { + if s.auxinfo == nil { + if val == elf.STT_NOTYPE { + return + } + s.makeAuxInfo() + } + s.auxinfo.elftype = val +} + // SortSub sorts a linked-list (by Sub) of *Symbol by Value. // Used for sub-symbols when loading host objects (see e.g. ldelf.go). func SortSub(l *Symbol) *Symbol { @@ -348,6 +478,7 @@ type FuncInfo struct { Pcline Pcdata Pcinline Pcdata Pcdata []Pcdata + IsStmtSym *Symbol Funcdata []*Symbol Funcdataoff []int64 File []*Symbol diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go index 98a5ae67b8..d79d1d8b1d 100644 --- a/src/cmd/link/internal/sym/symbols.go +++ b/src/cmd/link/internal/sym/symbols.go @@ -59,8 +59,6 @@ func (syms *Symbols) Newsym(name string, v int) *Symbol { syms.symbolBatch = batch[1:] s.Dynid = -1 - s.Plt = -1 - s.Got = -1 s.Name = name s.Version = int16(v) syms.Allsym = append(syms.Allsym, s) @@ -77,7 +75,6 @@ func (syms *Symbols) Lookup(name string, v int) *Symbol { return s } s = syms.Newsym(name, v) - s.Extname = s.Name m[name] = s return s } @@ -95,11 +92,12 @@ func (syms *Symbols) IncVersion() int { } // Rename renames a symbol. -func (syms *Symbols) Rename(old, new string, v int) { +func (syms *Symbols) Rename(old, new string, v int, reachparent map[*Symbol]*Symbol) { s := syms.hash[v][old] + oldExtName := s.Extname() s.Name = new - if s.Extname == old { - s.Extname = new + if oldExtName == old { + s.SetExtname(new) } delete(syms.hash[v], old) @@ -108,8 +106,16 @@ func (syms *Symbols) Rename(old, new string, v int) { syms.hash[v][new] = s } else { if s.Type == 0 { + dup.Attr |= s.Attr + if s.Attr.Reachable() && reachparent != nil { + reachparent[dup] = reachparent[s] + } *s = *dup } else if dup.Type == 0 { + s.Attr |= dup.Attr + if dup.Attr.Reachable() && reachparent != nil { + reachparent[s] = reachparent[dup] + } *dup = *s syms.hash[v][new] = s } diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go index 7cc6bef6b7..bffbc7c8a6 100644 --- a/src/cmd/link/internal/wasm/asm.go +++ b/src/cmd/link/internal/wasm/asm.go @@ -11,6 +11,7 @@ import ( "cmd/link/internal/sym" "io" "regexp" + "runtime" ) const ( @@ -172,6 +173,7 @@ func asmb(ctxt *ld.Link) { writeBuildID(ctxt, buildid) } + writeGoVersion(ctxt) writeTypeSec(ctxt, types) writeImportSec(ctxt, hostImports) writeFunctionSec(ctxt, fns) @@ -220,6 +222,13 @@ func writeBuildID(ctxt *ld.Link, buildid []byte) { writeSecSize(ctxt, sizeOffset) } +func writeGoVersion(ctxt *ld.Link) { + sizeOffset := writeSecHeader(ctxt, sectionCustom) + writeName(ctxt.Out, "go.version") + ctxt.Out.Write([]byte(runtime.Version())) + writeSecSize(ctxt, sizeOffset) +} + // writeTypeSec writes the section that declares all function types // so they can be referenced by index. func writeTypeSec(ctxt *ld.Link, types []*wasmFuncType) { diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go index 3150aac6cf..1744ab4d99 100644 --- a/src/cmd/link/internal/x86/asm.go +++ b/src/cmd/link/internal/x86/asm.go @@ -197,7 +197,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add += int64(targ.Plt) + r.Add += int64(targ.Plt()) } return true @@ -230,7 +230,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { addgotsym(ctxt, targ) r.Type = objabi.R_CONST // write r->add during relocsym r.Sym = nil - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) return true case 256 + objabi.RelocType(elf.R_386_GOTOFF): @@ -261,7 +261,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { if targ.Type == sym.SDYNIMPORT { addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) r.Type = objabi.R_PCREL return true } @@ -285,7 +285,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { addgotsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".got", 0) - r.Add += int64(targ.Got) + r.Add += int64(targ.Got()) r.Type = objabi.R_PCREL return true } @@ -303,7 +303,7 @@ func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool { } addpltsym(ctxt, targ) r.Sym = ctxt.Syms.Lookup(".plt", 0) - r.Add = int64(targ.Plt) + r.Add = int64(targ.Plt()) return true case objabi.R_ADDR: @@ -491,20 +491,18 @@ func pereloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, secto return true } -func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool { +func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) { if ctxt.LinkMode == ld.LinkExternal { - return false + return val, false } switch r.Type { case objabi.R_CONST: - *val = r.Add - return true + return r.Add, true case objabi.R_GOTOFF: - *val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)) - return true + return ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0)), true } - return false + return val, false } func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 { @@ -540,7 +538,7 @@ func elfsetupplt(ctxt *ld.Link) { } func addpltsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Plt >= 0 { + if s.Plt() >= 0 { return } @@ -578,7 +576,7 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_JMP_SLOT))) - s.Plt = int32(plt.Size - 16) + s.SetPlt(int32(plt.Size - 16)) } else if ctxt.HeadType == objabi.Hdarwin { // Same laziness as in 6l. @@ -589,29 +587,29 @@ func addpltsym(ctxt *ld.Link, s *sym.Symbol) { ctxt.Syms.Lookup(".linkedit.plt", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) // jmpq *got+size(IP) - s.Plt = int32(plt.Size) + s.SetPlt(int32(plt.Size)) plt.AddUint8(0xff) plt.AddUint8(0x25) - plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got)) + plt.AddAddrPlus(ctxt.Arch, ctxt.Syms.Lookup(".got", 0), int64(s.Got())) } else { ld.Errorf(s, "addpltsym: unsupported binary format") } } func addgotsym(ctxt *ld.Link, s *sym.Symbol) { - if s.Got >= 0 { + if s.Got() >= 0 { return } ld.Adddynsym(ctxt, s) got := ctxt.Syms.Lookup(".got", 0) - s.Got = int32(got.Size) + s.SetGot(int32(got.Size)) got.AddUint32(ctxt.Arch, 0) if ctxt.IsELF { rel := ctxt.Syms.Lookup(".rel", 0) - rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got)) + rel.AddAddrPlus(ctxt.Arch, got, int64(s.Got())) rel.AddUint32(ctxt.Arch, ld.ELF32_R_INFO(uint32(s.Dynid), uint32(elf.R_386_GLOB_DAT))) } else if ctxt.HeadType == objabi.Hdarwin { ctxt.Syms.Lookup(".linkedit.got", 0).AddUint32(ctxt.Arch, uint32(s.Dynid)) diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go index 71636990a1..6a60697ebd 100644 --- a/src/cmd/objdump/main.go +++ b/src/cmd/objdump/main.go @@ -75,6 +75,7 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() dis, err := f.Disasm() if err != nil { @@ -87,7 +88,6 @@ func main() { case 1: // disassembly of entire object dis.Print(os.Stdout, symRE, 0, ^uint64(0), *printCode) - os.Exit(0) case 3: // disassembly of PC range @@ -100,6 +100,5 @@ func main() { log.Fatalf("invalid end PC: %v", err) } dis.Print(os.Stdout, symRE, start, end, *printCode) - os.Exit(0) } } diff --git a/src/cmd/pprof/readlineui.go b/src/cmd/pprof/readlineui.go index 6e91816f9b..bf2f321184 100644 --- a/src/cmd/pprof/readlineui.go +++ b/src/cmd/pprof/readlineui.go @@ -34,6 +34,10 @@ type readlineUI struct { } func newReadlineUI() driver.UI { + // disable readline UI in dumb terminal. (golang.org/issue/26254) + if v := strings.ToLower(os.Getenv("TERM")); v == "" || v == "dumb" { + return nil + } // test if we can use terminal.ReadLine // that assumes operation in the raw mode. oldState, err := terminal.MakeRaw(0) diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go index 96c109e0f2..307da58bd5 100644 --- a/src/cmd/trace/annotations.go +++ b/src/cmd/trace/annotations.go @@ -438,8 +438,8 @@ func (task *taskDesc) complete() bool { return task.create != nil && task.end != nil } -// descendents returns all the task nodes in the subtree rooted from this task. -func (task *taskDesc) decendents() []*taskDesc { +// descendants returns all the task nodes in the subtree rooted from this task. +func (task *taskDesc) descendants() []*taskDesc { if task == nil { return nil } diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go index 62ff4d68c5..d986b71f79 100644 --- a/src/cmd/trace/trace.go +++ b/src/cmd/trace/trace.go @@ -220,7 +220,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) { params.startTime = task.firstTimestamp() - 1 params.endTime = task.lastTimestamp() + 1 params.maing = goid - params.tasks = task.decendents() + params.tasks = task.descendants() gs := map[uint64]bool{} for _, t := range params.tasks { // find only directly involved goroutines @@ -244,7 +244,7 @@ func httpJsonTrace(w http.ResponseWriter, r *http.Request) { params.mode = modeTaskOriented params.startTime = task.firstTimestamp() - 1 params.endTime = task.lastTimestamp() + 1 - params.tasks = task.decendents() + params.tasks = task.descendants() } start := int64(0) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/fcntl.go b/src/cmd/vendor/golang.org/x/sys/unix/fcntl.go index 0c58c7e1e5..9379ba9cef 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/fcntl.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/fcntl.go @@ -14,7 +14,11 @@ var fcntl64Syscall uintptr = SYS_FCNTL // FcntlInt performs a fcntl syscall on fd with the provided command and argument. func FcntlInt(fd uintptr, cmd, arg int) (int, error) { - valptr, _, err := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg)) + valptr, _, errno := Syscall(fcntl64Syscall, fd, uintptr(cmd), uintptr(arg)) + var err error + if errno != 0 { + err = errno + } return int(valptr), err } diff --git a/src/cmd/vendor/golang.org/x/sys/unix/gccgo_c.c b/src/cmd/vendor/golang.org/x/sys/unix/gccgo_c.c index 24e96b1198..46523ced65 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/gccgo_c.c +++ b/src/cmd/vendor/golang.org/x/sys/unix/gccgo_c.c @@ -36,12 +36,3 @@ gccgoRealSyscallNoError(uintptr_t trap, uintptr_t a1, uintptr_t a2, uintptr_t a3 { return syscall(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9); } - -// Define the use function in C so that it is not inlined. - -extern void use(void *) __asm__ (GOSYM_PREFIX GOPKGPATH ".use") __attribute__((noinline)); - -void -use(void *p __attribute__ ((unused))) -{ -} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh index ddc50a018a..4a2c5dc9b0 100755 --- a/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/src/cmd/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -193,6 +193,7 @@ struct ltchars { #include #include #include +#include #include #include @@ -404,7 +405,7 @@ ccflags="$@" $2 ~ /^LINUX_REBOOT_CMD_/ || $2 ~ /^LINUX_REBOOT_MAGIC[12]$/ || $2 !~ "NLA_TYPE_MASK" && - $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || + $2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P)_/ || $2 ~ /^SIOC/ || $2 ~ /^TIOC/ || $2 ~ /^TCGET/ || diff --git a/src/cmd/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl b/src/cmd/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl index be67afa417..49f186f832 100755 --- a/src/cmd/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl +++ b/src/cmd/vendor/golang.org/x/sys/unix/mksysctl_openbsd.pl @@ -240,7 +240,7 @@ foreach my $header (@headers) { print <= 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go new file mode 100644 index 0000000000..070bd38994 --- /dev/null +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gc_386.go @@ -0,0 +1,16 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux,!gccgo,386 + +package unix + +import "syscall" + +// Underlying system call writes to newoffset via pointer. +// Implemented in assembly to avoid allocation. +func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno) + +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) +func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go new file mode 100644 index 0000000000..308eb7aecf --- /dev/null +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_386.go @@ -0,0 +1,30 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux,gccgo,386 + +package unix + +import ( + "syscall" + "unsafe" +) + +func seek(fd int, offset int64, whence int) (int64, syscall.Errno) { + var newoffset int64 + offsetLow := uint32(offset & 0xffffffff) + offsetHigh := uint32((offset >> 32) & 0xffffffff) + _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) + return newoffset, err +} + +func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) { + fd, _, err := Syscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0) + return int(fd), err +} + +func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (int, syscall.Errno) { + fd, _, err := RawSyscall(SYS_SOCKETCALL, uintptr(call), uintptr(unsafe.Pointer(&a0)), 0) + return int(fd), err +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go similarity index 53% rename from src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo.go rename to src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go index df9c123718..aa7fc9e199 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_gccgo_arm.go @@ -2,9 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build linux -// +build gccgo -// +build 386 arm +// +build linux,gccgo,arm package unix @@ -13,9 +11,10 @@ import ( "unsafe" ) -func seek(fd int, offset int64, whence int) (newoffset int64, err syscall.Errno) { +func seek(fd int, offset int64, whence int) (int64, syscall.Errno) { + var newoffset int64 offsetLow := uint32(offset & 0xffffffff) offsetHigh := uint32((offset >> 32) & 0xffffffff) - _, _, err = Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) + _, _, err := Syscall6(SYS__LLSEEK, uintptr(fd), uintptr(offsetHigh), uintptr(offsetLow), uintptr(unsafe.Pointer(&newoffset)), uintptr(whence), 0) return newoffset, err } diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go index 090ed404ab..ad991031c7 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go @@ -8,6 +8,7 @@ package unix //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) @@ -47,6 +48,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -65,6 +67,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -80,6 +83,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go index 9e16cc9d14..0e05924820 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go @@ -15,6 +15,8 @@ import ( func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64 @@ -33,13 +35,12 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sysnb Setregid(rgid int, egid int) (err error) //sysnb Setresgid(rgid int, egid int, sgid int) (err error) //sysnb Setresuid(ruid int, euid int, suid int) (err error) - //sysnb Setreuid(ruid int, euid int) (err error) //sys Shutdown(fd int, how int) (err error) //sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error) - //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64 +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -61,16 +62,17 @@ func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, //sys Ioperm(from int, num int, on int) (err error) //sys Iopl(level int) (err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) +//sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) //sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64 //sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64 //sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64 //sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64 -//sys Utime(path string, buf *Utimbuf) (err error) -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Pause() (err error) func Fstatfs(fd int, buf *Statfs_t) (err error) { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go index 6fb8733d67..8c6720f7f4 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go @@ -7,8 +7,9 @@ package unix -//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) +//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) //sys Fstat(fd int, stat *Stat_t) (err error) @@ -45,6 +46,7 @@ package unix //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) = SYS_SYNC_FILE_RANGE2 //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) //sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) //sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) @@ -63,10 +65,11 @@ package unix //sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) //sys mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) //sysnb Time(t *Time_t) (tt Time_t, err error) - //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go index c0d86e722b..6e4ee0cf2a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_s390x.go @@ -11,6 +11,7 @@ import ( ) //sys Dup2(oldfd int, newfd int) (err error) +//sysnb EpollCreate(size int) (fd int, err error) //sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64 //sys Fchown(fd int, uid int, gid int) (err error) @@ -44,9 +45,11 @@ import ( //sys Statfs(path string, buf *Statfs_t) (err error) //sys SyncFileRange(fd int, off int64, n int64, flags int) (err error) //sys Truncate(path string, length int64) (err error) +//sys Ustat(dev int, ubuf *Ustat_t) (err error) //sysnb getgroups(n int, list *_Gid_t) (nn int, err error) //sysnb setgroups(n int, list *_Gid_t) (err error) +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -62,6 +65,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go index 78c1e0df1d..72e64187de 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go @@ -68,6 +68,7 @@ func Iopl(level int) (err error) { return ENOSYS } +//sys futimesat(dirfd int, path string, times *[2]Timeval) (err error) //sysnb Gettimeofday(tv *Timeval) (err error) func Time(t *Time_t) (tt Time_t, err error) { @@ -83,6 +84,7 @@ func Time(t *Time_t) (tt Time_t, err error) { } //sys Utime(path string, buf *Utimbuf) (err error) +//sys utimes(path string, times *[2]Timeval) (err error) func setTimespec(sec, nsec int64) Timespec { return Timespec{Sec: sec, Nsec: nsec} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_test.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_test.go index 7fd5e2a92f..eed17268b0 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_test.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_linux_test.go @@ -140,11 +140,16 @@ func TestUtimesNanoAt(t *testing.T) { if err != nil { t.Fatalf("Lstat: %v", err) } - if st.Atim != ts[0] { - t.Errorf("UtimesNanoAt: wrong atime: %v", st.Atim) + + // Only check Mtim, Atim might not be supported by the underlying filesystem + expected := ts[1] + if st.Mtim.Nsec == 0 { + // Some filesystems only support 1-second time stamp resolution + // and will always set Nsec to 0. + expected.Nsec = 0 } - if st.Mtim != ts[1] { - t.Errorf("UtimesNanoAt: wrong mtime: %v", st.Mtim) + if st.Mtim != expected { + t.Errorf("UtimesNanoAt: wrong mtime: expected %v, got %v", expected, st.Mtim) } } @@ -384,3 +389,33 @@ func stringsFromByteSlice(buf []byte) []string { } return result } + +func TestFaccessat(t *testing.T) { + defer chtmpdir(t)() + touch(t, "file1") + + err := unix.Faccessat(unix.AT_FDCWD, "file1", unix.O_RDONLY, 0) + if err != nil { + t.Errorf("Faccessat: unexpected error: %v", err) + } + + err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.O_RDONLY, 2) + if err != unix.EINVAL { + t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err) + } + + err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.O_RDONLY, unix.AT_EACCESS) + if err != unix.EOPNOTSUPP { + t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err) + } + + err = os.Symlink("file1", "symlink1") + if err != nil { + t.Fatal(err) + } + + err = unix.Faccessat(unix.AT_FDCWD, "symlink1", unix.O_RDONLY, unix.AT_SYMLINK_NOFOLLOW) + if err != unix.EOPNOTSUPP { + t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err) + } +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go index e1a3baa237..369a2be2dc 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_netbsd.go @@ -233,6 +233,7 @@ func Uname(uname *Utsname) error { //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_POSIX_FADVISE //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_openbsd.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_openbsd.go index 614fcf0494..9fc9c06a08 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_openbsd.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_openbsd.go @@ -201,6 +201,7 @@ func Uname(uname *Utsname) error { //sys Dup(fd int) (nfd int, err error) //sys Dup2(from int, to int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchflags(fd int, flags int) (err error) //sys Fchmod(fd int, mode uint32) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go index b7629529b3..820ef77af2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go @@ -314,7 +314,11 @@ func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error { // FcntlInt performs a fcntl syscall on fd with the provided command and argument. func FcntlInt(fd uintptr, cmd, arg int) (int, error) { - valptr, _, err := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0) + valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0) + var err error + if errno != 0 { + err = errno + } return int(valptr), err } @@ -595,6 +599,7 @@ func Poll(fds []PollFd, timeout int) (n int, err error) { //sys Dup(fd int) (nfd int, err error) //sys Dup2(oldfd int, newfd int) (err error) //sys Exit(code int) +//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) //sys Fchdir(fd int) (err error) //sys Fchmod(fd int, mode uint32) (err error) //sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix_test.go b/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix_test.go index ad09716a8a..d694990dbe 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix_test.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/syscall_unix_test.go @@ -98,6 +98,24 @@ func TestErrnoSignalName(t *testing.T) { } } +func TestFcntlInt(t *testing.T) { + t.Parallel() + file, err := ioutil.TempFile("", "TestFnctlInt") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + defer file.Close() + f := file.Fd() + flags, err := unix.FcntlInt(f, unix.F_GETFD, 0) + if err != nil { + t.Fatal(err) + } + if flags&unix.FD_CLOEXEC == 0 { + t.Errorf("flags %#x do not include FD_CLOEXEC", flags) + } +} + // TestFcntlFlock tests whether the file locking structure matches // the calling convention of each kernel. func TestFcntlFlock(t *testing.T) { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index ee17d4bd4a..2f0091bbc9 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -3,7 +3,7 @@ // +build 386,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -m32 _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1234,6 +1235,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 PERF_EVENT_IOC_QUERY_BPF = 0xc004240a @@ -1289,6 +1291,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1334,11 +1337,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1466,6 +1476,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8004700d + RTC_EPOCH_SET = 0x4004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8004700b + RTC_IRQP_SET = 0x4004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x801c7011 + RTC_PLL_SET = 0x401c7012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index 64ab9f40ad..a80c7ae5fb 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -3,7 +3,7 @@ // +build amd64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -m64 _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1234,6 +1235,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1289,6 +1291,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1334,11 +1337,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1467,6 +1477,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index 6ae0ac6f86..49a9b0133b 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -3,7 +3,7 @@ // +build arm,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1232,6 +1233,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 PERF_EVENT_IOC_QUERY_BPF = 0xc004240a @@ -1287,6 +1289,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1332,11 +1335,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1473,6 +1483,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8004700d + RTC_EPOCH_SET = 0x4004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8004700b + RTC_IRQP_SET = 0x4004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x801c7011 + RTC_PLL_SET = 0x401c7012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index f58450bf3d..8d70233b26 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -3,7 +3,7 @@ // +build arm64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go package unix @@ -450,6 +450,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1235,6 +1236,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1290,6 +1292,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1335,11 +1338,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1457,6 +1467,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 465ff2f0f3..410ab56b09 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -3,7 +3,7 @@ // +build mips,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1233,6 +1234,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc004240a @@ -1288,6 +1290,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1333,11 +1336,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1467,6 +1477,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4004700d + RTC_EPOCH_SET = 0x8004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4004700b + RTC_IRQP_SET = 0x8004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x401c7011 + RTC_PLL_SET = 0x801c7012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 37e851aabe..dac4d90fad 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -3,7 +3,7 @@ // +build mips64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1233,6 +1234,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1288,6 +1290,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1333,11 +1336,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1467,6 +1477,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 1131d3ca16..1d2f0e6382 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -3,7 +3,7 @@ // +build mips64le,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1233,6 +1234,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1288,6 +1290,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1333,11 +1336,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1467,6 +1477,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index d04a43b2bc..33b9940234 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -3,7 +3,7 @@ // +build mipsle,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1233,6 +1234,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40042407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8004240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc004240a @@ -1288,6 +1290,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1333,11 +1336,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1467,6 +1477,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4004700d + RTC_EPOCH_SET = 0x8004700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4004700b + RTC_IRQP_SET = 0x8004700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x401c7011 + RTC_PLL_SET = 0x801c7012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 710410efdd..c78d669761 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -3,7 +3,7 @@ // +build ppc64,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1234,6 +1235,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1290,6 +1292,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1335,11 +1338,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1523,6 +1533,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index c1c1c01bcf..63493756d8 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -3,7 +3,7 @@ // +build ppc64le,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1234,6 +1235,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x20002401 PERF_EVENT_IOC_ENABLE = 0x20002400 PERF_EVENT_IOC_ID = 0x40082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x8008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x80042409 PERF_EVENT_IOC_PERIOD = 0x80082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1290,6 +1292,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1335,11 +1338,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1523,6 +1533,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x20007002 + RTC_AIE_ON = 0x20007001 + RTC_ALM_READ = 0x40247008 + RTC_ALM_SET = 0x80247007 + RTC_EPOCH_READ = 0x4008700d + RTC_EPOCH_SET = 0x8008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x4008700b + RTC_IRQP_SET = 0x8008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x20007006 + RTC_PIE_ON = 0x20007005 + RTC_PLL_GET = 0x40207011 + RTC_PLL_SET = 0x80207012 + RTC_RD_TIME = 0x40247009 + RTC_SET_TIME = 0x8024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x20007004 + RTC_UIE_ON = 0x20007003 + RTC_VL_CLR = 0x20007014 + RTC_VL_READ = 0x40047013 + RTC_WIE_OFF = 0x20007010 + RTC_WIE_ON = 0x2000700f + RTC_WKALM_RD = 0x40287010 + RTC_WKALM_SET = 0x8028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index c7583e15eb..3814df8549 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -3,7 +3,7 @@ // +build s390x,linux -// Created by cgo -godefs - DO NOT EDIT +// Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs -- -Wall -Werror -static -I/tmp/include -fsigned-char _const.go package unix @@ -449,6 +449,7 @@ const ( ETH_P_PPP_DISC = 0x8863 ETH_P_PPP_MP = 0x8 ETH_P_PPP_SES = 0x8864 + ETH_P_PREAUTH = 0x88c7 ETH_P_PRP = 0x88fb ETH_P_PUP = 0x200 ETH_P_PUPAT = 0x201 @@ -1232,6 +1233,7 @@ const ( PERF_EVENT_IOC_DISABLE = 0x2401 PERF_EVENT_IOC_ENABLE = 0x2400 PERF_EVENT_IOC_ID = 0x80082407 + PERF_EVENT_IOC_MODIFY_ATTRIBUTES = 0x4008240b PERF_EVENT_IOC_PAUSE_OUTPUT = 0x40042409 PERF_EVENT_IOC_PERIOD = 0x40082404 PERF_EVENT_IOC_QUERY_BPF = 0xc008240a @@ -1287,6 +1289,7 @@ const ( PR_GET_PDEATHSIG = 0x2 PR_GET_SECCOMP = 0x15 PR_GET_SECUREBITS = 0x1b + PR_GET_SPECULATION_CTRL = 0x34 PR_GET_THP_DISABLE = 0x2a PR_GET_TID_ADDRESS = 0x28 PR_GET_TIMERSLACK = 0x1e @@ -1332,11 +1335,18 @@ const ( PR_SET_PTRACER_ANY = 0xffffffffffffffff PR_SET_SECCOMP = 0x16 PR_SET_SECUREBITS = 0x1c + PR_SET_SPECULATION_CTRL = 0x35 PR_SET_THP_DISABLE = 0x29 PR_SET_TIMERSLACK = 0x1d PR_SET_TIMING = 0xe PR_SET_TSC = 0x1a PR_SET_UNALIGN = 0x6 + PR_SPEC_DISABLE = 0x4 + PR_SPEC_ENABLE = 0x2 + PR_SPEC_FORCE_DISABLE = 0x8 + PR_SPEC_NOT_AFFECTED = 0x0 + PR_SPEC_PRCTL = 0x1 + PR_SPEC_STORE_BYPASS = 0x0 PR_SVE_GET_VL = 0x33 PR_SVE_SET_VL = 0x32 PR_SVE_SET_VL_ONEXEC = 0x40000 @@ -1527,6 +1537,33 @@ const ( RTCF_MASQ = 0x400000 RTCF_NAT = 0x800000 RTCF_VALVE = 0x200000 + RTC_AF = 0x20 + RTC_AIE_OFF = 0x7002 + RTC_AIE_ON = 0x7001 + RTC_ALM_READ = 0x80247008 + RTC_ALM_SET = 0x40247007 + RTC_EPOCH_READ = 0x8008700d + RTC_EPOCH_SET = 0x4008700e + RTC_IRQF = 0x80 + RTC_IRQP_READ = 0x8008700b + RTC_IRQP_SET = 0x4008700c + RTC_MAX_FREQ = 0x2000 + RTC_PF = 0x40 + RTC_PIE_OFF = 0x7006 + RTC_PIE_ON = 0x7005 + RTC_PLL_GET = 0x80207011 + RTC_PLL_SET = 0x40207012 + RTC_RD_TIME = 0x80247009 + RTC_SET_TIME = 0x4024700a + RTC_UF = 0x10 + RTC_UIE_OFF = 0x7004 + RTC_UIE_ON = 0x7003 + RTC_VL_CLR = 0x7014 + RTC_VL_READ = 0x80047013 + RTC_WIE_OFF = 0x7010 + RTC_WIE_ON = 0x700f + RTC_WKALM_RD = 0x80287010 + RTC_WKALM_SET = 0x4028700f RTF_ADDRCLASSMASK = 0xf8000000 RTF_ADDRCONF = 0x40000 RTF_ALLONLINK = 0x20000 diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 95de199fc4..7fdc85b172 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -1,5 +1,5 @@ // mkerrors.sh -m64 -// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build sparc64,linux diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go index 433becfd02..237e960959 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_386.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { @@ -1565,6 +1519,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice)) if e1 != 0 { @@ -1869,6 +1851,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getgroups(n int, list *_Gid_t) (nn int, err error) { r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0) nn = int(r0) @@ -1912,23 +1904,6 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { @@ -1959,6 +1934,21 @@ func setrlimit(resource int, rlim *rlimit32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1995,6 +1985,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func poll(fds *PollFd, nfds int, timeout int) (n int, err error) { r0, _, e1 := Syscall(SYS_POLL, uintptr(unsafe.Pointer(fds)), uintptr(nfds), uintptr(timeout)) n = int(r0) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go index 33c02b2695..9b40f580b0 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1937,6 +1902,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2127,6 +2102,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Utime(path string, buf *Utimbuf) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2142,6 +2132,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go index f91b56c217..d93cc2f3b1 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { @@ -1734,6 +1688,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchown(fd int, uid int, gid int) (err error) { _, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid)) if e1 != 0 { @@ -1852,6 +1834,16 @@ func Lstat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Pause() (err error) { + _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0) written = int(r0) @@ -1970,6 +1962,31 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1980,25 +1997,13 @@ func Gettimeofday(tv *Timeval) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func Pause() (err error) { - _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) if e1 != 0 { err = errnoErr(e1) } diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go index 52d7595250..5f7d0213b2 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go index 970a5c132d..e761705282 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len)) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { @@ -1794,6 +1776,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2004,6 +1996,21 @@ func Iopl(level int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2025,6 +2032,36 @@ func Time(t *Time_t) (tt Time_t, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lstat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2080,38 +2117,6 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Utime(path string, buf *Utimbuf) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go index b989d0f282..382e072f5e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1881,6 +1846,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2071,6 +2046,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2096,6 +2086,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go index 1f8d14cacc..da33eb12b0 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1881,6 +1846,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2071,6 +2046,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2096,6 +2086,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go index a9c7e520e4..f6e45189ae 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32)) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,34 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { + var _p0 unsafe.Pointer + if len(events) > 0 { + _p0 = unsafe.Pointer(&events[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0) if e1 != 0 { @@ -1794,6 +1776,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2004,6 +1996,21 @@ func Iopl(level int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2025,6 +2032,36 @@ func Time(t *Time_t) (tt Time_t, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Utime(path string, buf *Utimbuf) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Lstat(path string, stat *Stat_t) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -2080,38 +2117,6 @@ func Stat(path string, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Utime(path string, buf *Utimbuf) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - -func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { - var _p0 unsafe.Pointer - if len(events) > 0 { - _p0 = unsafe.Pointer(&events[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0) - n = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Pause() (err error) { _, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go index 3bb9a20992..0ae2aa8422 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,42 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1552,16 +1527,6 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Dup2(oldfd int, newfd int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { @@ -1963,6 +1928,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2153,6 +2128,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2189,6 +2179,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go index 56116623d6..fa16c165e1 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,42 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Dup2(oldfd int, newfd int) (err error) { + _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1552,16 +1527,6 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Dup2(oldfd int, newfd int) (err error) { - _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0) if e1 != 0 { @@ -1963,6 +1928,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) { r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen))) fd = int(r0) @@ -2153,6 +2128,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -2189,6 +2179,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go index 9696a0199d..38f903cd3e 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go @@ -143,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -173,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -494,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -544,21 +508,6 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fallocate(fd int, mode uint32, off int64, len int64) (err error) { _, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0) if e1 != 0 { @@ -1366,16 +1315,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1535,6 +1474,21 @@ func Munlockall() (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func faccessat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Dup2(oldfd int, newfd int) (err error) { _, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) if e1 != 0 { @@ -1545,6 +1499,17 @@ func Dup2(oldfd int, newfd int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func EpollCreate(size int) (fd int, err error) { + r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { var _p0 unsafe.Pointer if len(events) > 0 { @@ -1923,6 +1888,16 @@ func Truncate(path string, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Ustat(dev int, ubuf *Ustat_t) (err error) { + _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func getgroups(n int, list *_Gid_t) (nn int, err error) { r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0) nn = int(r0) @@ -1944,6 +1919,21 @@ func setgroups(n int, list *_Gid_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1969,6 +1959,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe2(p *[2]_C_int, flags int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go index c01b3b6bab..b26aee9579 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go @@ -14,6 +14,31 @@ var _ syscall.Errno // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func fchmodat(dirfd int, path string, mode uint32) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func ioctl(fd int, req uint, arg uintptr) (err error) { + _, _, e1 := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(arg)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(oldpath) @@ -118,21 +143,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func utimes(path string, times *[2]Timeval) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -148,16 +158,6 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) { - _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times))) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Getcwd(buf []byte) (n int, err error) { var _p0 unsafe.Pointer if len(buf) > 0 { @@ -186,6 +186,104 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func KeyctlInt(cmd int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err error) { + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func KeyctlBuffer(cmd int, arg2 int, buf []byte, arg5 int) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(buf)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlJoin(cmd int, arg2 string) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg2) + if err != nil { + return + } + r0, _, e1 := Syscall(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlSearch(cmd int, arg2 int, arg3 string, arg4 string, arg5 int) (ret int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(arg3) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(arg4) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(arg5), 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlIOV(cmd int, arg2 int, payload []Iovec, arg5 int) (err error) { + var _p0 unsafe.Pointer + if len(payload) > 0 { + _p0 = unsafe.Pointer(&payload[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(arg2), uintptr(_p0), uintptr(len(payload)), uintptr(arg5), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func keyctlDH(cmd int, arg2 *KeyctlDHParams, buf []byte) (ret int, err error) { + var _p0 unsafe.Pointer + if len(buf) > 0 { + _p0 = unsafe.Pointer(&buf[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_KEYCTL, uintptr(cmd), uintptr(unsafe.Pointer(arg2)), uintptr(_p0), uintptr(len(buf)), 0, 0) + ret = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) { _, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0) if e1 != 0 { @@ -251,6 +349,33 @@ func Acct(path string) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(payload) > 0 { + _p2 = unsafe.Pointer(&payload[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_ADD_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(payload)), uintptr(ringid), 0) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Adjtimex(buf *Timex) (state int, err error) { r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0) state = int(r0) @@ -344,17 +469,6 @@ func Dup3(oldfd int, newfd int, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func EpollCreate(size int) (fd int, err error) { - r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0) - fd = int(r0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func EpollCreate1(flag int) (fd int, err error) { r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0) fd = int(r0) @@ -376,8 +490,19 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Eventfd(initval uint, flags int) (fd int, err error) { + r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Exit(code int) { - Syscall(SYS_EXIT_GROUP, uintptr(code), 0, 0) + SyscallNoError(SYS_EXIT_GROUP, uintptr(code), 0, 0) return } @@ -428,21 +553,6 @@ func Fchmod(fd int, mode uint32) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) { - var _p0 *byte - _p0, err = BytePtrFromString(path) - if err != nil { - return - } - _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -528,7 +638,7 @@ func Getpgid(pid int) (pgid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getpid() (pid int) { - r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPID, 0, 0, 0) pid = int(r0) return } @@ -536,7 +646,7 @@ func Getpid() (pid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getppid() (ppid int) { - r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETPPID, 0, 0, 0) ppid = int(r0) return } @@ -593,7 +703,7 @@ func Getsid(pid int) (sid int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Gettid() (tid int) { - r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETTID, 0, 0, 0) tid = int(r0) return } @@ -692,6 +802,33 @@ func Klogctl(typ int, buf []byte) (n int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Lgetxattr(path string, attr string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(dest) > 0 { + _p2 = unsafe.Pointer(&dest[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall6(SYS_LGETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)), 0, 0) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Listxattr(path string, dest []byte) (sz int, err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -714,6 +851,74 @@ func Listxattr(path string, dest []byte) (sz int, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Llistxattr(path string, dest []byte) (sz int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 unsafe.Pointer + if len(dest) > 0 { + _p1 = unsafe.Pointer(&dest[0]) + } else { + _p1 = unsafe.Pointer(&_zero) + } + r0, _, e1 := Syscall(SYS_LLISTXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(dest))) + sz = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lremovexattr(path string, attr string) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_LREMOVEXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Lsetxattr(path string, attr string, data []byte, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(attr) + if err != nil { + return + } + var _p2 unsafe.Pointer + if len(data) > 0 { + _p2 = unsafe.Pointer(&data[0]) + } else { + _p2 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall6(SYS_LSETXATTR, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Mkdirat(dirfd int, path string, mode uint32) (err error) { var _p0 *byte _p0, err = BytePtrFromString(path) @@ -754,6 +959,17 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func PerfEventOpen(attr *PerfEventAttr, pid int, cpu int, groupFd int, flags int) (fd int, err error) { + r0, _, e1 := Syscall6(SYS_PERF_EVENT_OPEN, uintptr(unsafe.Pointer(attr)), uintptr(pid), uintptr(cpu), uintptr(groupFd), uintptr(flags), 0) + fd = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func PivotRoot(newroot string, putold string) (err error) { var _p0 *byte _p0, err = BytePtrFromString(newroot) @@ -794,6 +1010,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) ( // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) { + r0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask))) + n = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func read(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -851,6 +1078,32 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func RequestKey(keyType string, description string, callback string, destRingid int) (id int, err error) { + var _p0 *byte + _p0, err = BytePtrFromString(keyType) + if err != nil { + return + } + var _p1 *byte + _p1, err = BytePtrFromString(description) + if err != nil { + return + } + var _p2 *byte + _p2, err = BytePtrFromString(callback) + if err != nil { + return + } + r0, _, e1 := Syscall6(SYS_REQUEST_KEY, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(destRingid), 0, 0) + id = int(r0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Setdomainname(p []byte) (err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -960,8 +1213,33 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_STATX, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags), uintptr(mask), uintptr(unsafe.Pointer(stat)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Sync() { - Syscall(SYS_SYNC, 0, 0, 0) + SyscallNoError(SYS_SYNC, 0, 0, 0) + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Syncfs(fd int) (err error) { + _, _, e1 := Syscall(SYS_SYNCFS, uintptr(fd), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } return } @@ -1010,7 +1288,7 @@ func Times(tms *Tms) (ticks uintptr, err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Umask(mask int) (oldmask int) { - r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0) + r0, _ := RawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0) oldmask = int(r0) return } @@ -1052,16 +1330,6 @@ func Unshare(flags int) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Ustat(dev int, ubuf *Ustat_t) (err error) { - _, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0) - if e1 != 0 { - err = errnoErr(e1) - } - return -} - -// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT - func write(fd int, p []byte) (n int, err error) { var _p0 unsafe.Pointer if len(p) > 0 { @@ -1169,14 +1437,8 @@ func Mlock(b []byte) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Munlock(b []byte) (err error) { - var _p0 unsafe.Pointer - if len(b) > 0 { - _p0 = unsafe.Pointer(&b[0]) - } else { - _p0 = unsafe.Pointer(&_zero) - } - _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) +func Mlockall(flags int) (err error) { + _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) if e1 != 0 { err = errnoErr(e1) } @@ -1185,8 +1447,30 @@ func Munlock(b []byte) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT -func Mlockall(flags int) (err error) { - _, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0) +func Msync(b []byte, flags int) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MSYNC, uintptr(_p0), uintptr(len(b)), uintptr(flags)) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + +func Munlock(b []byte) (err error) { + var _p0 unsafe.Pointer + if len(b) > 0 { + _p0 = unsafe.Pointer(&b[0]) + } else { + _p0 = unsafe.Pointer(&_zero) + } + _, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0) if e1 != 0 { err = errnoErr(e1) } @@ -1262,6 +1546,21 @@ func Fstat(fd int, stat *Stat_t) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FSTATAT64, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fstatfs(fd int, buf *Statfs_t) (err error) { _, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0) if e1 != 0 { @@ -1283,7 +1582,7 @@ func Ftruncate(fd int, length int64) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getegid() (egid int) { - r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEGID, 0, 0, 0) egid = int(r0) return } @@ -1291,7 +1590,7 @@ func Getegid() (egid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Geteuid() (euid int) { - r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETEUID, 0, 0, 0) euid = int(r0) return } @@ -1299,7 +1598,7 @@ func Geteuid() (euid int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getgid() (gid int) { - r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETGID, 0, 0, 0) gid = int(r0) return } @@ -1317,7 +1616,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT func Getuid() (uid int) { - r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0) + r0, _ := RawSyscallNoError(SYS_GETUID, 0, 0, 0) uid = int(r0) return } @@ -1788,6 +2087,21 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func futimesat(dirfd int, path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times))) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Gettimeofday(tv *Timeval) (err error) { _, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0) if e1 != 0 { @@ -1813,6 +2127,21 @@ func Utime(path string, buf *Utimbuf) (err error) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func utimes(path string, times *[2]Timeval) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func pipe(p *[2]_C_int) (err error) { _, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go index fb4b962782..b3298930e7 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_386.go @@ -571,6 +571,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), 0, uintptr(length), uintptr(length>>32), uintptr(advice), 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go index beac82ef86..5096ef07e4 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_amd64.go @@ -571,6 +571,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall6(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), 0, uintptr(length), uintptr(advice)) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go index 7bd5f60b00..b7141c63f9 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_netbsd_arm.go @@ -571,6 +571,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fadvise(fd int, offset int64, length int64, advice int) (err error) { _, _, e1 := Syscall9(SYS_POSIX_FADVISE, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), 0, uintptr(length), uintptr(length>>32), uintptr(advice), 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go index 49b3b5e8a4..1942049b0f 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go @@ -569,6 +569,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go index c4c7d8540c..d351c72cb7 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go @@ -569,6 +569,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go index 210285b0ba..617d47f0f3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go @@ -569,6 +569,21 @@ func Exit(code int) { // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = errnoErr(e1) + } + return +} + +// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT + func Fchdir(fd int) (err error) { _, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go index 397896300d..e2e5fc5e0a 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsyscall_solaris_amd64.go @@ -41,6 +41,7 @@ import ( //go:cgo_import_dynamic libc_dup dup "libc.so" //go:cgo_import_dynamic libc_dup2 dup2 "libc.so" //go:cgo_import_dynamic libc_exit exit "libc.so" +//go:cgo_import_dynamic libc_faccessat faccessat "libc.so" //go:cgo_import_dynamic libc_fchdir fchdir "libc.so" //go:cgo_import_dynamic libc_fchmod fchmod "libc.so" //go:cgo_import_dynamic libc_fchmodat fchmodat "libc.so" @@ -169,6 +170,7 @@ import ( //go:linkname procDup libc_dup //go:linkname procDup2 libc_dup2 //go:linkname procExit libc_exit +//go:linkname procFaccessat libc_faccessat //go:linkname procFchdir libc_fchdir //go:linkname procFchmod libc_fchmod //go:linkname procFchmodat libc_fchmodat @@ -298,6 +300,7 @@ var ( procDup, procDup2, procExit, + procFaccessat, procFchdir, procFchmod, procFchmodat, @@ -695,6 +698,19 @@ func Exit(code int) { return } +func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) { + var _p0 *byte + _p0, err = BytePtrFromString(path) + if err != nil { + return + } + _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFaccessat)), 4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0) + if e1 != 0 { + err = e1 + } + return +} + func Fchdir(fd int) (err error) { _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procFchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0) if e1 != 0 { diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go index 83bb935b91..b005031abe 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_386.go @@ -1,5 +1,5 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. package unix diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go index 207b27938b..90c95c2c75 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_amd64.go @@ -1,5 +1,5 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build amd64,openbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go index 83bb935b91..b005031abe 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysctl_openbsd_arm.go @@ -1,5 +1,5 @@ // mksysctl_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. package unix diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index ed92409d97..c061d6f1d3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -331,4 +331,5 @@ const ( SYS_S390_GUARDED_STORAGE = 378 SYS_STATX = 379 SYS_S390_STHYI = 380 + SYS_KEXEC_FILE_LOAD = 381 ) diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index c9c129dc42..2d09936721 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -1,5 +1,5 @@ // mksysnum_linux.pl -Ilinux/usr/include -m64 -D__arch64__ linux/usr/include/asm/unistd.h -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build sparc64,linux diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go index 8afda9c451..f0daa05a9c 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_386.go @@ -1,5 +1,5 @@ // mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build 386,netbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go index aea8dbec43..ddb25b94f3 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_amd64.go @@ -1,5 +1,5 @@ // mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build amd64,netbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go index c6158a7ef9..315bd63f89 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_netbsd_arm.go @@ -1,5 +1,5 @@ // mksysnum_netbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build arm,netbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go index 3e8ce2a1dd..07787301f0 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_386.go @@ -1,5 +1,5 @@ // mksysnum_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build 386,openbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go index 32653e53c7..7a1693acbc 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/zsysnum_openbsd_arm.go @@ -1,5 +1,5 @@ // mksysnum_openbsd.pl -// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT +// Code generated by the command above; DO NOT EDIT. // +build arm,openbsd diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go index 4047462081..e89bc6b366 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_386.go @@ -705,6 +705,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1813,3 +1815,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go index 2ab0cb9e79..d95372baec 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go @@ -723,6 +723,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1833,3 +1835,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go index 18d577b912..77875ba01b 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go @@ -693,6 +693,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1802,3 +1804,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go index 6ea80563f1..5a9df694a6 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go @@ -702,6 +702,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1812,3 +1814,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go index e0a3932232..dcb239de81 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go @@ -697,6 +697,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1807,3 +1809,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go index 838135e24b..9cf85f7218 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go @@ -704,6 +704,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1814,3 +1816,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go index a9d0131f2e..6fd66e7510 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go @@ -704,6 +704,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1814,3 +1816,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go index 4f6f145556..faa5b3ef18 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go @@ -697,6 +697,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1807,3 +1809,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int32 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go index 9ddd47015e..ad4c452460 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go @@ -712,6 +712,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1822,3 +1824,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go index 3a5cc696ec..1fdb2f2162 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go @@ -712,6 +712,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1822,3 +1824,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go index 032a71bbfe..d32079d1aa 100644 --- a/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go +++ b/src/cmd/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go @@ -728,6 +728,8 @@ const ( AT_SYMLINK_FOLLOW = 0x400 AT_SYMLINK_NOFOLLOW = 0x100 + + AT_EACCESS = 0x200 ) type PollFd struct { @@ -1839,3 +1841,32 @@ const ( NFT_NG_INCREMENTAL = 0x0 NFT_NG_RANDOM = 0x1 ) + +type RTCTime struct { + Sec int32 + Min int32 + Hour int32 + Mday int32 + Mon int32 + Year int32 + Wday int32 + Yday int32 + Isdst int32 +} + +type RTCWkAlrm struct { + Enabled uint8 + Pending uint8 + _ [2]byte + Time RTCTime +} + +type RTCPLLInfo struct { + Ctrl int32 + Value int32 + Max int32 + Min int32 + Posmult int32 + Negmult int32 + Clock int64 +} diff --git a/src/cmd/vendor/vendor.json b/src/cmd/vendor/vendor.json index 26b32692b2..8009661879 100644 --- a/src/cmd/vendor/vendor.json +++ b/src/cmd/vendor/vendor.json @@ -125,10 +125,10 @@ "revisionTime": "2018-05-24T11:38:20Z" }, { - "checksumSHA1": "JChADiqeCEidXnI2Sg91xNMWCU0=", + "checksumSHA1": "VQyr/RTSmHpXD2wh988ZnWCVO6w=", "path": "golang.org/x/sys/unix", - "revision": "c11f84a56e43e20a78cee75a7c034031ecf57d1f", - "revisionTime": "2018-05-25T13:55:20Z" + "revision": "7138fd3d9dc8335c567ca206f4333fb75eb05d56", + "revisionTime": "2018-06-27T13:57:12Z" }, { "checksumSHA1": "y0x0I9zDxnxn9nCxwP/MdPyq1E8=", diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go index 09181f9689..e7fe4edc2a 100644 --- a/src/cmd/vet/all/main.go +++ b/src/cmd/vet/all/main.go @@ -198,6 +198,12 @@ func (p platform) vet() { return } + if p.os == "windows" && p.arch == "arm" { + // TODO(jordanrh1): enable as soon as the windows/arm port has fully landed + fmt.Println("skipping windows/arm") + return + } + var buf bytes.Buffer fmt.Fprintf(&buf, "go run main.go -p %s\n", p) diff --git a/src/cmd/vet/all/whitelist/386.txt b/src/cmd/vet/all/whitelist/386.txt index 76e82317ed..f59094eb14 100644 --- a/src/cmd/vet/all/whitelist/386.txt +++ b/src/cmd/vet/all/whitelist/386.txt @@ -22,5 +22,3 @@ runtime/duff_386.s: [386] duffcopy: function duffcopy missing Go declaration runtime/asm_386.s: [386] uint32tofloat64: function uint32tofloat64 missing Go declaration runtime/asm_386.s: [386] float64touint32: function float64touint32 missing Go declaration - -runtime/asm_386.s: [386] stackcheck: function stackcheck missing Go declaration diff --git a/src/cmd/vet/all/whitelist/all.txt b/src/cmd/vet/all/whitelist/all.txt index 397ee4e987..b974d21c6a 100644 --- a/src/cmd/vet/all/whitelist/all.txt +++ b/src/cmd/vet/all/whitelist/all.txt @@ -28,6 +28,25 @@ encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible wit runtime/testdata/testprog/deadlock.go: unreachable code runtime/testdata/testprog/deadlock.go: unreachable code +// Compiler tests that make sure even vet-failing code adheres to the spec. +cmd/compile/internal/gc/testdata/arithConst_test.go: a (64 bits) too small for shift of 4294967296 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (64 bits) too small for shift of 4294967296 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (32 bits) too small for shift of 4294967295 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (32 bits) too small for shift of 4294967295 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (16 bits) too small for shift of 65535 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (16 bits) too small for shift of 65535 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (8 bits) too small for shift of 255 +cmd/compile/internal/gc/testdata/arithConst_test.go: a (8 bits) too small for shift of 255 +cmd/compile/internal/gc/testdata/arith_test.go: x (64 bits) too small for shift of 100 +cmd/compile/internal/gc/testdata/arith_test.go: int32(x) (32 bits) too small for shift of 4294967295 +cmd/compile/internal/gc/testdata/arith_test.go: int16(x) (16 bits) too small for shift of 65535 +cmd/compile/internal/gc/testdata/arith_test.go: int8(x) (8 bits) too small for shift of 255 +cmd/compile/internal/gc/testdata/arith_test.go: w (32 bits) too small for shift of 32 +cmd/compile/internal/gc/testdata/break_test.go: unreachable code +cmd/compile/internal/gc/testdata/break_test.go: unreachable code +cmd/compile/internal/gc/testdata/namedReturn_test.go: self-assignment of t to t +cmd/compile/internal/gc/testdata/short_test.go: unreachable code + // Non-standard method signatures. // These cases are basically ok. // Errors are handled reasonably and there's no clear need for interface satisfaction. diff --git a/src/cmd/vet/all/whitelist/amd64.txt b/src/cmd/vet/all/whitelist/amd64.txt index 2268b39353..20e0d48d53 100644 --- a/src/cmd/vet/all/whitelist/amd64.txt +++ b/src/cmd/vet/all/whitelist/amd64.txt @@ -20,4 +20,3 @@ runtime/asm_amd64.s: [amd64] aeshashbody: function aeshashbody missing Go declar runtime/asm_amd64.s: [amd64] addmoduledata: function addmoduledata missing Go declaration runtime/duff_amd64.s: [amd64] duffzero: function duffzero missing Go declaration runtime/duff_amd64.s: [amd64] duffcopy: function duffcopy missing Go declaration -runtime/asm_amd64.s: [amd64] stackcheck: function stackcheck missing Go declaration diff --git a/src/cmd/vet/all/whitelist/nacl_amd64p32.txt b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt index 9280c68d2c..1ec11f7ca8 100644 --- a/src/cmd/vet/all/whitelist/nacl_amd64p32.txt +++ b/src/cmd/vet/all/whitelist/nacl_amd64p32.txt @@ -24,5 +24,3 @@ runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argc runtime/asm_amd64p32.s: [amd64p32] rt0_go: unknown variable argv runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP) - -runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration diff --git a/src/cmd/vet/copylock.go b/src/cmd/vet/copylock.go index ce14e1af34..ed88ca8960 100644 --- a/src/cmd/vet/copylock.go +++ b/src/cmd/vet/copylock.go @@ -234,13 +234,11 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath { return nil } - // We're looking for cases in which a reference to this type - // can be locked, but a value cannot. This differentiates + // We're looking for cases in which a pointer to this type + // is a sync.Locker, but a value is not. This differentiates // embedded interfaces from embedded values. - if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil { - if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil { - return []types.Type{typ} - } + if types.Implements(types.NewPointer(typ), lockerType) && !types.Implements(typ, lockerType) { + return []types.Type{typ} } nfields := styp.NumFields() @@ -254,3 +252,15 @@ func lockPath(tpkg *types.Package, typ types.Type) typePath { return nil } + +var lockerType *types.Interface + +// Construct a sync.Locker interface type. +func init() { + nullary := types.NewSignature(nil, nil, nil, false) // func() + methods := []*types.Func{ + types.NewFunc(token.NoPos, nil, "Lock", nullary), + types.NewFunc(token.NoPos, nil, "Unlock", nullary), + } + lockerType = types.NewInterface(methods, nil).Complete() +} diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go index 28da9e2d74..c50d4885a0 100644 --- a/src/cmd/vet/main.go +++ b/src/cmd/vet/main.go @@ -24,6 +24,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" "strconv" "strings" @@ -163,6 +164,12 @@ var ( exporters = make(map[string]func() interface{}) ) +// The exporters data as written to the vetx output file. +type vetxExport struct { + Name string + Data interface{} +} + // Vet can provide its own "export information" // about package A to future invocations of vet // on packages importing A. If B imports A, @@ -399,10 +406,17 @@ func doPackageCfg(cfgFile string) { mustTypecheck = true doPackage(vcfg.GoFiles, nil) if vcfg.VetxOutput != "" { - out := make(map[string]interface{}) + out := make([]vetxExport, 0, len(exporters)) for name, fn := range exporters { - out[name] = fn() + out = append(out, vetxExport{ + Name: name, + Data: fn(), + }) } + // Sort the data so that it is consistent across builds. + sort.Slice(out, func(i, j int) bool { + return out[i].Name < out[j].Name + }) var buf bytes.Buffer if err := gob.NewEncoder(&buf).Encode(out); err != nil { errorf("encoding vet output: %v", err) @@ -721,11 +735,15 @@ func readVetx(path, key string) interface{} { if err != nil { return nil } - m = make(map[string]interface{}) - err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m) + var out []vetxExport + err = gob.NewDecoder(bytes.NewReader(data)).Decode(&out) if err != nil { return nil } + m = make(map[string]interface{}) + for _, x := range out { + m[x.Name] = x.Data + } imported[path] = m } return m[key] diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go index 1edd3dd228..a55da1d3c8 100644 --- a/src/cmd/vet/print.go +++ b/src/cmd/vet/print.go @@ -16,6 +16,7 @@ import ( "go/token" "go/types" "regexp" + "sort" "strconv" "strings" "unicode/utf8" @@ -30,7 +31,7 @@ func init() { funcDecl, callExpr) registerPkgCheck("printf", findPrintfLike) registerExport("printf", exportPrintfLike) - gob.Register(map[string]int(nil)) + gob.Register([]printfExport(nil)) } func initPrintFlags() { @@ -57,13 +58,22 @@ func initPrintFlags() { var localPrintfLike = make(map[string]int) +type printfExport struct { + Name string + Kind int +} + +// printfImported maps from package name to the printf vet data +// exported by that package. +var printfImported = make(map[string]map[string]int) + type printfWrapper struct { - name string - fn *ast.FuncDecl - format *ast.Field - args *ast.Field - callers []printfCaller - printfLike bool + name string + fn *ast.FuncDecl + format *ast.Field + args *ast.Field + callers []printfCaller + failed bool // if true, not a printf wrapper } type printfCaller struct { @@ -158,6 +168,33 @@ func findPrintfLike(pkg *Package) { for _, w := range wrappers { // Scan function for calls that could be to other printf-like functions. ast.Inspect(w.fn.Body, func(n ast.Node) bool { + if w.failed { + return false + } + + // TODO: Relax these checks; issue 26555. + if assign, ok := n.(*ast.AssignStmt); ok { + for _, lhs := range assign.Lhs { + if match(lhs, w.format) || match(lhs, w.args) { + // Modifies the format + // string or args in + // some way, so not a + // simple wrapper. + w.failed = true + return false + } + } + } + if un, ok := n.(*ast.UnaryExpr); ok && un.Op == token.AND { + if match(un.X, w.format) || match(un.X, w.args) { + // Taking the address of the + // format string or args, + // so not a simple wrapper. + w.failed = true + return false + } + } + call, ok := n.(*ast.CallExpr) if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) { return true @@ -222,6 +259,20 @@ func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int } if !call.Ellipsis.IsValid() { + typ, ok := pkg.types[call.Fun].Type.(*types.Signature) + if !ok { + return + } + if len(call.Args) > typ.Params().Len() { + // If we're passing more arguments than what the + // print/printf function can take, adding an ellipsis + // would break the program. For example: + // + // func foo(arg1 string, arg2 ...interface{} { + // fmt.Printf("%s %v", arg1, arg2) + // } + return + } if !vcfg.VetxOnly { desc := "printf" if kind == kindPrint { @@ -241,7 +292,17 @@ func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int } func exportPrintfLike() interface{} { - return localPrintfLike + out := make([]printfExport, 0, len(localPrintfLike)) + for name, kind := range localPrintfLike { + out = append(out, printfExport{ + Name: name, + Kind: kind, + }) + } + sort.Slice(out, func(i, j int) bool { + return out[i].Name < out[j].Name + }) + return out } // isPrint records the print functions. @@ -438,9 +499,18 @@ func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kin if pkgpath == "" { kind = localPrintfLike[name] + } else if m, ok := printfImported[pkgpath]; ok { + kind = m[name] } else { - printfLike, _ := readVetx(pkgpath, "printf").(map[string]int) - kind = printfLike[name] + var m map[string]int + if out, ok := readVetx(pkgpath, "printf").([]printfExport); ok { + m = make(map[string]int) + for _, x := range out { + m[x.Name] = x.Kind + } + } + printfImported[pkgpath] = m + kind = m[name] } if kind == 0 { diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go index 3bc30c4740..32366eab44 100644 --- a/src/cmd/vet/structtag.go +++ b/src/cmd/vet/structtag.go @@ -10,6 +10,7 @@ import ( "errors" "go/ast" "go/token" + "go/types" "reflect" "strconv" "strings" @@ -24,9 +25,13 @@ func init() { // checkStructFieldTags checks all the field tags of a struct, including checking for duplicates. func checkStructFieldTags(f *File, node ast.Node) { + astType := node.(*ast.StructType) + typ := f.pkg.types[astType].Type.(*types.Struct) var seen map[[2]string]token.Pos - for _, field := range node.(*ast.StructType).Fields.List { - checkCanonicalFieldTag(f, field, &seen) + for i := 0; i < typ.NumFields(); i++ { + field := typ.Field(i) + tag := typ.Tag(i) + checkCanonicalFieldTag(f, astType, field, tag, &seen) } } @@ -34,83 +39,93 @@ var checkTagDups = []string{"json", "xml"} var checkTagSpaces = map[string]bool{"json": true, "xml": true, "asn1": true} // checkCanonicalFieldTag checks a single struct field tag. -func checkCanonicalFieldTag(f *File, field *ast.Field, seen *map[[2]string]token.Pos) { - if field.Tag == nil { - return - } - - tag, err := strconv.Unquote(field.Tag.Value) - if err != nil { - f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value) - return +// top is the top-level struct type that is currently being checked. +func checkCanonicalFieldTag(f *File, top *ast.StructType, field *types.Var, tag string, seen *map[[2]string]token.Pos) { + for _, key := range checkTagDups { + checkTagDuplicates(f, tag, key, field, field, seen) } if err := validateStructTag(tag); err != nil { - raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string - f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", raw, err) - } - - for _, key := range checkTagDups { - val := reflect.StructTag(tag).Get(key) - if val == "" || val == "-" || val[0] == ',' { - continue - } - if key == "xml" && len(field.Names) > 0 && field.Names[0].Name == "XMLName" { - // XMLName defines the XML element name of the struct being - // checked. That name cannot collide with element or attribute - // names defined on other fields of the struct. Vet does not have a - // check for untagged fields of type struct defining their own name - // by containing a field named XMLName; see issue 18256. - continue - } - if i := strings.Index(val, ","); i >= 0 { - if key == "xml" { - // Use a separate namespace for XML attributes. - for _, opt := range strings.Split(val[i:], ",") { - if opt == "attr" { - key += " attribute" // Key is part of the error message. - break - } - } - } - val = val[:i] - } - if *seen == nil { - *seen = map[[2]string]token.Pos{} - } - if pos, ok := (*seen)[[2]string{key, val}]; ok { - var name string - if len(field.Names) > 0 { - name = field.Names[0].Name - } else { - name = field.Type.(*ast.Ident).Name - } - f.Badf(field.Pos(), "struct field %s repeats %s tag %q also at %s", name, key, val, f.loc(pos)) - } else { - (*seen)[[2]string{key, val}] = field.Pos() - } + f.Badf(field.Pos(), "struct field tag %#q not compatible with reflect.StructTag.Get: %s", tag, err) } // Check for use of json or xml tags with unexported fields. // Embedded struct. Nothing to do for now, but that // may change, depending on what happens with issue 7363. - if len(field.Names) == 0 { + if field.Anonymous() { return } - if field.Names[0].IsExported() { + if field.Exported() { return } for _, enc := range [...]string{"json", "xml"} { if reflect.StructTag(tag).Get(enc) != "" { - f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc) + f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Name(), enc) return } } } +// checkTagDuplicates checks a single struct field tag to see if any tags are +// duplicated. nearest is the field that's closest to the field being checked, +// while still being part of the top-level struct type. +func checkTagDuplicates(f *File, tag, key string, nearest, field *types.Var, seen *map[[2]string]token.Pos) { + val := reflect.StructTag(tag).Get(key) + if val == "-" { + // Ignored, even if the field is anonymous. + return + } + if val == "" || val[0] == ',' { + if field.Anonymous() { + typ, ok := field.Type().Underlying().(*types.Struct) + if !ok { + return + } + for i := 0; i < typ.NumFields(); i++ { + field := typ.Field(i) + if !field.Exported() { + continue + } + tag := typ.Tag(i) + checkTagDuplicates(f, tag, key, nearest, field, seen) + } + } + // Ignored if the field isn't anonymous. + return + } + if key == "xml" && field.Name() == "XMLName" { + // XMLName defines the XML element name of the struct being + // checked. That name cannot collide with element or attribute + // names defined on other fields of the struct. Vet does not have a + // check for untagged fields of type struct defining their own name + // by containing a field named XMLName; see issue 18256. + return + } + if i := strings.Index(val, ","); i >= 0 { + if key == "xml" { + // Use a separate namespace for XML attributes. + for _, opt := range strings.Split(val[i:], ",") { + if opt == "attr" { + key += " attribute" // Key is part of the error message. + break + } + } + } + val = val[:i] + } + if *seen == nil { + *seen = map[[2]string]token.Pos{} + } + if pos, ok := (*seen)[[2]string{key, val}]; ok { + f.Badf(nearest.Pos(), "struct field %s repeats %s tag %q also at %s", field.Name(), key, val, f.loc(pos)) + } else { + (*seen)[[2]string{key, val}] = field.Pos() + } +} + var ( errTagSyntax = errors.New("bad syntax for struct tag pair") errTagKeySyntax = errors.New("bad syntax for struct tag key") diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go index 16f46a4897..88163b59d9 100644 --- a/src/cmd/vet/testdata/print.go +++ b/src/cmd/vet/testdata/print.go @@ -4,16 +4,10 @@ // This file contains tests for the printf checker. -// TODO(rsc): The user-defined wrapper tests are commented out -// because they produced too many false positives when vet was -// enabled during go test. See the TODO in ../print.go for a plan -// to fix that; when it's fixed, uncomment the user-defined wrapper tests. - package testdata import ( "fmt" - . "fmt" logpkg "log" // renamed to make it harder to see "math" "os" @@ -103,7 +97,7 @@ func PrintfTests() { fmt.Printf("%s", stringerarrayv) fmt.Printf("%v", notstringerarrayv) fmt.Printf("%T", notstringerarrayv) - fmt.Printf("%d", new(Formatter)) + fmt.Printf("%d", new(fmt.Formatter)) fmt.Printf("%*%", 2) // Ridiculous but allowed. fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say. @@ -250,13 +244,13 @@ func PrintfTests() { t.Logf("%d", 3) t.Logf("%d", "hi") // ERROR "Logf format %d has arg \x22hi\x22 of wrong type string" - // Errorf(1, "%d", 3) // OK - // Errorf(1, "%d", "hi") // no error "Errorf format %d has arg \x22hi\x22 of wrong type string" + Errorf(1, "%d", 3) // OK + Errorf(1, "%d", "hi") // ERROR "Errorf format %d has arg \x22hi\x22 of wrong type string" // Multiple string arguments before variadic args - // errorf("WARNING", "foobar") // OK - // errorf("INFO", "s=%s, n=%d", "foo", 1) // OK - // errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has 0 args" + errorf("WARNING", "foobar") // OK + errorf("INFO", "s=%s, n=%d", "foo", 1) // OK + errorf("ERROR", "%d") // no error "errorf format %d reads arg #1, but call has 0 args" // Printf from external package // externalprintf.Printf("%d", 42) // OK @@ -318,6 +312,9 @@ func PrintfTests() { l.Print("%d", 1) // ERROR "Print call has possible formatting directive %d" l.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string" l.Println("%d", 1) // ERROR "Println call has possible formatting directive %d" + + // Issue 26486 + dbg("", 1) // no error "call has arguments but no formatting directive" } func someString() string { return "X" } @@ -345,46 +342,32 @@ func (ss *someStruct) log(f func(), args ...interface{}) {} // A function we use as a function value; it has no other purpose. func someFunction() {} -/* // Printf is used by the test so we must declare it. func Printf(format string, args ...interface{}) { - panic("don't call - testing only") + fmt.Printf(format, args...) } // Println is used by the test so we must declare it. func Println(args ...interface{}) { - panic("don't call - testing only") + fmt.Println(args...) } -// Logf is used by the test so we must declare it. -func Logf(format string, args ...interface{}) { - panic("don't call - testing only") -} - -// Log is used by the test so we must declare it. -func Log(args ...interface{}) { - panic("don't call - testing only") -} -*/ - // printf is used by the test so we must declare it. func printf(format string, args ...interface{}) { - panic("don't call - testing only") + fmt.Printf(format, args...) } -/* // Errorf is used by the test for a case in which the first parameter // is not a format string. func Errorf(i int, format string, args ...interface{}) { - panic("don't call - testing only") + _ = fmt.Errorf(format, args...) } // errorf is used by the test for a case in which the function accepts multiple // string parameters before variadic arguments func errorf(level, format string, args ...interface{}) { - panic("don't call - testing only") + _ = fmt.Errorf(format, args...) } -*/ // multi is used by the test. func multi() []interface{} { @@ -443,6 +426,10 @@ func (*ptrStringer) BadWrapf(x int, format string, args ...interface{}) string { return fmt.Sprintf(format, args) // ERROR "missing ... in args forwarded to printf-like function" } +func (*ptrStringer) WrapfFalsePositive(x int, arg1 string, arg2 ...interface{}) string { + return fmt.Sprintf("%s %v", arg1, arg2) +} + type embeddedStringer struct { foo string ptrStringer @@ -650,3 +637,11 @@ func UnexportedStringerOrError() { func DisableErrorForFlag0() { fmt.Printf("%0t", true) } + +// Issue 26486. +func dbg(format string, args ...interface{}) { + if format == "" { + format = "%v" + } + fmt.Printf(format, args...) +} diff --git a/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go index ce21e803c8..ad55c4ab64 100644 --- a/src/cmd/vet/testdata/structtag.go +++ b/src/cmd/vet/testdata/structtag.go @@ -9,7 +9,7 @@ package testdata import "encoding/xml" type StructTagTest struct { - A int "hello" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" + A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" B int "\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key" C int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get" D int "x:`y`" // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value" @@ -42,43 +42,54 @@ type JSONEmbeddedField struct { type AnonymousJSON struct{} type AnonymousXML struct{} +type AnonymousJSONField struct { + DuplicateAnonJSON int `json:"a"` + + A int "hello" // ERROR "`hello` not compatible with reflect.StructTag.Get: bad syntax for struct tag pair" +} + type DuplicateJSONFields struct { JSON int `json:"a"` - DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:46" + DuplicateJSON int `json:"a"` // ERROR "struct field DuplicateJSON repeats json tag .a. also at structtag.go:52" IgnoredJSON int `json:"-"` OtherIgnoredJSON int `json:"-"` OmitJSON int `json:",omitempty"` OtherOmitJSON int `json:",omitempty"` - DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:46" + DuplicateOmitJSON int `json:"a,omitempty"` // ERROR "struct field DuplicateOmitJSON repeats json tag .a. also at structtag.go:52" NonJSON int `foo:"a"` DuplicateNonJSON int `foo:"a"` Embedded struct { DuplicateJSON int `json:"a"` // OK because its not in the same struct type } - AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:46" + AnonymousJSON `json:"a"` // ERROR "struct field AnonymousJSON repeats json tag .a. also at structtag.go:52" + + AnonymousJSONField // ERROR "struct field DuplicateAnonJSON repeats json tag .a. also at structtag.go:52" XML int `xml:"a"` - DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:60" + DuplicateXML int `xml:"a"` // ERROR "struct field DuplicateXML repeats xml tag .a. also at structtag.go:68" IgnoredXML int `xml:"-"` OtherIgnoredXML int `xml:"-"` OmitXML int `xml:",omitempty"` OtherOmitXML int `xml:",omitempty"` - DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:60" + DuplicateOmitXML int `xml:"a,omitempty"` // ERROR "struct field DuplicateOmitXML repeats xml tag .a. also at structtag.go:68" NonXML int `foo:"a"` DuplicateNonXML int `foo:"a"` - Embedded struct { + Embedded2 struct { DuplicateXML int `xml:"a"` // OK because its not in the same struct type } - AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:60" + AnonymousXML `xml:"a"` // ERROR "struct field AnonymousXML repeats xml tag .a. also at structtag.go:68" Attribute struct { XMLName xml.Name `xml:"b"` NoDup int `xml:"b"` // OK because XMLName above affects enclosing struct. Attr int `xml:"b,attr"` // OK because 0 is valid. - DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:76" - DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:76" + DupAttr int `xml:"b,attr"` // ERROR "struct field DupAttr repeats xml attribute tag .b. also at structtag.go:84" + DupOmitAttr int `xml:"b,omitempty,attr"` // ERROR "struct field DupOmitAttr repeats xml attribute tag .b. also at structtag.go:84" - AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:76" + AnonymousXML `xml:"b,attr"` // ERROR "struct field AnonymousXML repeats xml attribute tag .b. also at structtag.go:84" } + + AnonymousJSONField `json:"not_anon"` // ok; fields aren't embedded in JSON + AnonymousJSONField `json:"-"` // ok; entire field is ignored in JSON } type UnexpectedSpacetest struct { diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go index ecb4ce1295..90665d77bc 100644 --- a/src/cmd/vet/vet_test.go +++ b/src/cmd/vet/vet_test.go @@ -95,8 +95,7 @@ func TestVet(t *testing.T) { } batch := make([][]string, wide) for i, file := range gos { - // TODO: Remove print.go exception once we require type checking for everything, - // and then delete TestVetPrint. + // The print.go test is run by TestVetPrint. if strings.HasSuffix(file, "print.go") { continue } diff --git a/src/container/heap/heap.go b/src/container/heap/heap.go index 67b5efcac7..1ed0da8e6a 100644 --- a/src/container/heap/heap.go +++ b/src/container/heap/heap.go @@ -66,8 +66,8 @@ func Pop(h Interface) interface{} { return h.Pop() } -// Remove removes the element at index i from the heap. -// The complexity is O(log(n)) where n = h.Len(). +// Remove removes the element at index i from the heap and returns +// the element. The complexity is O(log(n)) where n = h.Len(). // func Remove(h Interface, i int) interface{} { n := h.Len() - 1 diff --git a/src/context/context.go b/src/context/context.go index 1b4fa41b8c..85f8acf8fa 100644 --- a/src/context/context.go +++ b/src/context/context.go @@ -210,8 +210,7 @@ func Background() Context { // TODO returns a non-nil, empty Context. Code should use context.TODO when // it's unclear which Context to use or it is not yet available (because the // surrounding function has not yet been extended to accept a Context -// parameter). TODO is recognized by static analysis tools that determine -// whether Contexts are propagated correctly in a program. +// parameter). func TODO() Context { return todo } diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go index 13ae2fcb82..49b78c3a8b 100644 --- a/src/crypto/aes/aes_gcm.go +++ b/src/crypto/aes/aes_gcm.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build amd64 +// +build amd64 arm64 package aes @@ -13,10 +13,7 @@ import ( "errors" ) -// The following functions are defined in gcm_amd64.s. - -//go:noescape -func aesEncBlock(dst, src *[16]byte, ks []uint32) +// The following functions are defined in gcm_*.s. //go:noescape func gcmAesInit(productTable *[256]byte, ks []uint32) @@ -118,7 +115,7 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) } - aesEncBlock(&tagMask, &counter, g.ks) + encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) var tagOut [gcmTagSize]byte gcmAesData(&g.productTable, data, &tagOut) @@ -171,7 +168,7 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) } - aesEncBlock(&tagMask, &counter, g.ks) + encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) var expectedTag [gcmTagSize]byte gcmAesData(&g.productTable, data, &expectedTag) diff --git a/src/crypto/aes/asm_arm64.s b/src/crypto/aes/asm_arm64.s index d2e8c8597f..13aee5ca29 100644 --- a/src/crypto/aes/asm_arm64.s +++ b/src/crypto/aes/asm_arm64.s @@ -3,7 +3,12 @@ // license that can be found in the LICENSE file. #include "textflag.h" - +DATA rotInvSRows<>+0x00(SB)/8, $0x080f0205040b0e01 +DATA rotInvSRows<>+0x08(SB)/8, $0x00070a0d0c030609 +GLOBL rotInvSRows<>(SB), (NOPTR+RODATA), $16 +DATA invSRows<>+0x00(SB)/8, $0x0b0e0104070a0d00 +DATA invSRows<>+0x08(SB)/8, $0x0306090c0f020508 +GLOBL invSRows<>(SB), (NOPTR+RODATA), $16 // func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) TEXT ·encryptBlockAsm(SB),NOSPLIT,$0 MOVD nr+0(FP), R9 @@ -105,3 +110,172 @@ dec128: VEOR V0.B16, V15.B16, V0.B16 VST1 [V0.B16], (R11) RET + +// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) { +// Note that round keys are stored in uint128 format, not uint32 +TEXT ·expandKeyAsm(SB),NOSPLIT,$0 + MOVD nr+0(FP), R8 + MOVD key+8(FP), R9 + MOVD enc+16(FP), R10 + MOVD dec+24(FP), R11 + LDP rotInvSRows<>(SB), (R0, R1) + VMOV R0, V3.D[0] + VMOV R1, V3.D[1] + VEOR V0.B16, V0.B16, V0.B16 // All zeroes + MOVW $1, R13 + TBZ $1, R8, ks192 + TBNZ $2, R8, ks256 + LDPW (R9), (R4, R5) + LDPW 8(R9), (R6, R7) + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + MOVW $0x1b, R14 +ks128Loop: + VMOV R7, V2.S[0] + WORD $0x4E030042 // TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 // Use AES to compute the SBOX + EORW R13, R4 + LSLW $1, R13 // Compute next Rcon + ANDSW $0x100, R13, ZR + CSELW NE, R14, R13, R13 // Fake modulo + SUBS $1, R8 + VMOV V2.S[0], R0 + EORW R0, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + BNE ks128Loop + CBZ R11, ksDone // If dec is nil we are done + SUB $176, R10 + // Decryption keys are encryption keys with InverseMixColumns applied + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1 (R10), [V0.B16, V1.B16, V2.B16] + AESIMC V0.B16, V14.B16 + AESIMC V1.B16, V13.B16 + VMOV V2.B16, V12.B16 + VST1.P [V12.B16, V13.B16, V14.B16], 48(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) + B ksDone +ks192: + LDPW (R9), (R2, R3) + LDPW 8(R9), (R4, R5) + LDPW 16(R9), (R6, R7) + STPW.P (R2, R3), 8(R10) + STPW.P (R4, R5), 8(R10) + SUB $4, R8 +ks192Loop: + STPW.P (R6, R7), 8(R10) + VMOV R7, V2.S[0] + WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + EORW R13, R2 + LSLW $1, R13 + SUBS $1, R8 + VMOV V2.S[0], R0 + EORW R0, R2 + EORW R2, R3 + EORW R3, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R2, R3), 8(R10) + STPW.P (R4, R5), 8(R10) + BNE ks192Loop + CBZ R11, ksDone + SUB $208, R10 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V15.B16 + AESIMC V1.B16, V14.B16 + AESIMC V2.B16, V13.B16 + AESIMC V3.B16, V12.B16 + VLD1 (R10), [V0.B16] + VST1.P [V0.B16], 16(R11) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) + B ksDone +ks256: + LDP invSRows<>(SB), (R0, R1) + VMOV R0, V4.D[0] + VMOV R1, V4.D[1] + LDPW (R9), (R0, R1) + LDPW 8(R9), (R2, R3) + LDPW 16(R9), (R4, R5) + LDPW 24(R9), (R6, R7) + STPW.P (R0, R1), 8(R10) + STPW.P (R2, R3), 8(R10) + SUB $7, R8 +ks256Loop: + STPW.P (R4, R5), 8(R10) + STPW.P (R6, R7), 8(R10) + VMOV R7, V2.S[0] + WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + EORW R13, R0 + LSLW $1, R13 + SUBS $1, R8 + VMOV V2.S[0], R9 + EORW R9, R0 + EORW R0, R1 + EORW R1, R2 + EORW R2, R3 + VMOV R3, V2.S[0] + WORD $0x4E040042 //TBL V3.B16, [V2.B16], V2.B16 + AESE V0.B16, V2.B16 + VMOV V2.S[0], R9 + EORW R9, R4 + EORW R4, R5 + EORW R5, R6 + EORW R6, R7 + STPW.P (R0, R1), 8(R10) + STPW.P (R2, R3), 8(R10) + BNE ks256Loop + CBZ R11, ksDone + SUB $240, R10 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + VMOV V0.B16, V7.B16 + AESIMC V1.B16, V6.B16 + AESIMC V2.B16, V5.B16 + AESIMC V3.B16, V4.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V11.B16 + AESIMC V1.B16, V10.B16 + AESIMC V2.B16, V9.B16 + AESIMC V3.B16, V8.B16 + VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16] + AESIMC V0.B16, V15.B16 + AESIMC V1.B16, V14.B16 + AESIMC V2.B16, V13.B16 + AESIMC V3.B16, V12.B16 + VLD1 (R10), [V0.B16, V1.B16, V2.B16] + AESIMC V0.B16, V18.B16 + AESIMC V1.B16, V17.B16 + VMOV V2.B16, V16.B16 + VST1.P [V16.B16, V17.B16, V18.B16], 48(R11) + VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11) + VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11) + VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11) +ksDone: + RET diff --git a/src/crypto/aes/block.go b/src/crypto/aes/block.go index 8647019d58..40bd0d335d 100644 --- a/src/crypto/aes/block.go +++ b/src/crypto/aes/block.go @@ -36,14 +36,17 @@ package aes +import ( + "encoding/binary" +) + // Encrypt one block from src into dst, using the expanded key xk. func encryptBlockGo(xk []uint32, dst, src []byte) { - var s0, s1, s2, s3, t0, t1, t2, t3 uint32 - - s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11]) - s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15]) + _ = src[15] // early bounds check + s0 := binary.BigEndian.Uint32(src[0:4]) + s1 := binary.BigEndian.Uint32(src[4:8]) + s2 := binary.BigEndian.Uint32(src[8:12]) + s3 := binary.BigEndian.Uint32(src[12:16]) // First round just XORs input with key. s0 ^= xk[0] @@ -55,6 +58,7 @@ func encryptBlockGo(xk []uint32, dst, src []byte) { // Number of rounds is set by length of expanded key. nr := len(xk)/4 - 2 // - 2: one above, one more below k := 4 + var t0, t1, t2, t3 uint32 for r := 0; r < nr; r++ { t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)] t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)] @@ -75,20 +79,20 @@ func encryptBlockGo(xk []uint32, dst, src []byte) { s2 ^= xk[k+2] s3 ^= xk[k+3] - dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0) - dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1) - dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2) - dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3) + _ = dst[15] // early bounds check + binary.BigEndian.PutUint32(dst[0:4], s0) + binary.BigEndian.PutUint32(dst[4:8], s1) + binary.BigEndian.PutUint32(dst[8:12], s2) + binary.BigEndian.PutUint32(dst[12:16], s3) } // Decrypt one block from src into dst, using the expanded key xk. func decryptBlockGo(xk []uint32, dst, src []byte) { - var s0, s1, s2, s3, t0, t1, t2, t3 uint32 - - s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) - s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7]) - s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11]) - s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15]) + _ = src[15] // early bounds check + s0 := binary.BigEndian.Uint32(src[0:4]) + s1 := binary.BigEndian.Uint32(src[4:8]) + s2 := binary.BigEndian.Uint32(src[8:12]) + s3 := binary.BigEndian.Uint32(src[12:16]) // First round just XORs input with key. s0 ^= xk[0] @@ -100,6 +104,7 @@ func decryptBlockGo(xk []uint32, dst, src []byte) { // Number of rounds is set by length of expanded key. nr := len(xk)/4 - 2 // - 2: one above, one more below k := 4 + var t0, t1, t2, t3 uint32 for r := 0; r < nr; r++ { t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)] t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)] @@ -120,10 +125,11 @@ func decryptBlockGo(xk []uint32, dst, src []byte) { s2 ^= xk[k+2] s3 ^= xk[k+3] - dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0) - dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1) - dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2) - dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3) + _ = dst[15] // early bounds check + binary.BigEndian.PutUint32(dst[0:4], s0) + binary.BigEndian.PutUint32(dst[4:8], s1) + binary.BigEndian.PutUint32(dst[8:12], s2) + binary.BigEndian.PutUint32(dst[12:16], s3) } // Apply sbox0 to each byte in w. @@ -144,7 +150,7 @@ func expandKeyGo(key []byte, enc, dec []uint32) { var i int nk := len(key) / 4 for i = 0; i < nk; i++ { - enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3]) + enc[i] = binary.BigEndian.Uint32(key[4*i:]) } for ; i < len(enc); i++ { t := enc[i-1] diff --git a/src/crypto/aes/cipher_arm64.go b/src/crypto/aes/cipher_arm64.go deleted file mode 100644 index a03547841f..0000000000 --- a/src/crypto/aes/cipher_arm64.go +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package aes - -import ( - "crypto/cipher" - "crypto/internal/subtle" - "internal/cpu" - "math/bits" -) - -// defined in asm_arm64.s -//go:noescape -func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) - -//go:noescape -func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) - -type aesCipherAsm struct { - aesCipher -} - -func newCipher(key []byte) (cipher.Block, error) { - if !cpu.ARM64.HasAES { - return newCipherGeneric(key) - } - n := len(key) + 28 - c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} - arm64ExpandKey(key, c.enc, c.dec) - return &c, nil -} - -func (c *aesCipherAsm) BlockSize() int { return BlockSize } - -func (c *aesCipherAsm) Encrypt(dst, src []byte) { - if len(src) < BlockSize { - panic("crypto/aes: input not full block") - } - if len(dst) < BlockSize { - panic("crypto/aes: output not full block") - } - if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { - panic("crypto/aes: invalid buffer overlap") - } - encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0]) -} - -func (c *aesCipherAsm) Decrypt(dst, src []byte) { - if len(src) < BlockSize { - panic("crypto/aes: input not full block") - } - if len(dst) < BlockSize { - panic("crypto/aes: output not full block") - } - if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) { - panic("crypto/aes: invalid buffer overlap") - } - decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0]) -} - -func arm64ExpandKey(key []byte, enc, dec []uint32) { - expandKeyGo(key, enc, dec) - nk := len(enc) - for i := 0; i < nk; i++ { - enc[i] = bits.ReverseBytes32(enc[i]) - dec[i] = bits.ReverseBytes32(dec[i]) - } -} - -// expandKey is used by BenchmarkExpand to ensure that the asm implementation -// of key expansion is used for the benchmark when it is available. -func expandKey(key []byte, enc, dec []uint32) { - if cpu.ARM64.HasAES { - arm64ExpandKey(key, enc, dec) - } else { - expandKeyGo(key, enc, dec) - } -} diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_asm.go similarity index 88% rename from src/crypto/aes/cipher_amd64.go rename to src/crypto/aes/cipher_asm.go index fd88343cae..93b963b285 100644 --- a/src/crypto/aes/cipher_amd64.go +++ b/src/crypto/aes/cipher_asm.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build amd64 arm64 + package aes import ( @@ -11,23 +13,31 @@ import ( "internal/cpu" ) -// defined in asm_amd64.s +// defined in asm_*.s +//go:noescape func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) + +//go:noescape func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) + +//go:noescape func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) type aesCipherAsm struct { aesCipher } +var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES +var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL + func newCipher(key []byte) (cipher.Block, error) { - if !cpu.X86.HasAES { + if !supportsAES { return newCipherGeneric(key) } n := len(key) + 28 c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} - rounds := 10 + var rounds int switch len(key) { case 128 / 8: rounds = 10 @@ -38,10 +48,9 @@ func newCipher(key []byte) (cipher.Block, error) { } expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0]) - if cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ { + if supportsAES && supportsGFMUL { return &aesCipherGCM{c}, nil } - return &c, nil } @@ -78,7 +87,7 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) { // expandKey is used by BenchmarkExpand to ensure that the asm implementation // of key expansion is used for the benchmark when it is available. func expandKey(key []byte, enc, dec []uint32) { - if cpu.X86.HasAES { + if supportsAES { rounds := 10 // rounds needed for AES128 switch len(key) { case 192 / 8: diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go index 8fa85a3ae8..bfa8cbba7f 100644 --- a/src/crypto/aes/ctr_s390x.go +++ b/src/crypto/aes/ctr_s390x.go @@ -7,7 +7,7 @@ package aes import ( "crypto/cipher" "crypto/internal/subtle" - "unsafe" + "encoding/binary" ) // Assert that aesCipherAsm implements the ctrAble interface. @@ -38,8 +38,8 @@ func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream { } var ac aesctr ac.block = c - ac.ctr[0] = *(*uint64)(unsafe.Pointer((&iv[0]))) // high bits - ac.ctr[1] = *(*uint64)(unsafe.Pointer((&iv[8]))) // low bits + ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits + ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits ac.buffer = ac.storage[:0] return &ac } @@ -48,10 +48,10 @@ func (c *aesctr) refill() { // Fill up the buffer with an incrementing count. c.buffer = c.storage[:streamBufferSize] c0, c1 := c.ctr[0], c.ctr[1] - for i := 0; i < streamBufferSize; i += BlockSize { - b0 := (*uint64)(unsafe.Pointer(&c.buffer[i])) - b1 := (*uint64)(unsafe.Pointer(&c.buffer[i+BlockSize/2])) - *b0, *b1 = c0, c1 + for i := 0; i < streamBufferSize; i += 16 { + binary.BigEndian.PutUint64(c.buffer[i+0:], c0) + binary.BigEndian.PutUint64(c.buffer[i+8:], c1) + // Increment in big endian: c0 is high, c1 is low. c1++ if c1 == 0 { diff --git a/src/crypto/aes/gcm_amd64.s b/src/crypto/aes/gcm_amd64.s index b651cc4925..e6eedf3264 100644 --- a/src/crypto/aes/gcm_amd64.s +++ b/src/crypto/aes/gcm_amd64.s @@ -71,56 +71,6 @@ GLOBL bswapMask<>(SB), (NOPTR+RODATA), $16 GLOBL gcmPoly<>(SB), (NOPTR+RODATA), $16 GLOBL andMask<>(SB), (NOPTR+RODATA), $240 -// func aesEncBlock(dst, src *[16]byte, ks []uint32) -TEXT ·aesEncBlock(SB),NOSPLIT,$0 - MOVQ dst+0(FP), DI - MOVQ src+8(FP), SI - MOVQ ks_base+16(FP), DX - MOVQ ks_len+24(FP), CX - - SHRQ $2, CX - DECQ CX - - MOVOU (SI), X0 - MOVOU (16*0)(DX), X1 - PXOR X1, X0 - MOVOU (16*1)(DX), X1 - AESENC X1, X0 - MOVOU (16*2)(DX), X1 - AESENC X1, X0 - MOVOU (16*3)(DX), X1 - AESENC X1, X0 - MOVOU (16*4)(DX), X1 - AESENC X1, X0 - MOVOU (16*5)(DX), X1 - AESENC X1, X0 - MOVOU (16*6)(DX), X1 - AESENC X1, X0 - MOVOU (16*7)(DX), X1 - AESENC X1, X0 - MOVOU (16*8)(DX), X1 - AESENC X1, X0 - MOVOU (16*9)(DX), X1 - AESENC X1, X0 - MOVOU (16*10)(DX), X1 - CMPQ CX, $12 - JB encLast - AESENC X1, X0 - MOVOU (16*11)(DX), X1 - AESENC X1, X0 - MOVOU (16*12)(DX), X1 - JE encLast - AESENC X1, X0 - MOVOU (16*13)(DX), X1 - AESENC X1, X0 - MOVOU (16*14)(DX), X1 - -encLast: - AESENCLAST X1, X0 - MOVOU X0, (DI) - - RET - // func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) TEXT ·gcmAesFinish(SB),NOSPLIT,$0 #define pTbl DI diff --git a/src/crypto/aes/gcm_arm64.s b/src/crypto/aes/gcm_arm64.s new file mode 100644 index 0000000000..61c868cd0c --- /dev/null +++ b/src/crypto/aes/gcm_arm64.s @@ -0,0 +1,1021 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "textflag.h" + +#define B0 V0 +#define B1 V1 +#define B2 V2 +#define B3 V3 +#define B4 V4 +#define B5 V5 +#define B6 V6 +#define B7 V7 + +#define ACC0 V8 +#define ACC1 V9 +#define ACCM V10 + +#define T0 V11 +#define T1 V12 +#define T2 V13 +#define T3 V14 + +#define POLY V15 +#define ZERO V16 +#define INC V17 +#define CTR V18 + +#define K0 V19 +#define K1 V20 +#define K2 V21 +#define K3 V22 +#define K4 V23 +#define K5 V24 +#define K6 V25 +#define K7 V26 +#define K8 V27 +#define K9 V28 +#define K10 V29 +#define K11 V30 +#define KLAST V31 + +#define reduce() \ + VEOR ACC0.B16, ACCM.B16, ACCM.B16 \ + VEOR ACC1.B16, ACCM.B16, ACCM.B16 \ + VEXT $8, ZERO.B16, ACCM.B16, T0.B16 \ + VEXT $8, ACCM.B16, ZERO.B16, ACCM.B16 \ + VEOR ACCM.B16, ACC0.B16, ACC0.B16 \ + VEOR T0.B16, ACC1.B16, ACC1.B16 \ + VPMULL POLY.D1, ACC0.D1, T0.Q1 \ + VEXT $8, ACC0.B16, ACC0.B16, ACC0.B16 \ + VEOR T0.B16, ACC0.B16, ACC0.B16 \ + VPMULL POLY.D1, ACC0.D1, T0.Q1 \ + VEOR T0.B16, ACC1.B16, ACC1.B16 \ + VEXT $8, ACC1.B16, ACC1.B16, ACC1.B16 \ + VEOR ACC1.B16, ACC0.B16, ACC0.B16 \ + +// func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) +TEXT ·gcmAesFinish(SB),NOSPLIT,$0 +#define pTbl R0 +#define tMsk R1 +#define tPtr R2 +#define plen R3 +#define dlen R4 + + MOVD $0xC2, R1 + LSL $56, R1 + MOVD $1, R0 + VMOV R1, POLY.D[0] + VMOV R0, POLY.D[1] + VEOR ZERO.B16, ZERO.B16, ZERO.B16 + + MOVD productTable+0(FP), pTbl + MOVD tagMask+8(FP), tMsk + MOVD T+16(FP), tPtr + MOVD pLen+24(FP), plen + MOVD dLen+32(FP), dlen + + VLD1 (tPtr), [ACC0.B16] + VLD1 (tMsk), [B1.B16] + + LSL $3, plen + LSL $3, dlen + + VMOV dlen, B0.D[0] + VMOV plen, B0.D[1] + + ADD $14*16, pTbl + VLD1.P (pTbl), [T1.B16, T2.B16] + + VEOR ACC0.B16, B0.B16, B0.B16 + + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + + reduce() + + VREV64 ACC0.B16, ACC0.B16 + VEOR B1.B16, ACC0.B16, ACC0.B16 + + VST1 [ACC0.B16], (tPtr) + RET +#undef pTbl +#undef tMsk +#undef tPtr +#undef plen +#undef dlen + +// func gcmAesInit(productTable *[256]byte, ks []uint32) +TEXT ·gcmAesInit(SB),NOSPLIT,$0 +#define pTbl R0 +#define KS R1 +#define NR R2 +#define I R3 + MOVD productTable+0(FP), pTbl + MOVD ks_base+8(FP), KS + MOVD ks_len+16(FP), NR + + MOVD $0xC2, I + LSL $56, I + VMOV I, POLY.D[0] + MOVD $1, I + VMOV I, POLY.D[1] + VEOR ZERO.B16, ZERO.B16, ZERO.B16 + + // Encrypt block 0 with the AES key to generate the hash key H + VLD1.P 64(KS), [T0.B16, T1.B16, T2.B16, T3.B16] + VEOR B0.B16, B0.B16, B0.B16 + AESE T0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T3.B16, B0.B16 + AESMC B0.B16, B0.B16 + VLD1.P 64(KS), [T0.B16, T1.B16, T2.B16, T3.B16] + AESE T0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T3.B16, B0.B16 + AESMC B0.B16, B0.B16 + TBZ $4, NR, initEncFinish + VLD1.P 32(KS), [T0.B16, T1.B16] + AESE T0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T1.B16, B0.B16 + AESMC B0.B16, B0.B16 + TBZ $3, NR, initEncFinish + VLD1.P 32(KS), [T0.B16, T1.B16] + AESE T0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T1.B16, B0.B16 + AESMC B0.B16, B0.B16 +initEncFinish: + VLD1 (KS), [T0.B16, T1.B16, T2.B16] + AESE T0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE T1.B16, B0.B16 + VEOR T2.B16, B0.B16, B0.B16 + + VREV64 B0.B16, B0.B16 + + // Multiply by 2 modulo P + VMOV B0.D[0], I + ASR $63, I + VMOV I, T1.D[0] + VMOV I, T1.D[1] + VAND POLY.B16, T1.B16, T1.B16 + VUSHR $63, B0.D2, T2.D2 + VEXT $8, ZERO.B16, T2.B16, T2.B16 + VSHL $1, B0.D2, B0.D2 + VEOR T1.B16, B0.B16, B0.B16 + VEOR T2.B16, B0.B16, B0.B16 // Can avoid this when VSLI is available + + // Karatsuba pre-computation + VEXT $8, B0.B16, B0.B16, B1.B16 + VEOR B0.B16, B1.B16, B1.B16 + + ADD $14*16, pTbl + VST1 [B0.B16, B1.B16], (pTbl) + SUB $2*16, pTbl + + VMOV B0.B16, B2.B16 + VMOV B1.B16, B3.B16 + + MOVD $7, I + +initLoop: + // Compute powers of H + SUBS $1, I + + VPMULL B0.D1, B2.D1, T1.Q1 + VPMULL2 B0.D2, B2.D2, T0.Q1 + VPMULL B1.D1, B3.D1, T2.Q1 + VEOR T0.B16, T2.B16, T2.B16 + VEOR T1.B16, T2.B16, T2.B16 + VEXT $8, ZERO.B16, T2.B16, T3.B16 + VEXT $8, T2.B16, ZERO.B16, T2.B16 + VEOR T2.B16, T0.B16, T0.B16 + VEOR T3.B16, T1.B16, T1.B16 + VPMULL POLY.D1, T0.D1, T2.Q1 + VEXT $8, T0.B16, T0.B16, T0.B16 + VEOR T2.B16, T0.B16, T0.B16 + VPMULL POLY.D1, T0.D1, T2.Q1 + VEXT $8, T0.B16, T0.B16, T0.B16 + VEOR T2.B16, T0.B16, T0.B16 + VEOR T1.B16, T0.B16, B2.B16 + VMOV B2.B16, B3.B16 + VEXT $8, B2.B16, B2.B16, B2.B16 + VEOR B2.B16, B3.B16, B3.B16 + + VST1 [B2.B16, B3.B16], (pTbl) + SUB $2*16, pTbl + + BNE initLoop + RET +#undef I +#undef NR +#undef KS +#undef pTbl + +// func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) +TEXT ·gcmAesData(SB),NOSPLIT,$0 +#define pTbl R0 +#define aut R1 +#define tPtr R2 +#define autLen R3 +#define H0 R4 +#define pTblSave R5 + +#define mulRound(X) \ + VLD1.P 32(pTbl), [T1.B16, T2.B16] \ + VREV64 X.B16, X.B16 \ + VEXT $8, X.B16, X.B16, T0.B16 \ + VEOR X.B16, T0.B16, T0.B16 \ + VPMULL X.D1, T1.D1, T3.Q1 \ + VEOR T3.B16, ACC1.B16, ACC1.B16 \ + VPMULL2 X.D2, T1.D2, T3.Q1 \ + VEOR T3.B16, ACC0.B16, ACC0.B16 \ + VPMULL T0.D1, T2.D1, T3.Q1 \ + VEOR T3.B16, ACCM.B16, ACCM.B16 + + MOVD productTable+0(FP), pTbl + MOVD data_base+8(FP), aut + MOVD data_len+16(FP), autLen + MOVD T+32(FP), tPtr + + VEOR ACC0.B16, ACC0.B16, ACC0.B16 + CBZ autLen, dataBail + + MOVD $0xC2, H0 + LSL $56, H0 + VMOV H0, POLY.D[0] + MOVD $1, H0 + VMOV H0, POLY.D[1] + VEOR ZERO.B16, ZERO.B16, ZERO.B16 + MOVD pTbl, pTblSave + + CMP $13, autLen + BEQ dataTLS + CMP $128, autLen + BLT startSinglesLoop + B octetsLoop + +dataTLS: + ADD $14*16, pTbl + VLD1.P (pTbl), [T1.B16, T2.B16] + VEOR B0.B16, B0.B16, B0.B16 + + MOVD (aut), H0 + VMOV H0, B0.D[0] + MOVW 8(aut), H0 + VMOV H0, B0.S[2] + MOVB 12(aut), H0 + VMOV H0, B0.B[12] + + MOVD $0, autLen + B dataMul + +octetsLoop: + CMP $128, autLen + BLT startSinglesLoop + SUB $128, autLen + + VLD1.P 32(aut), [B0.B16, B1.B16] + + VLD1.P 32(pTbl), [T1.B16, T2.B16] + VREV64 B0.B16, B0.B16 + VEOR ACC0.B16, B0.B16, B0.B16 + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + + mulRound(B1) + VLD1.P 32(aut), [B2.B16, B3.B16] + mulRound(B2) + mulRound(B3) + VLD1.P 32(aut), [B4.B16, B5.B16] + mulRound(B4) + mulRound(B5) + VLD1.P 32(aut), [B6.B16, B7.B16] + mulRound(B6) + mulRound(B7) + + MOVD pTblSave, pTbl + reduce() + B octetsLoop + +startSinglesLoop: + + ADD $14*16, pTbl + VLD1.P (pTbl), [T1.B16, T2.B16] + +singlesLoop: + + CMP $16, autLen + BLT dataEnd + SUB $16, autLen + + VLD1.P 16(aut), [B0.B16] +dataMul: + VREV64 B0.B16, B0.B16 + VEOR ACC0.B16, B0.B16, B0.B16 + + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + + reduce() + + B singlesLoop + +dataEnd: + + CBZ autLen, dataBail + VEOR B0.B16, B0.B16, B0.B16 + ADD autLen, aut + +dataLoadLoop: + MOVB.W -1(aut), H0 + VEXT $15, B0.B16, ZERO.B16, B0.B16 + VMOV H0, B0.B[0] + SUBS $1, autLen + BNE dataLoadLoop + B dataMul + +dataBail: + VST1 [ACC0.B16], (tPtr) + RET + +#undef pTbl +#undef aut +#undef tPtr +#undef autLen +#undef H0 +#undef pTblSave + +// func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) +TEXT ·gcmAesEnc(SB),NOSPLIT,$0 +#define pTbl R0 +#define dstPtr R1 +#define ctrPtr R2 +#define srcPtr R3 +#define ks R4 +#define tPtr R5 +#define srcPtrLen R6 +#define aluCTR R7 +#define aluTMP R8 +#define aluK R9 +#define NR R10 +#define H0 R11 +#define H1 R12 +#define curK R13 +#define pTblSave R14 + +#define aesrndx8(K) \ + AESE K.B16, B0.B16 \ + AESMC B0.B16, B0.B16 \ + AESE K.B16, B1.B16 \ + AESMC B1.B16, B1.B16 \ + AESE K.B16, B2.B16 \ + AESMC B2.B16, B2.B16 \ + AESE K.B16, B3.B16 \ + AESMC B3.B16, B3.B16 \ + AESE K.B16, B4.B16 \ + AESMC B4.B16, B4.B16 \ + AESE K.B16, B5.B16 \ + AESMC B5.B16, B5.B16 \ + AESE K.B16, B6.B16 \ + AESMC B6.B16, B6.B16 \ + AESE K.B16, B7.B16 \ + AESMC B7.B16, B7.B16 + +#define aesrndlastx8(K) \ + AESE K.B16, B0.B16 \ + AESE K.B16, B1.B16 \ + AESE K.B16, B2.B16 \ + AESE K.B16, B3.B16 \ + AESE K.B16, B4.B16 \ + AESE K.B16, B5.B16 \ + AESE K.B16, B6.B16 \ + AESE K.B16, B7.B16 + + MOVD productTable+0(FP), pTbl + MOVD dst+8(FP), dstPtr + MOVD src_base+32(FP), srcPtr + MOVD src_len+40(FP), srcPtrLen + MOVD ctr+56(FP), ctrPtr + MOVD T+64(FP), tPtr + MOVD ks_base+72(FP), ks + MOVD ks_len+80(FP), NR + + MOVD $0xC2, H1 + LSL $56, H1 + MOVD $1, H0 + VMOV H1, POLY.D[0] + VMOV H0, POLY.D[1] + VEOR ZERO.B16, ZERO.B16, ZERO.B16 + // Compute NR from len(ks) + MOVD pTbl, pTblSave + // Current tag, after AAD + VLD1 (tPtr), [ACC0.B16] + VEOR ACC1.B16, ACC1.B16, ACC1.B16 + VEOR ACCM.B16, ACCM.B16, ACCM.B16 + // Prepare initial counter, and the increment vector + VLD1 (ctrPtr), [CTR.B16] + VEOR INC.B16, INC.B16, INC.B16 + MOVD $1, H0 + VMOV H0, INC.S[3] + VREV32 CTR.B16, CTR.B16 + VADD CTR.S4, INC.S4, CTR.S4 + // Skip to <8 blocks loop + CMP $128, srcPtrLen + + MOVD ks, H0 + // For AES-128 round keys are stored in: K0 .. K10, KLAST + VLD1.P 64(H0), [K0.B16, K1.B16, K2.B16, K3.B16] + VLD1.P 64(H0), [K4.B16, K5.B16, K6.B16, K7.B16] + VLD1.P 48(H0), [K8.B16, K9.B16, K10.B16] + VMOV K10.B16, KLAST.B16 + + BLT startSingles + // There are at least 8 blocks to encrypt + TBZ $4, NR, octetsLoop + + // For AES-192 round keys occupy: K0 .. K7, K10, K11, K8, K9, KLAST + VMOV K8.B16, K10.B16 + VMOV K9.B16, K11.B16 + VMOV KLAST.B16, K8.B16 + VLD1.P 16(H0), [K9.B16] + VLD1.P 16(H0), [KLAST.B16] + TBZ $3, NR, octetsLoop + // For AES-256 round keys occupy: K0 .. K7, K10, K11, mem, mem, K8, K9, KLAST + VMOV KLAST.B16, K8.B16 + VLD1.P 16(H0), [K9.B16] + VLD1.P 16(H0), [KLAST.B16] + ADD $10*16, ks, H0 + MOVD H0, curK + +octetsLoop: + SUB $128, srcPtrLen + + VMOV CTR.B16, B0.B16 + VADD B0.S4, INC.S4, B1.S4 + VREV32 B0.B16, B0.B16 + VADD B1.S4, INC.S4, B2.S4 + VREV32 B1.B16, B1.B16 + VADD B2.S4, INC.S4, B3.S4 + VREV32 B2.B16, B2.B16 + VADD B3.S4, INC.S4, B4.S4 + VREV32 B3.B16, B3.B16 + VADD B4.S4, INC.S4, B5.S4 + VREV32 B4.B16, B4.B16 + VADD B5.S4, INC.S4, B6.S4 + VREV32 B5.B16, B5.B16 + VADD B6.S4, INC.S4, B7.S4 + VREV32 B6.B16, B6.B16 + VADD B7.S4, INC.S4, CTR.S4 + VREV32 B7.B16, B7.B16 + + aesrndx8(K0) + aesrndx8(K1) + aesrndx8(K2) + aesrndx8(K3) + aesrndx8(K4) + aesrndx8(K5) + aesrndx8(K6) + aesrndx8(K7) + TBZ $4, NR, octetsFinish + aesrndx8(K10) + aesrndx8(K11) + TBZ $3, NR, octetsFinish + VLD1.P 32(curK), [T1.B16, T2.B16] + aesrndx8(T1) + aesrndx8(T2) + MOVD H0, curK +octetsFinish: + aesrndx8(K8) + aesrndlastx8(K9) + + VEOR KLAST.B16, B0.B16, B0.B16 + VEOR KLAST.B16, B1.B16, B1.B16 + VEOR KLAST.B16, B2.B16, B2.B16 + VEOR KLAST.B16, B3.B16, B3.B16 + VEOR KLAST.B16, B4.B16, B4.B16 + VEOR KLAST.B16, B5.B16, B5.B16 + VEOR KLAST.B16, B6.B16, B6.B16 + VEOR KLAST.B16, B7.B16, B7.B16 + + VLD1.P 32(srcPtr), [T1.B16, T2.B16] + VEOR B0.B16, T1.B16, B0.B16 + VEOR B1.B16, T2.B16, B1.B16 + VST1.P [B0.B16, B1.B16], 32(dstPtr) + VLD1.P 32(srcPtr), [T1.B16, T2.B16] + VEOR B2.B16, T1.B16, B2.B16 + VEOR B3.B16, T2.B16, B3.B16 + VST1.P [B2.B16, B3.B16], 32(dstPtr) + VLD1.P 32(srcPtr), [T1.B16, T2.B16] + VEOR B4.B16, T1.B16, B4.B16 + VEOR B5.B16, T2.B16, B5.B16 + VST1.P [B4.B16, B5.B16], 32(dstPtr) + VLD1.P 32(srcPtr), [T1.B16, T2.B16] + VEOR B6.B16, T1.B16, B6.B16 + VEOR B7.B16, T2.B16, B7.B16 + VST1.P [B6.B16, B7.B16], 32(dstPtr) + + VLD1.P 32(pTbl), [T1.B16, T2.B16] + VREV64 B0.B16, B0.B16 + VEOR ACC0.B16, B0.B16, B0.B16 + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + + mulRound(B1) + mulRound(B2) + mulRound(B3) + mulRound(B4) + mulRound(B5) + mulRound(B6) + mulRound(B7) + MOVD pTblSave, pTbl + reduce() + + CMP $128, srcPtrLen + BGE octetsLoop + +startSingles: + CBZ srcPtrLen, done + ADD $14*16, pTbl + // Preload H and its Karatsuba precomp + VLD1.P (pTbl), [T1.B16, T2.B16] + // Preload AES round keys + ADD $128, ks + VLD1.P 48(ks), [K8.B16, K9.B16, K10.B16] + VMOV K10.B16, KLAST.B16 + TBZ $4, NR, singlesLoop + VLD1.P 32(ks), [B1.B16, B2.B16] + VMOV B2.B16, KLAST.B16 + TBZ $3, NR, singlesLoop + VLD1.P 32(ks), [B3.B16, B4.B16] + VMOV B4.B16, KLAST.B16 + +singlesLoop: + CMP $16, srcPtrLen + BLT tail + SUB $16, srcPtrLen + + VLD1.P 16(srcPtr), [T0.B16] + VEOR KLAST.B16, T0.B16, T0.B16 + + VREV32 CTR.B16, B0.B16 + VADD CTR.S4, INC.S4, CTR.S4 + + AESE K0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K3.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K4.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K5.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K6.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K7.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K8.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K9.B16, B0.B16 + TBZ $4, NR, singlesLast + AESMC B0.B16, B0.B16 + AESE K10.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B1.B16, B0.B16 + TBZ $3, NR, singlesLast + AESMC B0.B16, B0.B16 + AESE B2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B3.B16, B0.B16 +singlesLast: + VEOR T0.B16, B0.B16, B0.B16 +encReduce: + VST1.P [B0.B16], 16(dstPtr) + + VREV64 B0.B16, B0.B16 + VEOR ACC0.B16, B0.B16, B0.B16 + + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + + reduce() + + B singlesLoop +tail: + CBZ srcPtrLen, done + + VEOR T0.B16, T0.B16, T0.B16 + VEOR T3.B16, T3.B16, T3.B16 + MOVD $0, H1 + SUB $1, H1 + ADD srcPtrLen, srcPtr + + TBZ $3, srcPtrLen, ld4 + MOVD.W -8(srcPtr), H0 + VMOV H0, T0.D[0] + VMOV H1, T3.D[0] +ld4: + TBZ $2, srcPtrLen, ld2 + MOVW.W -4(srcPtr), H0 + VEXT $12, T0.B16, ZERO.B16, T0.B16 + VEXT $12, T3.B16, ZERO.B16, T3.B16 + VMOV H0, T0.S[0] + VMOV H1, T3.S[0] +ld2: + TBZ $1, srcPtrLen, ld1 + MOVH.W -2(srcPtr), H0 + VEXT $14, T0.B16, ZERO.B16, T0.B16 + VEXT $14, T3.B16, ZERO.B16, T3.B16 + VMOV H0, T0.H[0] + VMOV H1, T3.H[0] +ld1: + TBZ $0, srcPtrLen, ld0 + MOVB.W -1(srcPtr), H0 + VEXT $15, T0.B16, ZERO.B16, T0.B16 + VEXT $15, T3.B16, ZERO.B16, T3.B16 + VMOV H0, T0.B[0] + VMOV H1, T3.B[0] +ld0: + + MOVD ZR, srcPtrLen + VEOR KLAST.B16, T0.B16, T0.B16 + VREV32 CTR.B16, B0.B16 + + AESE K0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K3.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K4.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K5.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K6.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K7.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K8.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K9.B16, B0.B16 + TBZ $4, NR, tailLast + AESMC B0.B16, B0.B16 + AESE K10.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B1.B16, B0.B16 + TBZ $3, NR, tailLast + AESMC B0.B16, B0.B16 + AESE B2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B3.B16, B0.B16 + +tailLast: + VEOR T0.B16, B0.B16, B0.B16 + VAND T3.B16, B0.B16, B0.B16 + B encReduce + +done: + VST1 [ACC0.B16], (tPtr) + RET + +// func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) +TEXT ·gcmAesDec(SB),NOSPLIT,$0 + MOVD productTable+0(FP), pTbl + MOVD dst+8(FP), dstPtr + MOVD src_base+32(FP), srcPtr + MOVD src_len+40(FP), srcPtrLen + MOVD ctr+56(FP), ctrPtr + MOVD T+64(FP), tPtr + MOVD ks_base+72(FP), ks + MOVD ks_len+80(FP), NR + + MOVD $0xC2, H1 + LSL $56, H1 + MOVD $1, H0 + VMOV H1, POLY.D[0] + VMOV H0, POLY.D[1] + VEOR ZERO.B16, ZERO.B16, ZERO.B16 + // Compute NR from len(ks) + MOVD pTbl, pTblSave + // Current tag, after AAD + VLD1 (tPtr), [ACC0.B16] + VEOR ACC1.B16, ACC1.B16, ACC1.B16 + VEOR ACCM.B16, ACCM.B16, ACCM.B16 + // Prepare initial counter, and the increment vector + VLD1 (ctrPtr), [CTR.B16] + VEOR INC.B16, INC.B16, INC.B16 + MOVD $1, H0 + VMOV H0, INC.S[3] + VREV32 CTR.B16, CTR.B16 + VADD CTR.S4, INC.S4, CTR.S4 + + MOVD ks, H0 + // For AES-128 round keys are stored in: K0 .. K10, KLAST + VLD1.P 64(H0), [K0.B16, K1.B16, K2.B16, K3.B16] + VLD1.P 64(H0), [K4.B16, K5.B16, K6.B16, K7.B16] + VLD1.P 48(H0), [K8.B16, K9.B16, K10.B16] + VMOV K10.B16, KLAST.B16 + + // Skip to <8 blocks loop + CMP $128, srcPtrLen + BLT startSingles + // There are at least 8 blocks to encrypt + TBZ $4, NR, octetsLoop + + // For AES-192 round keys occupy: K0 .. K7, K10, K11, K8, K9, KLAST + VMOV K8.B16, K10.B16 + VMOV K9.B16, K11.B16 + VMOV KLAST.B16, K8.B16 + VLD1.P 16(H0), [K9.B16] + VLD1.P 16(H0), [KLAST.B16] + TBZ $3, NR, octetsLoop + // For AES-256 round keys occupy: K0 .. K7, K10, K11, mem, mem, K8, K9, KLAST + VMOV KLAST.B16, K8.B16 + VLD1.P 16(H0), [K9.B16] + VLD1.P 16(H0), [KLAST.B16] + ADD $10*16, ks, H0 + MOVD H0, curK + +octetsLoop: + SUB $128, srcPtrLen + + VMOV CTR.B16, B0.B16 + VADD B0.S4, INC.S4, B1.S4 + VREV32 B0.B16, B0.B16 + VADD B1.S4, INC.S4, B2.S4 + VREV32 B1.B16, B1.B16 + VADD B2.S4, INC.S4, B3.S4 + VREV32 B2.B16, B2.B16 + VADD B3.S4, INC.S4, B4.S4 + VREV32 B3.B16, B3.B16 + VADD B4.S4, INC.S4, B5.S4 + VREV32 B4.B16, B4.B16 + VADD B5.S4, INC.S4, B6.S4 + VREV32 B5.B16, B5.B16 + VADD B6.S4, INC.S4, B7.S4 + VREV32 B6.B16, B6.B16 + VADD B7.S4, INC.S4, CTR.S4 + VREV32 B7.B16, B7.B16 + + aesrndx8(K0) + aesrndx8(K1) + aesrndx8(K2) + aesrndx8(K3) + aesrndx8(K4) + aesrndx8(K5) + aesrndx8(K6) + aesrndx8(K7) + TBZ $4, NR, octetsFinish + aesrndx8(K10) + aesrndx8(K11) + TBZ $3, NR, octetsFinish + VLD1.P 32(curK), [T1.B16, T2.B16] + aesrndx8(T1) + aesrndx8(T2) + MOVD H0, curK +octetsFinish: + aesrndx8(K8) + aesrndlastx8(K9) + + VEOR KLAST.B16, B0.B16, T1.B16 + VEOR KLAST.B16, B1.B16, T2.B16 + VEOR KLAST.B16, B2.B16, B2.B16 + VEOR KLAST.B16, B3.B16, B3.B16 + VEOR KLAST.B16, B4.B16, B4.B16 + VEOR KLAST.B16, B5.B16, B5.B16 + VEOR KLAST.B16, B6.B16, B6.B16 + VEOR KLAST.B16, B7.B16, B7.B16 + + VLD1.P 32(srcPtr), [B0.B16, B1.B16] + VEOR B0.B16, T1.B16, T1.B16 + VEOR B1.B16, T2.B16, T2.B16 + VST1.P [T1.B16, T2.B16], 32(dstPtr) + + VLD1.P 32(pTbl), [T1.B16, T2.B16] + VREV64 B0.B16, B0.B16 + VEOR ACC0.B16, B0.B16, B0.B16 + VEXT $8, B0.B16, B0.B16, T0.B16 + VEOR B0.B16, T0.B16, T0.B16 + VPMULL B0.D1, T1.D1, ACC1.Q1 + VPMULL2 B0.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + mulRound(B1) + + VLD1.P 32(srcPtr), [B0.B16, B1.B16] + VEOR B2.B16, B0.B16, T1.B16 + VEOR B3.B16, B1.B16, T2.B16 + VST1.P [T1.B16, T2.B16], 32(dstPtr) + mulRound(B0) + mulRound(B1) + + VLD1.P 32(srcPtr), [B0.B16, B1.B16] + VEOR B4.B16, B0.B16, T1.B16 + VEOR B5.B16, B1.B16, T2.B16 + VST1.P [T1.B16, T2.B16], 32(dstPtr) + mulRound(B0) + mulRound(B1) + + VLD1.P 32(srcPtr), [B0.B16, B1.B16] + VEOR B6.B16, B0.B16, T1.B16 + VEOR B7.B16, B1.B16, T2.B16 + VST1.P [T1.B16, T2.B16], 32(dstPtr) + mulRound(B0) + mulRound(B1) + + MOVD pTblSave, pTbl + reduce() + + CMP $128, srcPtrLen + BGE octetsLoop + +startSingles: + CBZ srcPtrLen, done + ADD $14*16, pTbl + // Preload H and its Karatsuba precomp + VLD1.P (pTbl), [T1.B16, T2.B16] + // Preload AES round keys + ADD $128, ks + VLD1.P 48(ks), [K8.B16, K9.B16, K10.B16] + VMOV K10.B16, KLAST.B16 + TBZ $4, NR, singlesLoop + VLD1.P 32(ks), [B1.B16, B2.B16] + VMOV B2.B16, KLAST.B16 + TBZ $3, NR, singlesLoop + VLD1.P 32(ks), [B3.B16, B4.B16] + VMOV B4.B16, KLAST.B16 + +singlesLoop: + CMP $16, srcPtrLen + BLT tail + SUB $16, srcPtrLen + + VLD1.P 16(srcPtr), [T0.B16] + VREV64 T0.B16, B5.B16 + VEOR KLAST.B16, T0.B16, T0.B16 + + VREV32 CTR.B16, B0.B16 + VADD CTR.S4, INC.S4, CTR.S4 + + AESE K0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K3.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K4.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K5.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K6.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K7.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K8.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K9.B16, B0.B16 + TBZ $4, NR, singlesLast + AESMC B0.B16, B0.B16 + AESE K10.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B1.B16, B0.B16 + TBZ $3, NR, singlesLast + AESMC B0.B16, B0.B16 + AESE B2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B3.B16, B0.B16 +singlesLast: + VEOR T0.B16, B0.B16, B0.B16 + + VST1.P [B0.B16], 16(dstPtr) + + VEOR ACC0.B16, B5.B16, B5.B16 + VEXT $8, B5.B16, B5.B16, T0.B16 + VEOR B5.B16, T0.B16, T0.B16 + VPMULL B5.D1, T1.D1, ACC1.Q1 + VPMULL2 B5.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + reduce() + + B singlesLoop +tail: + CBZ srcPtrLen, done + + VREV32 CTR.B16, B0.B16 + VADD CTR.S4, INC.S4, CTR.S4 + + AESE K0.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K1.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K3.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K4.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K5.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K6.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K7.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K8.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE K9.B16, B0.B16 + TBZ $4, NR, tailLast + AESMC B0.B16, B0.B16 + AESE K10.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B1.B16, B0.B16 + TBZ $3, NR, tailLast + AESMC B0.B16, B0.B16 + AESE B2.B16, B0.B16 + AESMC B0.B16, B0.B16 + AESE B3.B16, B0.B16 +tailLast: + VEOR KLAST.B16, B0.B16, B0.B16 + + // Assuming it is safe to load past dstPtr due to the presence of the tag + VLD1 (srcPtr), [B5.B16] + + VEOR B5.B16, B0.B16, B0.B16 + + VEOR T3.B16, T3.B16, T3.B16 + MOVD $0, H1 + SUB $1, H1 + + TBZ $3, srcPtrLen, ld4 + VMOV B0.D[0], H0 + MOVD.P H0, 8(dstPtr) + VMOV H1, T3.D[0] + VEXT $8, ZERO.B16, B0.B16, B0.B16 +ld4: + TBZ $2, srcPtrLen, ld2 + VMOV B0.S[0], H0 + MOVW.P H0, 4(dstPtr) + VEXT $12, T3.B16, ZERO.B16, T3.B16 + VMOV H1, T3.S[0] + VEXT $4, ZERO.B16, B0.B16, B0.B16 +ld2: + TBZ $1, srcPtrLen, ld1 + VMOV B0.H[0], H0 + MOVH.P H0, 2(dstPtr) + VEXT $14, T3.B16, ZERO.B16, T3.B16 + VMOV H1, T3.H[0] + VEXT $2, ZERO.B16, B0.B16, B0.B16 +ld1: + TBZ $0, srcPtrLen, ld0 + VMOV B0.B[0], H0 + MOVB.P H0, 1(dstPtr) + VEXT $15, T3.B16, ZERO.B16, T3.B16 + VMOV H1, T3.B[0] +ld0: + + VAND T3.B16, B5.B16, B5.B16 + VREV64 B5.B16, B5.B16 + + VEOR ACC0.B16, B5.B16, B5.B16 + VEXT $8, B5.B16, B5.B16, T0.B16 + VEOR B5.B16, T0.B16, T0.B16 + VPMULL B5.D1, T1.D1, ACC1.Q1 + VPMULL2 B5.D2, T1.D2, ACC0.Q1 + VPMULL T0.D1, T2.D1, ACCM.Q1 + reduce() +done: + VST1 [ACC0.B16], (tPtr) + + RET diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go index d154ddbaa0..c58aa2cda8 100644 --- a/src/crypto/aes/gcm_s390x.go +++ b/src/crypto/aes/gcm_s390x.go @@ -8,6 +8,7 @@ import ( "crypto/cipher" subtleoverlap "crypto/internal/subtle" "crypto/subtle" + "encoding/binary" "errors" "internal/cpu" ) @@ -22,35 +23,15 @@ type gcmCount [16]byte // inc increments the rightmost 32-bits of the count value by 1. func (x *gcmCount) inc() { - // The compiler should optimize this to a 32-bit addition. - n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24 - n += 1 - x[12] = byte(n >> 24) - x[13] = byte(n >> 16) - x[14] = byte(n >> 8) - x[15] = byte(n) + binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1) } // gcmLengths writes len0 || len1 as big-endian values to a 16-byte array. func gcmLengths(len0, len1 uint64) [16]byte { - return [16]byte{ - byte(len0 >> 56), - byte(len0 >> 48), - byte(len0 >> 40), - byte(len0 >> 32), - byte(len0 >> 24), - byte(len0 >> 16), - byte(len0 >> 8), - byte(len0), - byte(len1 >> 56), - byte(len1 >> 48), - byte(len1 >> 40), - byte(len1 >> 32), - byte(len1 >> 24), - byte(len1 >> 16), - byte(len1 >> 8), - byte(len1), - } + v := [16]byte{} + binary.BigEndian.PutUint64(v[0:], len0) + binary.BigEndian.PutUint64(v[8:], len1) + return v } // gcmHashKey represents the 16-byte hash key required by the GHASH algorithm. diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go index 6321e9e82d..73d78550f8 100644 --- a/src/crypto/cipher/gcm.go +++ b/src/crypto/cipher/gcm.go @@ -7,6 +7,7 @@ package cipher import ( subtleoverlap "crypto/internal/subtle" "crypto/subtle" + "encoding/binary" "errors" ) @@ -53,8 +54,8 @@ type gcmAble interface { } // gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM -// standard and make getUint64 suitable for marshaling these values, the bits -// are stored backwards. For example: +// standard and make binary.BigEndian suitable for marshaling these values, the +// bits are stored in big endian order. For example: // the coefficient of x⁰ can be obtained by v.low >> 63. // the coefficient of x⁶³ can be obtained by v.low & 1. // the coefficient of x⁶⁴ can be obtained by v.high >> 63. @@ -130,8 +131,8 @@ func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, erro // would expect, say, 4*key to be in index 4 of the table but due to // this bit ordering it will actually be in index 0010 (base 2) = 2. x := gcmFieldElement{ - getUint64(key[:8]), - getUint64(key[8:]), + binary.BigEndian.Uint64(key[:8]), + binary.BigEndian.Uint64(key[8:]), } g.productTable[reverseBits(1)] = x @@ -316,8 +317,8 @@ func (g *gcm) mul(y *gcmFieldElement) { // Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks. func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) { for len(blocks) > 0 { - y.low ^= getUint64(blocks) - y.high ^= getUint64(blocks[8:]) + y.low ^= binary.BigEndian.Uint64(blocks) + y.high ^= binary.BigEndian.Uint64(blocks[8:]) g.mul(y) blocks = blocks[gcmBlockSize:] } @@ -339,12 +340,8 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) { // gcmInc32 treats the final four bytes of counterBlock as a big-endian value // and increments it. func gcmInc32(counterBlock *[16]byte) { - for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- { - counterBlock[i]++ - if counterBlock[i] != 0 { - break - } - } + ctr := counterBlock[len(counterBlock)-4:] + binary.BigEndian.PutUint32(ctr, binary.BigEndian.Uint32(ctr)+1) } // sliceForAppend takes a slice and a requested number of bytes. It returns a @@ -400,8 +397,8 @@ func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { g.update(&y, nonce) y.high ^= uint64(len(nonce)) * 8 g.mul(&y) - putUint64(counter[:8], y.low) - putUint64(counter[8:], y.high) + binary.BigEndian.PutUint64(counter[:8], y.low) + binary.BigEndian.PutUint64(counter[8:], y.high) } } @@ -417,33 +414,8 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize] g.mul(&y) - putUint64(out, y.low) - putUint64(out[8:], y.high) + binary.BigEndian.PutUint64(out, y.low) + binary.BigEndian.PutUint64(out[8:], y.high) xorWords(out, out, tagMask[:]) } - -func getUint64(data []byte) uint64 { - _ = data[7] // bounds check hint to compiler; see golang.org/issue/14808 - r := uint64(data[0])<<56 | - uint64(data[1])<<48 | - uint64(data[2])<<40 | - uint64(data[3])<<32 | - uint64(data[4])<<24 | - uint64(data[5])<<16 | - uint64(data[6])<<8 | - uint64(data[7]) - return r -} - -func putUint64(out []byte, v uint64) { - _ = out[7] // bounds check hint to compiler; see golang.org/issue/14808 - out[0] = byte(v >> 56) - out[1] = byte(v >> 48) - out[2] = byte(v >> 40) - out[3] = byte(v >> 32) - out[4] = byte(v >> 24) - out[5] = byte(v >> 16) - out[6] = byte(v >> 8) - out[7] = byte(v) -} diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go index c48001db28..64d5cc0db4 100644 --- a/src/crypto/cipher/gcm_test.go +++ b/src/crypto/cipher/gcm_test.go @@ -424,7 +424,7 @@ func TestGCMAsm(t *testing.T) { // generate permutations type pair struct{ align, length int } - lengths := []int{0, 8192, 8193, 8208} + lengths := []int{0, 156, 8192, 8193, 8208} keySizes := []int{16, 24, 32} alignments := []int{0, 1, 2, 3} if testing.Short() { diff --git a/src/crypto/ecdsa/example_test.go b/src/crypto/ecdsa/example_test.go new file mode 100644 index 0000000000..bddeab8955 --- /dev/null +++ b/src/crypto/ecdsa/example_test.go @@ -0,0 +1,32 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package ecdsa_test + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/sha256" + "fmt" +) + +func Example() { + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + panic(err) + } + + msg := "hello, world" + hash := sha256.Sum256([]byte(msg)) + + r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:]) + if err != nil { + panic(err) + } + fmt.Printf("signature: (0x%x, 0x%x)\n", r, s) + + valid := ecdsa.Verify(&privateKey.PublicKey, hash[:], r, s) + fmt.Println("signature verified:", valid) +} diff --git a/src/crypto/elliptic/fuzz_test.go b/src/crypto/elliptic/fuzz_test.go new file mode 100644 index 0000000000..10196cf0bc --- /dev/null +++ b/src/crypto/elliptic/fuzz_test.go @@ -0,0 +1,54 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build amd64 arm64 + +package elliptic + +import ( + "crypto/rand" + "testing" + "time" +) + +func TestFuzz(t *testing.T) { + + p256 := P256() + p256Generic := p256.Params() + + var scalar1 [32]byte + var scalar2 [32]byte + var timeout *time.Timer + + if testing.Short() { + timeout = time.NewTimer(500 * time.Millisecond) + } else { + timeout = time.NewTimer(2 * time.Second) + } + + for { + select { + case <-timeout.C: + return + default: + } + + rand.Read(scalar1[:]) + rand.Read(scalar2[:]) + + x, y := p256.ScalarBaseMult(scalar1[:]) + x2, y2 := p256Generic.ScalarBaseMult(scalar1[:]) + + xx, yy := p256.ScalarMult(x, y, scalar2[:]) + xx2, yy2 := p256Generic.ScalarMult(x2, y2, scalar2[:]) + + if x.Cmp(x2) != 0 || y.Cmp(y2) != 0 { + t.Fatalf("ScalarBaseMult does not match reference result with scalar: %x, please report this error to security@golang.org", scalar1) + } + + if xx.Cmp(xx2) != 0 || yy.Cmp(yy2) != 0 { + t.Fatalf("ScalarMult does not match reference result with scalars: %x and %x, please report this error to security@golang.org", scalar1, scalar2) + } + } +} diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go index bb9757355a..80e123a734 100644 --- a/src/crypto/elliptic/p256.go +++ b/src/crypto/elliptic/p256.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64 +// +build !amd64,!arm64 package elliptic diff --git a/src/crypto/elliptic/p256_amd64.go b/src/crypto/elliptic/p256_asm.go similarity index 99% rename from src/crypto/elliptic/p256_amd64.go rename to src/crypto/elliptic/p256_asm.go index 30eb33a0d4..6cf7742e1b 100644 --- a/src/crypto/elliptic/p256_amd64.go +++ b/src/crypto/elliptic/p256_asm.go @@ -10,7 +10,7 @@ // https://link.springer.com/article/10.1007%2Fs13389-014-0090-x // https://eprint.iacr.org/2013/816.pdf -// +build amd64 +// +build amd64 arm64 package elliptic diff --git a/src/crypto/elliptic/p256_asm_arm64.s b/src/crypto/elliptic/p256_asm_arm64.s new file mode 100644 index 0000000000..f571c50342 --- /dev/null +++ b/src/crypto/elliptic/p256_asm_arm64.s @@ -0,0 +1,1529 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains constant-time, 64-bit assembly implementation of +// P256. The optimizations performed here are described in detail in: +// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with +// 256-bit primes" +// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x +// https://eprint.iacr.org/2013/816.pdf + +#include "textflag.h" + +#define res_ptr R0 +#define a_ptr R1 +#define b_ptr R2 + +#define acc0 R3 +#define acc1 R4 +#define acc2 R5 +#define acc3 R6 + +#define acc4 R7 +#define acc5 R8 +#define acc6 R9 +#define acc7 R10 +#define t0 R11 +#define t1 R12 +#define t2 R13 +#define t3 R14 +#define const0 R15 +#define const1 R16 + +#define hlp0 R17 +#define hlp1 res_ptr + +#define x0 R19 +#define x1 R20 +#define x2 R21 +#define x3 R22 +#define y0 R23 +#define y1 R24 +#define y2 R25 +#define y3 R26 + +#define const2 t2 +#define const3 t3 + +DATA p256const0<>+0x00(SB)/8, $0x00000000ffffffff +DATA p256const1<>+0x00(SB)/8, $0xffffffff00000001 +DATA p256ordK0<>+0x00(SB)/8, $0xccd1c8aaee00bc4f +DATA p256ord<>+0x00(SB)/8, $0xf3b9cac2fc632551 +DATA p256ord<>+0x08(SB)/8, $0xbce6faada7179e84 +DATA p256ord<>+0x10(SB)/8, $0xffffffffffffffff +DATA p256ord<>+0x18(SB)/8, $0xffffffff00000000 +DATA p256one<>+0x00(SB)/8, $0x0000000000000001 +DATA p256one<>+0x08(SB)/8, $0xffffffff00000000 +DATA p256one<>+0x10(SB)/8, $0xffffffffffffffff +DATA p256one<>+0x18(SB)/8, $0x00000000fffffffe +GLOBL p256const0<>(SB), 8, $8 +GLOBL p256const1<>(SB), 8, $8 +GLOBL p256ordK0<>(SB), 8, $8 +GLOBL p256ord<>(SB), 8, $32 +GLOBL p256one<>(SB), 8, $32 + +/* ---------------------------------------*/ +// func p256LittleToBig(res []byte, in []uint64) +TEXT ·p256LittleToBig(SB),NOSPLIT,$0 + JMP ·p256BigToLittle(SB) +/* ---------------------------------------*/ +// func p256BigToLittle(res []uint64, in []byte) +TEXT ·p256BigToLittle(SB),NOSPLIT,$0 + MOVD res+0(FP), res_ptr + MOVD in+24(FP), a_ptr + + LDP 0*16(a_ptr), (acc0, acc1) + LDP 1*16(a_ptr), (acc2, acc3) + + REV acc0, acc0 + REV acc1, acc1 + REV acc2, acc2 + REV acc3, acc3 + + STP (acc3, acc2), 0*16(res_ptr) + STP (acc1, acc0), 1*16(res_ptr) + RET +/* ---------------------------------------*/ +// func p256MovCond(res, a, b []uint64, cond int) +// If cond == 0 res=b, else res=a +TEXT ·p256MovCond(SB),NOSPLIT,$0 + MOVD res+0(FP), res_ptr + MOVD a+24(FP), a_ptr + MOVD b+48(FP), b_ptr + MOVD cond+72(FP), R3 + + CMP $0, R3 + // Two remarks: + // 1) Will want to revisit NEON, when support is better + // 2) CSEL might not be constant time on all ARM processors + LDP 0*16(a_ptr), (R4, R5) + LDP 1*16(a_ptr), (R6, R7) + LDP 2*16(a_ptr), (R8, R9) + LDP 0*16(b_ptr), (R16, R17) + LDP 1*16(b_ptr), (R19, R20) + LDP 2*16(b_ptr), (R21, R22) + CSEL EQ, R16, R4, R4 + CSEL EQ, R17, R5, R5 + CSEL EQ, R19, R6, R6 + CSEL EQ, R20, R7, R7 + CSEL EQ, R21, R8, R8 + CSEL EQ, R22, R9, R9 + STP (R4, R5), 0*16(res_ptr) + STP (R6, R7), 1*16(res_ptr) + STP (R8, R9), 2*16(res_ptr) + + LDP 3*16(a_ptr), (R4, R5) + LDP 4*16(a_ptr), (R6, R7) + LDP 5*16(a_ptr), (R8, R9) + LDP 3*16(b_ptr), (R16, R17) + LDP 4*16(b_ptr), (R19, R20) + LDP 5*16(b_ptr), (R21, R22) + CSEL EQ, R16, R4, R4 + CSEL EQ, R17, R5, R5 + CSEL EQ, R19, R6, R6 + CSEL EQ, R20, R7, R7 + CSEL EQ, R21, R8, R8 + CSEL EQ, R22, R9, R9 + STP (R4, R5), 3*16(res_ptr) + STP (R6, R7), 4*16(res_ptr) + STP (R8, R9), 5*16(res_ptr) + + RET +/* ---------------------------------------*/ +// func p256NegCond(val []uint64, cond int) +TEXT ·p256NegCond(SB),NOSPLIT,$0 + MOVD val+0(FP), a_ptr + MOVD cond+24(FP), hlp0 + MOVD a_ptr, res_ptr + // acc = poly + MOVD $-1, acc0 + MOVD p256const0<>(SB), acc1 + MOVD $0, acc2 + MOVD p256const1<>(SB), acc3 + // Load the original value + LDP 0*16(a_ptr), (t0, t1) + LDP 1*16(a_ptr), (t2, t3) + // Speculatively subtract + SUBS t0, acc0 + SBCS t1, acc1 + SBCS t2, acc2 + SBC t3, acc3 + // If condition is 0, keep original value + CMP $0, hlp0 + CSEL EQ, t0, acc0, acc0 + CSEL EQ, t1, acc1, acc1 + CSEL EQ, t2, acc2, acc2 + CSEL EQ, t3, acc3, acc3 + // Store result + STP (acc0, acc1), 0*16(res_ptr) + STP (acc2, acc3), 1*16(res_ptr) + + RET +/* ---------------------------------------*/ +// func p256Sqr(res, in []uint64, n int) +TEXT ·p256Sqr(SB),NOSPLIT,$0 + MOVD res+0(FP), res_ptr + MOVD in+24(FP), a_ptr + MOVD n+48(FP), b_ptr + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + + LDP 0*16(a_ptr), (x0, x1) + LDP 1*16(a_ptr), (x2, x3) + +sqrLoop: + SUB $1, b_ptr + CALL p256SqrInternal<>(SB) + MOVD y0, x0 + MOVD y1, x1 + MOVD y2, x2 + MOVD y3, x3 + CBNZ b_ptr, sqrLoop + + STP (y0, y1), 0*16(res_ptr) + STP (y2, y3), 1*16(res_ptr) + RET +/* ---------------------------------------*/ +// func p256Mul(res, in1, in2 []uint64) +TEXT ·p256Mul(SB),NOSPLIT,$0 + MOVD res+0(FP), res_ptr + MOVD in1+24(FP), a_ptr + MOVD in2+48(FP), b_ptr + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + + LDP 0*16(a_ptr), (x0, x1) + LDP 1*16(a_ptr), (x2, x3) + + LDP 0*16(b_ptr), (y0, y1) + LDP 1*16(b_ptr), (y2, y3) + + CALL p256MulInternal<>(SB) + + STP (y0, y1), 0*16(res_ptr) + STP (y2, y3), 1*16(res_ptr) + RET +/* ---------------------------------------*/ +// func p256FromMont(res, in []uint64) +TEXT ·p256FromMont(SB),NOSPLIT,$0 + MOVD res+0(FP), res_ptr + MOVD in+24(FP), a_ptr + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + + LDP 0*16(a_ptr), (acc0, acc1) + LDP 1*16(a_ptr), (acc2, acc3) + // Only reduce, no multiplications are needed + // First reduction step + ADDS acc0<<32, acc1, acc1 + LSR $32, acc0, t0 + MUL acc0, const1, t1 + UMULH acc0, const1, acc0 + ADCS t0, acc2 + ADCS t1, acc3 + ADC $0, acc0 + // Second reduction step + ADDS acc1<<32, acc2, acc2 + LSR $32, acc1, t0 + MUL acc1, const1, t1 + UMULH acc1, const1, acc1 + ADCS t0, acc3 + ADCS t1, acc0 + ADC $0, acc1 + // Third reduction step + ADDS acc2<<32, acc3, acc3 + LSR $32, acc2, t0 + MUL acc2, const1, t1 + UMULH acc2, const1, acc2 + ADCS t0, acc0 + ADCS t1, acc1 + ADC $0, acc2 + // Last reduction step + ADDS acc3<<32, acc0, acc0 + LSR $32, acc3, t0 + MUL acc3, const1, t1 + UMULH acc3, const1, acc3 + ADCS t0, acc1 + ADCS t1, acc2 + ADC $0, acc3 + + SUBS $-1, acc0, t0 + SBCS const0, acc1, t1 + SBCS $0, acc2, t2 + SBCS const1, acc3, t3 + + CSEL CS, t0, acc0, acc0 + CSEL CS, t1, acc1, acc1 + CSEL CS, t2, acc2, acc2 + CSEL CS, t3, acc3, acc3 + + STP (acc0, acc1), 0*16(res_ptr) + STP (acc2, acc3), 1*16(res_ptr) + + RET +/* ---------------------------------------*/ +// Constant time point access to arbitrary point table. +// Indexed from 1 to 15, with -1 offset +// (index 0 is implicitly point at infinity) +// func p256Select(point, table []uint64, idx int) +TEXT ·p256Select(SB),NOSPLIT,$0 + MOVD idx+48(FP), const0 + MOVD table+24(FP), b_ptr + MOVD point+0(FP), res_ptr + + EOR x0, x0, x0 + EOR x1, x1, x1 + EOR x2, x2, x2 + EOR x3, x3, x3 + EOR y0, y0, y0 + EOR y1, y1, y1 + EOR y2, y2, y2 + EOR y3, y3, y3 + EOR t0, t0, t0 + EOR t1, t1, t1 + EOR t2, t2, t2 + EOR t3, t3, t3 + + MOVD $0, const1 + +loop_select: + ADD $1, const1 + CMP const0, const1 + LDP.P 16(b_ptr), (acc0, acc1) + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + LDP.P 16(b_ptr), (acc2, acc3) + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + LDP.P 16(b_ptr), (acc4, acc5) + CSEL EQ, acc4, y0, y0 + CSEL EQ, acc5, y1, y1 + LDP.P 16(b_ptr), (acc6, acc7) + CSEL EQ, acc6, y2, y2 + CSEL EQ, acc7, y3, y3 + LDP.P 16(b_ptr), (acc0, acc1) + CSEL EQ, acc0, t0, t0 + CSEL EQ, acc1, t1, t1 + LDP.P 16(b_ptr), (acc2, acc3) + CSEL EQ, acc2, t2, t2 + CSEL EQ, acc3, t3, t3 + + CMP $16, const1 + BNE loop_select + + STP (x0, x1), 0*16(res_ptr) + STP (x2, x3), 1*16(res_ptr) + STP (y0, y1), 2*16(res_ptr) + STP (y2, y3), 3*16(res_ptr) + STP (t0, t1), 4*16(res_ptr) + STP (t2, t3), 5*16(res_ptr) + RET +/* ---------------------------------------*/ +// Constant time point access to base point table. +// func p256SelectBase(point, table []uint64, idx int) +TEXT ·p256SelectBase(SB),NOSPLIT,$0 + MOVD idx+48(FP), t0 + MOVD table+24(FP), t1 + MOVD point+0(FP), res_ptr + + EOR x0, x0, x0 + EOR x1, x1, x1 + EOR x2, x2, x2 + EOR x3, x3, x3 + EOR y0, y0, y0 + EOR y1, y1, y1 + EOR y2, y2, y2 + EOR y3, y3, y3 + + MOVD $0, t2 + +loop_select: + ADD $1, t2 + CMP t0, t2 + LDP.P 16(t1), (acc0, acc1) + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + LDP.P 16(t1), (acc2, acc3) + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + LDP.P 16(t1), (acc4, acc5) + CSEL EQ, acc4, y0, y0 + CSEL EQ, acc5, y1, y1 + LDP.P 16(t1), (acc6, acc7) + CSEL EQ, acc6, y2, y2 + CSEL EQ, acc7, y3, y3 + + CMP $32, t2 + BNE loop_select + + STP (x0, x1), 0*16(res_ptr) + STP (x2, x3), 1*16(res_ptr) + STP (y0, y1), 2*16(res_ptr) + STP (y2, y3), 3*16(res_ptr) + RET +/* ---------------------------------------*/ +// func p256OrdSqr(res, in []uint64, n int) +TEXT ·p256OrdSqr(SB),NOSPLIT,$0 + MOVD in+24(FP), a_ptr + MOVD n+48(FP), b_ptr + + MOVD p256ordK0<>(SB), hlp1 + LDP p256ord<>+0x00(SB), (const0, const1) + LDP p256ord<>+0x10(SB), (const2, const3) + + LDP 0*16(a_ptr), (x0, x1) + LDP 1*16(a_ptr), (x2, x3) + +ordSqrLoop: + SUB $1, b_ptr + + // x[1:] * x[0] + MUL x0, x1, acc1 + UMULH x0, x1, acc2 + + MUL x0, x2, t0 + ADDS t0, acc2, acc2 + UMULH x0, x2, acc3 + + MUL x0, x3, t0 + ADCS t0, acc3, acc3 + UMULH x0, x3, acc4 + ADC $0, acc4, acc4 + // x[2:] * x[1] + MUL x1, x2, t0 + ADDS t0, acc3 + UMULH x1, x2, t1 + ADCS t1, acc4 + ADC $0, ZR, acc5 + + MUL x1, x3, t0 + ADDS t0, acc4 + UMULH x1, x3, t1 + ADC t1, acc5 + // x[3] * x[2] + MUL x2, x3, t0 + ADDS t0, acc5 + UMULH x2, x3, acc6 + ADC $0, acc6 + + MOVD $0, acc7 + // *2 + ADDS acc1, acc1 + ADCS acc2, acc2 + ADCS acc3, acc3 + ADCS acc4, acc4 + ADCS acc5, acc5 + ADCS acc6, acc6 + ADC $0, acc7 + // Missing products + MUL x0, x0, acc0 + UMULH x0, x0, t0 + ADDS t0, acc1, acc1 + + MUL x1, x1, t0 + ADCS t0, acc2, acc2 + UMULH x1, x1, t1 + ADCS t1, acc3, acc3 + + MUL x2, x2, t0 + ADCS t0, acc4, acc4 + UMULH x2, x2, t1 + ADCS t1, acc5, acc5 + + MUL x3, x3, t0 + ADCS t0, acc6, acc6 + UMULH x3, x3, t1 + ADC t1, acc7, acc7 + // First reduction step + MUL acc0, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc0, acc0 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc1, acc1 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc2, acc2 + UMULH const2, hlp0, acc0 + + MUL const3, hlp0, t0 + ADCS t0, acc3, acc3 + + UMULH const3, hlp0, hlp0 + ADC $0, hlp0 + + ADDS t1, acc1, acc1 + ADCS y0, acc2, acc2 + ADCS acc0, acc3, acc3 + ADC $0, hlp0, acc0 + // Second reduction step + MUL acc1, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc1, acc1 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc2, acc2 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc3, acc3 + UMULH const2, hlp0, acc1 + + MUL const3, hlp0, t0 + ADCS t0, acc0, acc0 + + UMULH const3, hlp0, hlp0 + ADC $0, hlp0 + + ADDS t1, acc2, acc2 + ADCS y0, acc3, acc3 + ADCS acc1, acc0, acc0 + ADC $0, hlp0, acc1 + // Third reduction step + MUL acc2, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc2, acc2 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc3, acc3 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc0, acc0 + UMULH const2, hlp0, acc2 + + MUL const3, hlp0, t0 + ADCS t0, acc1, acc1 + + UMULH const3, hlp0, hlp0 + ADC $0, hlp0 + + ADDS t1, acc3, acc3 + ADCS y0, acc0, acc0 + ADCS acc2, acc1, acc1 + ADC $0, hlp0, acc2 + + // Last reduction step + MUL acc3, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc3, acc3 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc0, acc0 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc1, acc1 + UMULH const2, hlp0, acc3 + + MUL const3, hlp0, t0 + ADCS t0, acc2, acc2 + + UMULH const3, hlp0, hlp0 + ADC $0, acc7 + + ADDS t1, acc0, acc0 + ADCS y0, acc1, acc1 + ADCS acc3, acc2, acc2 + ADC $0, hlp0, acc3 + + ADDS acc4, acc0, acc0 + ADCS acc5, acc1, acc1 + ADCS acc6, acc2, acc2 + ADCS acc7, acc3, acc3 + ADC $0, ZR, acc4 + + SUBS const0, acc0, y0 + SBCS const1, acc1, y1 + SBCS const2, acc2, y2 + SBCS const3, acc3, y3 + SBCS $0, acc4, acc4 + + CSEL CS, y0, acc0, x0 + CSEL CS, y1, acc1, x1 + CSEL CS, y2, acc2, x2 + CSEL CS, y3, acc3, x3 + + CBNZ b_ptr, ordSqrLoop + + MOVD res+0(FP), res_ptr + STP (x0, x1), 0*16(res_ptr) + STP (x2, x3), 1*16(res_ptr) + + RET +/* ---------------------------------------*/ +// func p256OrdMul(res, in1, in2 []uint64) +TEXT ·p256OrdMul(SB),NOSPLIT,$0 + MOVD in1+24(FP), a_ptr + MOVD in2+48(FP), b_ptr + + MOVD p256ordK0<>(SB), hlp1 + LDP p256ord<>+0x00(SB), (const0, const1) + LDP p256ord<>+0x10(SB), (const2, const3) + + LDP 0*16(a_ptr), (x0, x1) + LDP 1*16(a_ptr), (x2, x3) + LDP 0*16(b_ptr), (y0, y1) + LDP 1*16(b_ptr), (y2, y3) + + // y[0] * x + MUL y0, x0, acc0 + UMULH y0, x0, acc1 + + MUL y0, x1, t0 + ADDS t0, acc1 + UMULH y0, x1, acc2 + + MUL y0, x2, t0 + ADCS t0, acc2 + UMULH y0, x2, acc3 + + MUL y0, x3, t0 + ADCS t0, acc3 + UMULH y0, x3, acc4 + ADC $0, acc4 + // First reduction step + MUL acc0, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc0, acc0 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc1, acc1 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc2, acc2 + UMULH const2, hlp0, acc0 + + MUL const3, hlp0, t0 + ADCS t0, acc3, acc3 + + UMULH const3, hlp0, hlp0 + ADC $0, acc4 + + ADDS t1, acc1, acc1 + ADCS y0, acc2, acc2 + ADCS acc0, acc3, acc3 + ADC $0, hlp0, acc0 + // y[1] * x + MUL y1, x0, t0 + ADDS t0, acc1 + UMULH y1, x0, t1 + + MUL y1, x1, t0 + ADCS t0, acc2 + UMULH y1, x1, hlp0 + + MUL y1, x2, t0 + ADCS t0, acc3 + UMULH y1, x2, y0 + + MUL y1, x3, t0 + ADCS t0, acc4 + UMULH y1, x3, y1 + ADC $0, ZR, acc5 + + ADDS t1, acc2 + ADCS hlp0, acc3 + ADCS y0, acc4 + ADC y1, acc5 + // Second reduction step + MUL acc1, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc1, acc1 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc2, acc2 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc3, acc3 + UMULH const2, hlp0, acc1 + + MUL const3, hlp0, t0 + ADCS t0, acc0, acc0 + + UMULH const3, hlp0, hlp0 + ADC $0, acc5 + + ADDS t1, acc2, acc2 + ADCS y0, acc3, acc3 + ADCS acc1, acc0, acc0 + ADC $0, hlp0, acc1 + // y[2] * x + MUL y2, x0, t0 + ADDS t0, acc2 + UMULH y2, x0, t1 + + MUL y2, x1, t0 + ADCS t0, acc3 + UMULH y2, x1, hlp0 + + MUL y2, x2, t0 + ADCS t0, acc4 + UMULH y2, x2, y0 + + MUL y2, x3, t0 + ADCS t0, acc5 + UMULH y2, x3, y1 + ADC $0, ZR, acc6 + + ADDS t1, acc3 + ADCS hlp0, acc4 + ADCS y0, acc5 + ADC y1, acc6 + // Third reduction step + MUL acc2, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc2, acc2 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc3, acc3 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc0, acc0 + UMULH const2, hlp0, acc2 + + MUL const3, hlp0, t0 + ADCS t0, acc1, acc1 + + UMULH const3, hlp0, hlp0 + ADC $0, acc6 + + ADDS t1, acc3, acc3 + ADCS y0, acc0, acc0 + ADCS acc2, acc1, acc1 + ADC $0, hlp0, acc2 + // y[3] * x + MUL y3, x0, t0 + ADDS t0, acc3 + UMULH y3, x0, t1 + + MUL y3, x1, t0 + ADCS t0, acc4 + UMULH y3, x1, hlp0 + + MUL y3, x2, t0 + ADCS t0, acc5 + UMULH y3, x2, y0 + + MUL y3, x3, t0 + ADCS t0, acc6 + UMULH y3, x3, y1 + ADC $0, ZR, acc7 + + ADDS t1, acc4 + ADCS hlp0, acc5 + ADCS y0, acc6 + ADC y1, acc7 + // Last reduction step + MUL acc3, hlp1, hlp0 + + MUL const0, hlp1, t0 + ADDS t0, acc3, acc3 + UMULH const0, hlp0, t1 + + MUL const1, hlp0, t0 + ADCS t0, acc0, acc0 + UMULH const1, hlp0, y0 + + MUL const2, hlp0, t0 + ADCS t0, acc1, acc1 + UMULH const2, hlp0, acc3 + + MUL const3, hlp0, t0 + ADCS t0, acc2, acc2 + + UMULH const3, hlp0, hlp0 + ADC $0, acc7 + + ADDS t1, acc0, acc0 + ADCS y0, acc1, acc1 + ADCS acc3, acc2, acc2 + ADC $0, hlp0, acc3 + + ADDS acc4, acc0, acc0 + ADCS acc5, acc1, acc1 + ADCS acc6, acc2, acc2 + ADCS acc7, acc3, acc3 + ADC $0, ZR, acc4 + + SUBS const0, acc0, t0 + SBCS const1, acc1, t1 + SBCS const2, acc2, t2 + SBCS const3, acc3, t3 + SBCS $0, acc4, acc4 + + CSEL CS, t0, acc0, acc0 + CSEL CS, t1, acc1, acc1 + CSEL CS, t2, acc2, acc2 + CSEL CS, t3, acc3, acc3 + + MOVD res+0(FP), res_ptr + STP (acc0, acc1), 0*16(res_ptr) + STP (acc2, acc3), 1*16(res_ptr) + + RET +/* ---------------------------------------*/ +TEXT p256SubInternal<>(SB),NOSPLIT,$0 + SUBS x0, y0, acc0 + SBCS x1, y1, acc1 + SBCS x2, y2, acc2 + SBCS x3, y3, acc3 + SBC $0, ZR, t0 + + ADDS $-1, acc0, acc4 + ADCS const0, acc1, acc5 + ADCS $0, acc2, acc6 + ADC const1, acc3, acc7 + + ANDS $1, t0 + CSEL EQ, acc0, acc4, x0 + CSEL EQ, acc1, acc5, x1 + CSEL EQ, acc2, acc6, x2 + CSEL EQ, acc3, acc7, x3 + + RET +/* ---------------------------------------*/ +TEXT p256SqrInternal<>(SB),NOSPLIT,$0 + // x[1:] * x[0] + MUL x0, x1, acc1 + UMULH x0, x1, acc2 + + MUL x0, x2, t0 + ADDS t0, acc2, acc2 + UMULH x0, x2, acc3 + + MUL x0, x3, t0 + ADCS t0, acc3, acc3 + UMULH x0, x3, acc4 + ADC $0, acc4, acc4 + // x[2:] * x[1] + MUL x1, x2, t0 + ADDS t0, acc3 + UMULH x1, x2, t1 + ADCS t1, acc4 + ADC $0, ZR, acc5 + + MUL x1, x3, t0 + ADDS t0, acc4 + UMULH x1, x3, t1 + ADC t1, acc5 + // x[3] * x[2] + MUL x2, x3, t0 + ADDS t0, acc5 + UMULH x2, x3, acc6 + ADC $0, acc6 + + MOVD $0, acc7 + // *2 + ADDS acc1, acc1 + ADCS acc2, acc2 + ADCS acc3, acc3 + ADCS acc4, acc4 + ADCS acc5, acc5 + ADCS acc6, acc6 + ADC $0, acc7 + // Missing products + MUL x0, x0, acc0 + UMULH x0, x0, t0 + ADDS t0, acc1, acc1 + + MUL x1, x1, t0 + ADCS t0, acc2, acc2 + UMULH x1, x1, t1 + ADCS t1, acc3, acc3 + + MUL x2, x2, t0 + ADCS t0, acc4, acc4 + UMULH x2, x2, t1 + ADCS t1, acc5, acc5 + + MUL x3, x3, t0 + ADCS t0, acc6, acc6 + UMULH x3, x3, t1 + ADCS t1, acc7, acc7 + // First reduction step + ADDS acc0<<32, acc1, acc1 + LSR $32, acc0, t0 + MUL acc0, const1, t1 + UMULH acc0, const1, acc0 + ADCS t0, acc2, acc2 + ADCS t1, acc3, acc3 + ADC $0, acc0, acc0 + // Second reduction step + ADDS acc1<<32, acc2, acc2 + LSR $32, acc1, t0 + MUL acc1, const1, t1 + UMULH acc1, const1, acc1 + ADCS t0, acc3, acc3 + ADCS t1, acc0, acc0 + ADC $0, acc1, acc1 + // Third reduction step + ADDS acc2<<32, acc3, acc3 + LSR $32, acc2, t0 + MUL acc2, const1, t1 + UMULH acc2, const1, acc2 + ADCS t0, acc0, acc0 + ADCS t1, acc1, acc1 + ADC $0, acc2, acc2 + // Last reduction step + ADDS acc3<<32, acc0, acc0 + LSR $32, acc3, t0 + MUL acc3, const1, t1 + UMULH acc3, const1, acc3 + ADCS t0, acc1, acc1 + ADCS t1, acc2, acc2 + ADC $0, acc3, acc3 + // Add bits [511:256] of the sqr result + ADDS acc4, acc0, acc0 + ADCS acc5, acc1, acc1 + ADCS acc6, acc2, acc2 + ADCS acc7, acc3, acc3 + ADC $0, ZR, acc4 + + SUBS $-1, acc0, t0 + SBCS const0, acc1, t1 + SBCS $0, acc2, t2 + SBCS const1, acc3, t3 + SBCS $0, acc4, acc4 + + CSEL CS, t0, acc0, y0 + CSEL CS, t1, acc1, y1 + CSEL CS, t2, acc2, y2 + CSEL CS, t3, acc3, y3 + RET +/* ---------------------------------------*/ +TEXT p256MulInternal<>(SB),NOSPLIT,$0 + // y[0] * x + MUL y0, x0, acc0 + UMULH y0, x0, acc1 + + MUL y0, x1, t0 + ADDS t0, acc1 + UMULH y0, x1, acc2 + + MUL y0, x2, t0 + ADCS t0, acc2 + UMULH y0, x2, acc3 + + MUL y0, x3, t0 + ADCS t0, acc3 + UMULH y0, x3, acc4 + ADC $0, acc4 + // First reduction step + ADDS acc0<<32, acc1, acc1 + LSR $32, acc0, t0 + MUL acc0, const1, t1 + UMULH acc0, const1, acc0 + ADCS t0, acc2 + ADCS t1, acc3 + ADC $0, acc0 + // y[1] * x + MUL y1, x0, t0 + ADDS t0, acc1 + UMULH y1, x0, t1 + + MUL y1, x1, t0 + ADCS t0, acc2 + UMULH y1, x1, t2 + + MUL y1, x2, t0 + ADCS t0, acc3 + UMULH y1, x2, t3 + + MUL y1, x3, t0 + ADCS t0, acc4 + UMULH y1, x3, hlp0 + ADC $0, ZR, acc5 + + ADDS t1, acc2 + ADCS t2, acc3 + ADCS t3, acc4 + ADC hlp0, acc5 + // Second reduction step + ADDS acc1<<32, acc2, acc2 + LSR $32, acc1, t0 + MUL acc1, const1, t1 + UMULH acc1, const1, acc1 + ADCS t0, acc3 + ADCS t1, acc0 + ADC $0, acc1 + // y[2] * x + MUL y2, x0, t0 + ADDS t0, acc2 + UMULH y2, x0, t1 + + MUL y2, x1, t0 + ADCS t0, acc3 + UMULH y2, x1, t2 + + MUL y2, x2, t0 + ADCS t0, acc4 + UMULH y2, x2, t3 + + MUL y2, x3, t0 + ADCS t0, acc5 + UMULH y2, x3, hlp0 + ADC $0, ZR, acc6 + + ADDS t1, acc3 + ADCS t2, acc4 + ADCS t3, acc5 + ADC hlp0, acc6 + // Third reduction step + ADDS acc2<<32, acc3, acc3 + LSR $32, acc2, t0 + MUL acc2, const1, t1 + UMULH acc2, const1, acc2 + ADCS t0, acc0 + ADCS t1, acc1 + ADC $0, acc2 + // y[3] * x + MUL y3, x0, t0 + ADDS t0, acc3 + UMULH y3, x0, t1 + + MUL y3, x1, t0 + ADCS t0, acc4 + UMULH y3, x1, t2 + + MUL y3, x2, t0 + ADCS t0, acc5 + UMULH y3, x2, t3 + + MUL y3, x3, t0 + ADCS t0, acc6 + UMULH y3, x3, hlp0 + ADC $0, ZR, acc7 + + ADDS t1, acc4 + ADCS t2, acc5 + ADCS t3, acc6 + ADC hlp0, acc7 + // Last reduction step + ADDS acc3<<32, acc0, acc0 + LSR $32, acc3, t0 + MUL acc3, const1, t1 + UMULH acc3, const1, acc3 + ADCS t0, acc1 + ADCS t1, acc2 + ADC $0, acc3 + // Add bits [511:256] of the mul result + ADDS acc4, acc0, acc0 + ADCS acc5, acc1, acc1 + ADCS acc6, acc2, acc2 + ADCS acc7, acc3, acc3 + ADC $0, ZR, acc4 + + SUBS $-1, acc0, t0 + SBCS const0, acc1, t1 + SBCS $0, acc2, t2 + SBCS const1, acc3, t3 + SBCS $0, acc4, acc4 + + CSEL CS, t0, acc0, y0 + CSEL CS, t1, acc1, y1 + CSEL CS, t2, acc2, y2 + CSEL CS, t3, acc3, y3 + RET +/* ---------------------------------------*/ +#define p256MulBy2Inline \ + ADDS y0, y0, x0; \ + ADCS y1, y1, x1; \ + ADCS y2, y2, x2; \ + ADCS y3, y3, x3; \ + ADC $0, ZR, hlp0; \ + SUBS $-1, x0, t0; \ + SBCS const0, x1, t1;\ + SBCS $0, x2, t2; \ + SBCS const1, x3, t3;\ + SBCS $0, hlp0, hlp0;\ + CSEL CC, x0, t0, x0;\ + CSEL CC, x1, t1, x1;\ + CSEL CC, x2, t2, x2;\ + CSEL CC, x3, t3, x3; +/* ---------------------------------------*/ +#define x1in(off) (off)(a_ptr) +#define y1in(off) (off + 32)(a_ptr) +#define z1in(off) (off + 64)(a_ptr) +#define x2in(off) (off)(b_ptr) +#define z2in(off) (off + 64)(b_ptr) +#define x3out(off) (off)(res_ptr) +#define y3out(off) (off + 32)(res_ptr) +#define z3out(off) (off + 64)(res_ptr) +#define LDx(src) LDP src(0), (x0, x1); LDP src(16), (x2, x3) +#define LDy(src) LDP src(0), (y0, y1); LDP src(16), (y2, y3) +#define STx(src) STP (x0, x1), src(0); STP (x2, x3), src(16) +#define STy(src) STP (y0, y1), src(0); STP (y2, y3), src(16) +/* ---------------------------------------*/ +#define y2in(off) (32*0 + 8 + off)(RSP) +#define s2(off) (32*1 + 8 + off)(RSP) +#define z1sqr(off) (32*2 + 8 + off)(RSP) +#define h(off) (32*3 + 8 + off)(RSP) +#define r(off) (32*4 + 8 + off)(RSP) +#define hsqr(off) (32*5 + 8 + off)(RSP) +#define rsqr(off) (32*6 + 8 + off)(RSP) +#define hcub(off) (32*7 + 8 + off)(RSP) + +#define z2sqr(off) (32*8 + 8 + off)(RSP) +#define s1(off) (32*9 + 8 + off)(RSP) +#define u1(off) (32*10 + 8 + off)(RSP) +#define u2(off) (32*11 + 8 + off)(RSP) + +// func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int) +TEXT ·p256PointAddAffineAsm(SB),0,$264-96 + MOVD in1+24(FP), a_ptr + MOVD in2+48(FP), b_ptr + MOVD sign+72(FP), hlp0 + MOVD sel+80(FP), hlp1 + MOVD zero+88(FP), t2 + + MOVD $1, t0 + CMP $0, t2 + CSEL EQ, ZR, t0, t2 + CMP $0, hlp1 + CSEL EQ, ZR, t0, hlp1 + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + EOR t2<<1, hlp1 + + // Negate y2in based on sign + LDP 2*16(b_ptr), (y0, y1) + LDP 3*16(b_ptr), (y2, y3) + MOVD $-1, acc0 + + SUBS y0, acc0, acc0 + SBCS y1, const0, acc1 + SBCS y2, ZR, acc2 + SBCS y3, const1, acc3 + SBC $0, ZR, t0 + + ADDS $-1, acc0, acc4 + ADCS const0, acc1, acc5 + ADCS $0, acc2, acc6 + ADCS const1, acc3, acc7 + ADC $0, t0, t0 + + CMP $0, t0 + CSEL EQ, acc4, acc0, acc0 + CSEL EQ, acc5, acc1, acc1 + CSEL EQ, acc6, acc2, acc2 + CSEL EQ, acc7, acc3, acc3 + // If condition is 0, keep original value + CMP $0, hlp0 + CSEL EQ, y0, acc0, y0 + CSEL EQ, y1, acc1, y1 + CSEL EQ, y2, acc2, y2 + CSEL EQ, y3, acc3, y3 + // Store result + STy(y2in) + // Begin point add + LDx(z1in) + CALL p256SqrInternal<>(SB) // z1ˆ2 + STy(z1sqr) + + LDx(x2in) + CALL p256MulInternal<>(SB) // x2 * z1ˆ2 + + LDx(x1in) + CALL p256SubInternal<>(SB) // h = u2 - u1 + STx(h) + + LDy(z1in) + CALL p256MulInternal<>(SB) // z3 = h * z1 + + LDP 4*16(a_ptr), (acc0, acc1)// iff select[0] == 0, z3 = z1 + LDP 5*16(a_ptr), (acc2, acc3) + ANDS $1, hlp1, ZR + CSEL EQ, acc0, y0, y0 + CSEL EQ, acc1, y1, y1 + CSEL EQ, acc2, y2, y2 + CSEL EQ, acc3, y3, y3 + LDP p256one<>+0x00(SB), (acc0, acc1) + LDP p256one<>+0x10(SB), (acc2, acc3) + ANDS $2, hlp1, ZR // iff select[1] == 0, z3 = 1 + CSEL EQ, acc0, y0, y0 + CSEL EQ, acc1, y1, y1 + CSEL EQ, acc2, y2, y2 + CSEL EQ, acc3, y3, y3 + LDx(z1in) + MOVD res+0(FP), t0 + STP (y0, y1), 4*16(t0) + STP (y2, y3), 5*16(t0) + + LDy(z1sqr) + CALL p256MulInternal<>(SB) // z1 ^ 3 + + LDx(y2in) + CALL p256MulInternal<>(SB) // s2 = y2 * z1ˆ3 + STy(s2) + + LDx(y1in) + CALL p256SubInternal<>(SB) // r = s2 - s1 + STx(r) + + CALL p256SqrInternal<>(SB) // rsqr = rˆ2 + STy (rsqr) + + LDx(h) + CALL p256SqrInternal<>(SB) // hsqr = hˆ2 + STy(hsqr) + + CALL p256MulInternal<>(SB) // hcub = hˆ3 + STy(hcub) + + LDx(y1in) + CALL p256MulInternal<>(SB) // y1 * hˆ3 + STy(s2) + + LDP hsqr(0*8), (x0, x1) + LDP hsqr(2*8), (x2, x3) + LDP 0*16(a_ptr), (y0, y1) + LDP 1*16(a_ptr), (y2, y3) + CALL p256MulInternal<>(SB) // u1 * hˆ2 + STP (y0, y1), h(0*8) + STP (y2, y3), h(2*8) + + p256MulBy2Inline // u1 * hˆ2 * 2, inline + + LDy(rsqr) + CALL p256SubInternal<>(SB) // rˆ2 - u1 * hˆ2 * 2 + + MOVD x0, y0 + MOVD x1, y1 + MOVD x2, y2 + MOVD x3, y3 + LDx(hcub) + CALL p256SubInternal<>(SB) + + LDP 0*16(a_ptr), (acc0, acc1) + LDP 1*16(a_ptr), (acc2, acc3) + ANDS $1, hlp1, ZR // iff select[0] == 0, x3 = x1 + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + LDP 0*16(b_ptr), (acc0, acc1) + LDP 1*16(b_ptr), (acc2, acc3) + ANDS $2, hlp1, ZR // iff select[1] == 0, x3 = x2 + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + MOVD res+0(FP), t0 + STP (x0, x1), 0*16(t0) + STP (x2, x3), 1*16(t0) + + LDP h(0*8), (y0, y1) + LDP h(2*8), (y2, y3) + CALL p256SubInternal<>(SB) + + LDP r(0*8), (y0, y1) + LDP r(2*8), (y2, y3) + CALL p256MulInternal<>(SB) + + LDP s2(0*8), (x0, x1) + LDP s2(2*8), (x2, x3) + CALL p256SubInternal<>(SB) + LDP 2*16(a_ptr), (acc0, acc1) + LDP 3*16(a_ptr), (acc2, acc3) + ANDS $1, hlp1, ZR // iff select[0] == 0, y3 = y1 + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + LDP y2in(0*8), (acc0, acc1) + LDP y2in(2*8), (acc2, acc3) + ANDS $2, hlp1, ZR // iff select[1] == 0, y3 = y2 + CSEL EQ, acc0, x0, x0 + CSEL EQ, acc1, x1, x1 + CSEL EQ, acc2, x2, x2 + CSEL EQ, acc3, x3, x3 + MOVD res+0(FP), t0 + STP (x0, x1), 2*16(t0) + STP (x2, x3), 3*16(t0) + + RET + +#define p256AddInline \ + ADDS y0, x0, x0; \ + ADCS y1, x1, x1; \ + ADCS y2, x2, x2; \ + ADCS y3, x3, x3; \ + ADC $0, ZR, hlp0; \ + SUBS $-1, x0, t0; \ + SBCS const0, x1, t1;\ + SBCS $0, x2, t2; \ + SBCS const1, x3, t3;\ + SBCS $0, hlp0, hlp0;\ + CSEL CC, x0, t0, x0;\ + CSEL CC, x1, t1, x1;\ + CSEL CC, x2, t2, x2;\ + CSEL CC, x3, t3, x3; + +#define s(off) (32*0 + 8 + off)(RSP) +#define m(off) (32*1 + 8 + off)(RSP) +#define zsqr(off) (32*2 + 8 + off)(RSP) +#define tmp(off) (32*3 + 8 + off)(RSP) + +//func p256PointDoubleAsm(res, in []uint64) +TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$136-48 + MOVD res+0(FP), res_ptr + MOVD in+24(FP), a_ptr + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + + // Begin point double + LDP 4*16(a_ptr), (x0, x1) + LDP 5*16(a_ptr), (x2, x3) + CALL p256SqrInternal<>(SB) + STP (y0, y1), zsqr(0*8) + STP (y2, y3), zsqr(2*8) + + LDP 0*16(a_ptr), (x0, x1) + LDP 1*16(a_ptr), (x2, x3) + p256AddInline + STx(m) + + LDx(z1in) + LDy(y1in) + CALL p256MulInternal<>(SB) + p256MulBy2Inline + STx(z3out) + + LDy(x1in) + LDx(zsqr) + CALL p256SubInternal<>(SB) + LDy(m) + CALL p256MulInternal<>(SB) + + // Multiply by 3 + p256MulBy2Inline + p256AddInline + STx(m) + + LDy(y1in) + p256MulBy2Inline + CALL p256SqrInternal<>(SB) + STy(s) + MOVD y0, x0 + MOVD y1, x1 + MOVD y2, x2 + MOVD y3, x3 + CALL p256SqrInternal<>(SB) + + // Divide by 2 + ADDS $-1, y0, t0 + ADCS const0, y1, t1 + ADCS $0, y2, t2 + ADCS const1, y3, t3 + ADC $0, ZR, hlp0 + + ANDS $1, y0, ZR + CSEL EQ, y0, t0, t0 + CSEL EQ, y1, t1, t1 + CSEL EQ, y2, t2, t2 + CSEL EQ, y3, t3, t3 + AND y0, hlp0, hlp0 + + EXTR $1, t0, t1, y0 + EXTR $1, t1, t2, y1 + EXTR $1, t2, t3, y2 + EXTR $1, t3, hlp0, y3 + STy(y3out) + + LDx(x1in) + LDy(s) + CALL p256MulInternal<>(SB) + STy(s) + p256MulBy2Inline + STx(tmp) + + LDx(m) + CALL p256SqrInternal<>(SB) + LDx(tmp) + CALL p256SubInternal<>(SB) + + STx(x3out) + + LDy(s) + CALL p256SubInternal<>(SB) + + LDy(m) + CALL p256MulInternal<>(SB) + + LDx(y3out) + CALL p256SubInternal<>(SB) + STx(y3out) + RET +/* ---------------------------------------*/ +#undef y2in +#undef x3out +#undef y3out +#undef z3out +#define y2in(off) (off + 32)(b_ptr) +#define x3out(off) (off)(b_ptr) +#define y3out(off) (off + 32)(b_ptr) +#define z3out(off) (off + 64)(b_ptr) +//func p256PointAddAsm(res, in1, in2 []uint64) int +TEXT ·p256PointAddAsm(SB),0,$392-80 + // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl + // Move input to stack in order to free registers + MOVD in1+24(FP), a_ptr + MOVD in2+48(FP), b_ptr + + MOVD p256const0<>(SB), const0 + MOVD p256const1<>(SB), const1 + + // Begin point add + LDx(z2in) + CALL p256SqrInternal<>(SB) // z2^2 + STy(z2sqr) + + CALL p256MulInternal<>(SB) // z2^3 + + LDx(y1in) + CALL p256MulInternal<>(SB) // s1 = z2ˆ3*y1 + STy(s1) + + LDx(z1in) + CALL p256SqrInternal<>(SB) // z1^2 + STy(z1sqr) + + CALL p256MulInternal<>(SB) // z1^3 + + LDx(y2in) + CALL p256MulInternal<>(SB) // s2 = z1ˆ3*y2 + + LDx(s1) + CALL p256SubInternal<>(SB) // r = s2 - s1 + STx(r) + + MOVD $1, t2 + ORR x0, x1, t0 // Check if zero mod p256 + ORR x2, x3, t1 + ORR t1, t0, t0 + CMP $0, t0 + CSEL EQ, t2, ZR, hlp1 + + EOR $-1, x0, t0 + EOR const0, x1, t1 + EOR const1, x3, t3 + + ORR t0, t1, t0 + ORR x2, t3, t1 + ORR t1, t0, t0 + CMP $0, t0 + CSEL EQ, t2, hlp1, hlp1 + + LDx(z2sqr) + LDy(x1in) + CALL p256MulInternal<>(SB) // u1 = x1 * z2ˆ2 + STy(u1) + + LDx(z1sqr) + LDy(x2in) + CALL p256MulInternal<>(SB) // u2 = x2 * z1ˆ2 + STy(u2) + + LDx(u1) + CALL p256SubInternal<>(SB) // h = u2 - u1 + STx(h) + + MOVD $1, t2 + ORR x0, x1, t0 // Check if zero mod p256 + ORR x2, x3, t1 + ORR t1, t0, t0 + CMP $0, t0 + CSEL EQ, t2, ZR, hlp0 + + EOR $-1, x0, t0 + EOR const0, x1, t1 + EOR const1, x3, t3 + + ORR t0, t1, t0 + ORR x2, t3, t1 + ORR t1, t0, t0 + CMP $0, t0 + CSEL EQ, t2, hlp0, hlp0 + + AND hlp0, hlp1, hlp1 + + LDx(r) + CALL p256SqrInternal<>(SB) // rsqr = rˆ2 + STy(rsqr) + + LDx(h) + CALL p256SqrInternal<>(SB) // hsqr = hˆ2 + STy(hsqr) + + LDx(h) + CALL p256MulInternal<>(SB) // hcub = hˆ3 + STy(hcub) + + LDx(s1) + CALL p256MulInternal<>(SB) + STy(s2) + + LDx(z1in) + LDy(z2in) + CALL p256MulInternal<>(SB) // z1 * z2 + LDx(h) + CALL p256MulInternal<>(SB) // z1 * z2 * h + MOVD res+0(FP), b_ptr + STy(z3out) + + LDx(hsqr) + LDy(u1) + CALL p256MulInternal<>(SB) // hˆ2 * u1 + STy(u2) + + p256MulBy2Inline // u1 * hˆ2 * 2, inline + LDy(rsqr) + CALL p256SubInternal<>(SB) // rˆ2 - u1 * hˆ2 * 2 + + MOVD x0, y0 + MOVD x1, y1 + MOVD x2, y2 + MOVD x3, y3 + LDx(hcub) + CALL p256SubInternal<>(SB) + STx(x3out) + + LDy(u2) + CALL p256SubInternal<>(SB) + + LDy(r) + CALL p256MulInternal<>(SB) + + LDx(s2) + CALL p256SubInternal<>(SB) + STx(y3out) + + MOVD hlp1, R0 + MOVD R0, ret+72(FP) + + RET diff --git a/src/crypto/elliptic/p256_generic.go b/src/crypto/elliptic/p256_generic.go index 9963fcafdd..9427331d52 100644 --- a/src/crypto/elliptic/p256_generic.go +++ b/src/crypto/elliptic/p256_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !amd64,!s390x +// +build !amd64,!s390x,!arm64 package elliptic diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go index b8df8a3711..952d20aa16 100644 --- a/src/crypto/rand/rand.go +++ b/src/crypto/rand/rand.go @@ -11,7 +11,7 @@ import "io" // Reader is a global, shared instance of a cryptographically // secure random number generator. // -// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise. +// On Linux and FreeBSD, Reader uses getrandom(2) if available, /dev/urandom otherwise. // On OpenBSD, Reader uses getentropy(2). // On other Unix-like systems, Reader reads from /dev/urandom. // On Windows systems, Reader uses the CryptGenRandom API. diff --git a/src/crypto/rand/rand_batched.go b/src/crypto/rand/rand_batched.go new file mode 100644 index 0000000000..60267fd4bc --- /dev/null +++ b/src/crypto/rand/rand_batched.go @@ -0,0 +1,42 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build linux freebsd + +package rand + +import ( + "internal/syscall/unix" +) + +// maxGetRandomRead is platform dependent. +func init() { + altGetRandom = batched(getRandomBatch, maxGetRandomRead) +} + +// batched returns a function that calls f to populate a []byte by chunking it +// into subslices of, at most, readMax bytes. +func batched(f func([]byte) bool, readMax int) func([]byte) bool { + return func(buf []byte) bool { + for len(buf) > readMax { + if !f(buf[:readMax]) { + return false + } + buf = buf[readMax:] + } + return len(buf) == 0 || f(buf) + } +} + +// If the kernel is too old to support the getrandom syscall(), +// unix.GetRandom will immediately return ENOSYS and we will then fall back to +// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS +// result so we only suffer the syscall overhead once in this case. +// If the kernel supports the getrandom() syscall, unix.GetRandom will block +// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK). +// In this case, unix.GetRandom will not return an error. +func getRandomBatch(p []byte) (ok bool) { + n, err := unix.GetRandom(p, 0) + return n == len(p) && err == nil +} diff --git a/src/crypto/rand/rand_linux_test.go b/src/crypto/rand/rand_batched_test.go similarity index 97% rename from src/crypto/rand/rand_linux_test.go rename to src/crypto/rand/rand_batched_test.go index 77b7b6ebd7..837db83f77 100644 --- a/src/crypto/rand/rand_linux_test.go +++ b/src/crypto/rand/rand_batched_test.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build linux freebsd + package rand import ( diff --git a/src/crypto/rand/rand_freebsd.go b/src/crypto/rand/rand_freebsd.go new file mode 100644 index 0000000000..b4d6653343 --- /dev/null +++ b/src/crypto/rand/rand_freebsd.go @@ -0,0 +1,9 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package rand + +// maxGetRandomRead is the maximum number of bytes to ask for in one call to the +// getrandom() syscall. In FreeBSD at most 256 bytes will be returned per call. +const maxGetRandomRead = (1 << 8) diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go index dbd038cc58..26b93c54d2 100644 --- a/src/crypto/rand/rand_linux.go +++ b/src/crypto/rand/rand_linux.go @@ -4,14 +4,6 @@ package rand -import ( - "internal/syscall/unix" -) - -func init() { - altGetRandom = batched(getRandomLinux, maxGetRandomRead) -} - // maxGetRandomRead is the maximum number of bytes to ask for in one call to the // getrandom() syscall. In linux at most 2^25-1 bytes will be returned per call. // From the manpage @@ -20,29 +12,3 @@ func init() { // is returned by a single call to getrandom() on systems where int // has a size of 32 bits. const maxGetRandomRead = (1 << 25) - 1 - -// batched returns a function that calls f to populate a []byte by chunking it -// into subslices of, at most, readMax bytes. -func batched(f func([]byte) bool, readMax int) func([]byte) bool { - return func(buf []byte) bool { - for len(buf) > readMax { - if !f(buf[:readMax]) { - return false - } - buf = buf[readMax:] - } - return len(buf) == 0 || f(buf) - } -} - -// If the kernel is too old (before 3.17) to support the getrandom syscall(), -// unix.GetRandom will immediately return ENOSYS and we will then fall back to -// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS -// result so we only suffer the syscall overhead once in this case. -// If the kernel supports the getrandom() syscall, unix.GetRandom will block -// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK). -// In this case, unix.GetRandom will not return an error. -func getRandomLinux(p []byte) (ok bool) { - n, err := unix.GetRandom(p, 0) - return n == len(p) && err == nil -} diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go index f7cd74693d..13c874a961 100644 --- a/src/crypto/rand/rand_unix.go +++ b/src/crypto/rand/rand_unix.go @@ -14,6 +14,7 @@ import ( "crypto/aes" "crypto/cipher" "crypto/internal/boring" + "encoding/binary" "io" "os" "runtime" @@ -144,14 +145,7 @@ func (r *reader) Read(b []byte) (n int, err error) { // dst = encrypt(t^seed) // seed = encrypt(t^dst) ns := time.Now().UnixNano() - r.time[0] = byte(ns >> 56) - r.time[1] = byte(ns >> 48) - r.time[2] = byte(ns >> 40) - r.time[3] = byte(ns >> 32) - r.time[4] = byte(ns >> 24) - r.time[5] = byte(ns >> 16) - r.time[6] = byte(ns >> 8) - r.time[7] = byte(ns) + binary.BigEndian.PutUint64(r.time[:], uint64(ns)) r.cipher.Encrypt(r.time[0:], r.time[0:]) for i := 0; i < aes.BlockSize; i++ { r.dst[i] = r.time[i] ^ r.seed[i] diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go index c445bb078f..d5e6ebcd71 100644 --- a/src/crypto/rc4/rc4.go +++ b/src/crypto/rc4/rc4.go @@ -54,12 +54,9 @@ func (c *Cipher) Reset() { c.i, c.j = 0, 0 } -// xorKeyStreamGeneric sets dst to the result of XORing src with the -// key stream. Dst and src must overlap entirely or not at all. -// -// This is the pure Go version. rc4_{amd64,386,arm}* contain assembly -// implementations. This is here for tests and to prevent bitrot. -func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) { +// XORKeyStream sets dst to the result of XORing src with the key stream. +// Dst and src must overlap entirely or not at all. +func (c *Cipher) XORKeyStream(dst, src []byte) { if len(src) == 0 { return } diff --git a/src/crypto/rc4/rc4_386.s b/src/crypto/rc4/rc4_386.s deleted file mode 100644 index 54221036ba..0000000000 --- a/src/crypto/rc4/rc4_386.s +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -#include "textflag.h" - -// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8) -TEXT ·xorKeyStream(SB),NOSPLIT,$0 - MOVL dst+0(FP), DI - MOVL src+4(FP), SI - MOVL state+12(FP), BP - - MOVL i+16(FP), AX - MOVBLZX (AX), AX - MOVL j+20(FP), BX - MOVBLZX (BX), BX - CMPL n+8(FP), $0 - JEQ done - -loop: - // i += 1 - INCB AX - - // j += c.s[i] - MOVBLZX (BP)(AX*4), DX - ADDB DX, BX - MOVBLZX BX, BX - - // c.s[i], c.s[j] = c.s[j], c.s[i] - MOVBLZX (BP)(BX*4), CX - MOVB CX, (BP)(AX*4) - MOVB DX, (BP)(BX*4) - - // *dst = *src ^ c.s[c.s[i]+c.s[j]] - ADDB DX, CX - MOVBLZX CX, CX - MOVB (BP)(CX*4), CX - XORB (SI), CX - MOVBLZX CX, CX - MOVB CX, (DI) - - INCL SI - INCL DI - DECL n+8(FP) - JNE loop - -done: - MOVL i+16(FP), CX - MOVB AX, (CX) - MOVL j+20(FP), CX - MOVB BX, (CX) - - RET diff --git a/src/crypto/rc4/rc4_amd64.s b/src/crypto/rc4/rc4_amd64.s deleted file mode 100644 index 57d941c8f3..0000000000 --- a/src/crypto/rc4/rc4_amd64.s +++ /dev/null @@ -1,179 +0,0 @@ -// Original source: -// http://www.zorinaq.com/papers/rc4-amd64.html -// http://www.zorinaq.com/papers/rc4-amd64.tar.bz2 - -#include "textflag.h" - -// Local modifications: -// -// Transliterated from GNU to 6a assembly syntax by the Go authors. -// The comments and spacing are from the original. -// -// The new EXTEND macros avoid a bad stall on some systems after 8-bit math. -// -// The original code accumulated 64 bits of key stream in an integer -// register and then XOR'ed the key stream into the data 8 bytes at a time. -// Modified to accumulate 128 bits of key stream into an XMM register -// and then XOR the key stream into the data 16 bytes at a time. -// Approximately doubles throughput. - -// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5 -// but makes the code run 2.0x slower on Xeon. -#define EXTEND(r) MOVBLZX r, r - -/* -** RC4 implementation optimized for AMD64. -** -** Author: Marc Bevand -** Licence: I hereby disclaim the copyright on this code and place it -** in the public domain. -** -** The code has been designed to be easily integrated into openssl: -** the exported RC4() function can replace the actual implementations -** openssl already contains. Please note that when linking with openssl, -** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled -** with -DRC4_INT='unsigned long'. -** -** The throughput achieved by this code is about 320 MBytes/sec, on -** a 1.8 GHz AMD Opteron (rev C0) processor. -*/ - -TEXT ·xorKeyStream(SB),NOSPLIT,$0 - MOVQ n+16(FP), BX // rbx = ARG(len) - MOVQ src+8(FP), SI // in = ARG(in) - MOVQ dst+0(FP), DI // out = ARG(out) - MOVQ state+24(FP), BP // d = ARG(data) - MOVQ i+32(FP), AX - MOVBQZX 0(AX), CX // x = *xp - MOVQ j+40(FP), AX - MOVBQZX 0(AX), DX // y = *yp - - LEAQ (SI)(BX*1), R9 // limit = in+len - -l1: CMPQ SI, R9 // cmp in with in+len - JGE finished // jump if (in >= in+len) - - INCB CX - EXTEND(CX) - TESTL $15, CX - JZ wordloop - - MOVBLZX (BP)(CX*4), AX - - ADDB AX, DX // y += tx - EXTEND(DX) - MOVBLZX (BP)(DX*4), BX // ty = d[y] - MOVB BX, (BP)(CX*4) // d[x] = ty - ADDB AX, BX // val = ty+tx - EXTEND(BX) - MOVB AX, (BP)(DX*4) // d[y] = tx - MOVBLZX (BP)(BX*4), R8 // val = d[val] - XORB (SI), R8 // xor 1 byte - MOVB R8, (DI) - INCQ SI // in++ - INCQ DI // out++ - JMP l1 - -wordloop: - SUBQ $16, R9 - CMPQ SI, R9 - JGT end - -start: - ADDQ $16, SI // increment in - ADDQ $16, DI // increment out - - // Each KEYROUND generates one byte of key and - // inserts it into an XMM register at the given 16-bit index. - // The key state array is uint32 words only using the bottom - // byte of each word, so the 16-bit OR only copies 8 useful bits. - // We accumulate alternating bytes into X0 and X1, and then at - // the end we OR X1<<8 into X0 to produce the actual key. - // - // At the beginning of the loop, CX%16 == 0, so the 16 loads - // at state[CX], state[CX+1], ..., state[CX+15] can precompute - // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15], - // without fear of the byte computation CX+15 wrapping around. - // - // The first round needs R12[0], the second needs R12[1], and so on. - // We can avoid memory stalls by starting the load for round n+1 - // before the end of round n, using the LOAD macro. - LEAQ (BP)(CX*4), R12 - -#define KEYROUND(xmm, load, off, r1, r2, index) \ - MOVBLZX (BP)(DX*4), R8; \ - MOVB r1, (BP)(DX*4); \ - load((off+1), r2); \ - MOVB R8, (off*4)(R12); \ - ADDB r1, R8; \ - EXTEND(R8); \ - PINSRW $index, (BP)(R8*4), xmm - -#define LOAD(off, reg) \ - MOVBLZX (off*4)(R12), reg; \ - ADDB reg, DX; \ - EXTEND(DX) - -#define SKIP(off, reg) - - LOAD(0, AX) - KEYROUND(X0, LOAD, 0, AX, BX, 0) - KEYROUND(X1, LOAD, 1, BX, AX, 0) - KEYROUND(X0, LOAD, 2, AX, BX, 1) - KEYROUND(X1, LOAD, 3, BX, AX, 1) - KEYROUND(X0, LOAD, 4, AX, BX, 2) - KEYROUND(X1, LOAD, 5, BX, AX, 2) - KEYROUND(X0, LOAD, 6, AX, BX, 3) - KEYROUND(X1, LOAD, 7, BX, AX, 3) - KEYROUND(X0, LOAD, 8, AX, BX, 4) - KEYROUND(X1, LOAD, 9, BX, AX, 4) - KEYROUND(X0, LOAD, 10, AX, BX, 5) - KEYROUND(X1, LOAD, 11, BX, AX, 5) - KEYROUND(X0, LOAD, 12, AX, BX, 6) - KEYROUND(X1, LOAD, 13, BX, AX, 6) - KEYROUND(X0, LOAD, 14, AX, BX, 7) - KEYROUND(X1, SKIP, 15, BX, AX, 7) - - ADDB $16, CX - - PSLLQ $8, X1 - PXOR X1, X0 - MOVOU -16(SI), X2 - PXOR X0, X2 - MOVOU X2, -16(DI) - - CMPQ SI, R9 // cmp in with in+len-16 - JLE start // jump if (in <= in+len-16) - -end: - DECB CX - ADDQ $16, R9 // tmp = in+len - - // handle the last bytes, one by one -l2: CMPQ SI, R9 // cmp in with in+len - JGE finished // jump if (in >= in+len) - - INCB CX - EXTEND(CX) - MOVBLZX (BP)(CX*4), AX - - ADDB AX, DX // y += tx - EXTEND(DX) - MOVBLZX (BP)(DX*4), BX // ty = d[y] - MOVB BX, (BP)(CX*4) // d[x] = ty - ADDB AX, BX // val = ty+tx - EXTEND(BX) - MOVB AX, (BP)(DX*4) // d[y] = tx - MOVBLZX (BP)(BX*4), R8 // val = d[val] - XORB (SI), R8 // xor 1 byte - MOVB R8, (DI) - INCQ SI // in++ - INCQ DI // out++ - JMP l2 - -finished: - MOVQ j+40(FP), BX - MOVB DX, 0(BX) - MOVQ i+32(FP), AX - MOVB CX, 0(AX) - RET diff --git a/src/crypto/rc4/rc4_amd64p32.s b/src/crypto/rc4/rc4_amd64p32.s deleted file mode 100644 index 970b34e08e..0000000000 --- a/src/crypto/rc4/rc4_amd64p32.s +++ /dev/null @@ -1,192 +0,0 @@ -// Original source: -// http://www.zorinaq.com/papers/rc4-amd64.html -// http://www.zorinaq.com/papers/rc4-amd64.tar.bz2 - -#include "textflag.h" - -// Local modifications: -// -// Transliterated from GNU to 6a assembly syntax by the Go authors. -// The comments and spacing are from the original. -// -// The new EXTEND macros avoid a bad stall on some systems after 8-bit math. -// -// The original code accumulated 64 bits of key stream in an integer -// register and then XOR'ed the key stream into the data 8 bytes at a time. -// Modified to accumulate 128 bits of key stream into an XMM register -// and then XOR the key stream into the data 16 bytes at a time. -// Approximately doubles throughput. -// -// Converted to amd64p32. -// -// To make safe for Native Client, avoid use of BP, R15, -// and two-register addressing modes. - -// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5 -// but makes the code run 2.0x slower on Xeon. -#define EXTEND(r) MOVBLZX r, r - -/* -** RC4 implementation optimized for AMD64. -** -** Author: Marc Bevand -** Licence: I hereby disclaim the copyright on this code and place it -** in the public domain. -** -** The code has been designed to be easily integrated into openssl: -** the exported RC4() function can replace the actual implementations -** openssl already contains. Please note that when linking with openssl, -** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled -** with -DRC4_INT='unsigned long'. -** -** The throughput achieved by this code is about 320 MBytes/sec, on -** a 1.8 GHz AMD Opteron (rev C0) processor. -*/ - -TEXT ·xorKeyStream(SB),NOSPLIT,$0 - MOVL n+8(FP), BX // rbx = ARG(len) - MOVL src+4(FP), SI // in = ARG(in) - MOVL dst+0(FP), DI // out = ARG(out) - MOVL state+12(FP), R10 // d = ARG(data) - MOVL i+16(FP), AX - MOVBQZX 0(AX), CX // x = *xp - MOVL j+20(FP), AX - MOVBQZX 0(AX), DX // y = *yp - - LEAQ (SI)(BX*1), R9 // limit = in+len - -l1: CMPQ SI, R9 // cmp in with in+len - JGE finished // jump if (in >= in+len) - - INCB CX - EXTEND(CX) - TESTL $15, CX - JZ wordloop - LEAL (R10)(CX*4), R12 - - MOVBLZX (R12), AX - - ADDB AX, DX // y += tx - EXTEND(DX) - LEAL (R10)(DX*4), R11 - MOVBLZX (R11), BX // ty = d[y] - MOVB BX, (R12) // d[x] = ty - ADDB AX, BX // val = ty+tx - EXTEND(BX) - LEAL (R10)(BX*4), R13 - MOVB AX, (R11) // d[y] = tx - MOVBLZX (R13), R8 // val = d[val] - XORB (SI), R8 // xor 1 byte - MOVB R8, (DI) - INCQ SI // in++ - INCQ DI // out++ - JMP l1 - -wordloop: - SUBQ $16, R9 - CMPQ SI, R9 - JGT end - -start: - ADDQ $16, SI // increment in - ADDQ $16, DI // increment out - - // Each KEYROUND generates one byte of key and - // inserts it into an XMM register at the given 16-bit index. - // The key state array is uint32 words only using the bottom - // byte of each word, so the 16-bit OR only copies 8 useful bits. - // We accumulate alternating bytes into X0 and X1, and then at - // the end we OR X1<<8 into X0 to produce the actual key. - // - // At the beginning of the loop, CX%16 == 0, so the 16 loads - // at state[CX], state[CX+1], ..., state[CX+15] can precompute - // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15], - // without fear of the byte computation CX+15 wrapping around. - // - // The first round needs R12[0], the second needs R12[1], and so on. - // We can avoid memory stalls by starting the load for round n+1 - // before the end of round n, using the LOAD macro. - LEAQ (R10)(CX*4), R12 - -#define KEYROUND(xmm, load, off, r1, r2, index) \ - LEAL (R10)(DX*4), R11; \ - MOVBLZX (R11), R8; \ - MOVB r1, (R11); \ - load((off+1), r2); \ - MOVB R8, (off*4)(R12); \ - ADDB r1, R8; \ - EXTEND(R8); \ - LEAL (R10)(R8*4), R14; \ - PINSRW $index, (R14), xmm - -#define LOAD(off, reg) \ - MOVBLZX (off*4)(R12), reg; \ - ADDB reg, DX; \ - EXTEND(DX) - -#define SKIP(off, reg) - - LOAD(0, AX) - KEYROUND(X0, LOAD, 0, AX, BX, 0) - KEYROUND(X1, LOAD, 1, BX, AX, 0) - KEYROUND(X0, LOAD, 2, AX, BX, 1) - KEYROUND(X1, LOAD, 3, BX, AX, 1) - KEYROUND(X0, LOAD, 4, AX, BX, 2) - KEYROUND(X1, LOAD, 5, BX, AX, 2) - KEYROUND(X0, LOAD, 6, AX, BX, 3) - KEYROUND(X1, LOAD, 7, BX, AX, 3) - KEYROUND(X0, LOAD, 8, AX, BX, 4) - KEYROUND(X1, LOAD, 9, BX, AX, 4) - KEYROUND(X0, LOAD, 10, AX, BX, 5) - KEYROUND(X1, LOAD, 11, BX, AX, 5) - KEYROUND(X0, LOAD, 12, AX, BX, 6) - KEYROUND(X1, LOAD, 13, BX, AX, 6) - KEYROUND(X0, LOAD, 14, AX, BX, 7) - KEYROUND(X1, SKIP, 15, BX, AX, 7) - - ADDB $16, CX - - PSLLQ $8, X1 - PXOR X1, X0 - MOVOU -16(SI), X2 - PXOR X0, X2 - MOVOU X2, -16(DI) - - CMPQ SI, R9 // cmp in with in+len-16 - JLE start // jump if (in <= in+len-16) - -end: - DECB CX - ADDQ $16, R9 // tmp = in+len - - // handle the last bytes, one by one -l2: CMPQ SI, R9 // cmp in with in+len - JGE finished // jump if (in >= in+len) - - INCB CX - EXTEND(CX) - LEAL (R10)(CX*4), R12 - MOVBLZX (R12), AX - - ADDB AX, DX // y += tx - EXTEND(DX) - LEAL (R10)(DX*4), R11 - MOVBLZX (R11), BX // ty = d[y] - MOVB BX, (R12) // d[x] = ty - ADDB AX, BX // val = ty+tx - EXTEND(BX) - LEAL (R10)(BX*4), R13 - MOVB AX, (R11) // d[y] = tx - MOVBLZX (R13), R8 // val = d[val] - XORB (SI), R8 // xor 1 byte - MOVB R8, (DI) - INCQ SI // in++ - INCQ DI // out++ - JMP l2 - -finished: - MOVL j+20(FP), BX - MOVB DX, 0(BX) - MOVL i+16(FP), AX - MOVB CX, 0(AX) - RET diff --git a/src/crypto/rc4/rc4_arm.s b/src/crypto/rc4/rc4_arm.s deleted file mode 100644 index c726d6d1c0..0000000000 --- a/src/crypto/rc4/rc4_arm.s +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !nacl - -#include "textflag.h" - -// Registers -#define Rdst R0 -#define Rsrc R1 -#define Rn R2 -#define Rstate R3 -#define Rpi R4 -#define Rpj R5 -#define Ri R6 -#define Rj R7 -#define Rk R8 -#define Rt R11 -#define Rt2 R12 - -// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8) -TEXT ·xorKeyStream(SB),NOSPLIT,$0 - MOVW dst+0(FP), Rdst - MOVW src+4(FP), Rsrc - MOVW n+8(FP), Rn - MOVW state+12(FP), Rstate - MOVW i+16(FP), Rpi - MOVW j+20(FP), Rpj - MOVBU (Rpi), Ri - MOVBU (Rpj), Rj - MOVW $0, Rk - -loop: - // i += 1; j += state[i] - ADD $1, Ri - AND $0xff, Ri - MOVBU Ri<<2(Rstate), Rt - ADD Rt, Rj - AND $0xff, Rj - - // swap state[i] <-> state[j] - MOVBU Rj<<2(Rstate), Rt2 - MOVB Rt2, Ri<<2(Rstate) - MOVB Rt, Rj<<2(Rstate) - - // dst[k] = src[k] ^ state[state[i] + state[j]] - ADD Rt2, Rt - AND $0xff, Rt - MOVBU Rt<<2(Rstate), Rt - MOVBU Rk<<0(Rsrc), Rt2 - EOR Rt, Rt2 - MOVB Rt2, Rk<<0(Rdst) - - ADD $1, Rk - CMP Rk, Rn - BNE loop - -done: - MOVB Ri, (Rpi) - MOVB Rj, (Rpj) - RET diff --git a/src/crypto/rc4/rc4_asm.go b/src/crypto/rc4/rc4_asm.go deleted file mode 100644 index fc79e7ffc7..0000000000 --- a/src/crypto/rc4/rc4_asm.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build amd64 amd64p32 arm,!nacl 386 - -package rc4 - -import "crypto/internal/subtle" - -func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) - -// XORKeyStream sets dst to the result of XORing src with the key stream. -// Dst and src must overlap entirely or not at all. -func (c *Cipher) XORKeyStream(dst, src []byte) { - if len(src) == 0 { - return - } - if len(dst) < len(src) { - panic("crypto/cipher: output smaller than input") - } - if subtle.InexactOverlap(dst[:len(src)], src) { - panic("crypto/cipher: invalid buffer overlap") - } - xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j) -} diff --git a/src/crypto/rc4/rc4_ref.go b/src/crypto/rc4/rc4_ref.go deleted file mode 100644 index 9b98fc49e7..0000000000 --- a/src/crypto/rc4/rc4_ref.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !amd64,!amd64p32,!arm,!386 arm,nacl - -package rc4 - -// XORKeyStream sets dst to the result of XORing src with the key stream. -// Dst and src must overlap entirely or not at all. -func (c *Cipher) XORKeyStream(dst, src []byte) { - c.xorKeyStreamGeneric(dst, src) -} diff --git a/src/crypto/rc4/rc4_test.go b/src/crypto/rc4/rc4_test.go index 1fc08b8593..e7356aa45d 100644 --- a/src/crypto/rc4/rc4_test.go +++ b/src/crypto/rc4/rc4_test.go @@ -117,30 +117,19 @@ func TestGolden(t *testing.T) { } func TestBlock(t *testing.T) { - testBlock(t, (*Cipher).XORKeyStream) -} - -// Test the pure Go version. -// Because we have assembly for amd64, 386, and arm, this prevents -// bitrot of the reference implementations. -func TestBlockGeneric(t *testing.T) { - testBlock(t, (*Cipher).xorKeyStreamGeneric) -} - -func testBlock(t *testing.T, xor func(c *Cipher, dst, src []byte)) { c1a, _ := NewCipher(golden[0].key) c1b, _ := NewCipher(golden[1].key) data1 := make([]byte, 1<<20) for i := range data1 { - xor(c1a, data1[i:i+1], data1[i:i+1]) - xor(c1b, data1[i:i+1], data1[i:i+1]) + c1a.XORKeyStream(data1[i:i+1], data1[i:i+1]) + c1b.XORKeyStream(data1[i:i+1], data1[i:i+1]) } c2a, _ := NewCipher(golden[0].key) c2b, _ := NewCipher(golden[1].key) data2 := make([]byte, 1<<20) - xor(c2a, data2, data2) - xor(c2b, data2, data2) + c2a.XORKeyStream(data2, data2) + c2b.XORKeyStream(data2, data2) if !bytes.Equal(data1, data2) { t.Fatalf("bad block") diff --git a/src/crypto/sha1/sha1block_arm64.go b/src/crypto/sha1/sha1block_arm64.go index 173c40fec8..08d3df0000 100644 --- a/src/crypto/sha1/sha1block_arm64.go +++ b/src/crypto/sha1/sha1block_arm64.go @@ -13,13 +13,11 @@ var k = []uint32{ 0xCA62C1D6, } -var hasSHA1 = cpu.ARM64.HasSHA1 - //go:noescape func sha1block(h []uint32, p []byte, k []uint32) func block(dig *digest, p []byte) { - if !hasSHA1 { + if !cpu.ARM64.HasSHA1 { blockGeneric(dig, p) } else { h := dig.h[:] diff --git a/src/crypto/sha256/sha256block_arm64.go b/src/crypto/sha256/sha256block_arm64.go index 75bbcbe0eb..e5da566363 100644 --- a/src/crypto/sha256/sha256block_arm64.go +++ b/src/crypto/sha256/sha256block_arm64.go @@ -8,13 +8,11 @@ import "internal/cpu" var k = _K -var hasSHA2 = cpu.ARM64.HasSHA2 - //go:noescape func sha256block(h []uint32, p []byte, k []uint32) func block(dig *digest, p []byte) { - if !hasSHA2 { + if !cpu.ARM64.HasSHA2 { blockGeneric(dig, p) } else { h := dig.h[:] diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go index 9a63eef571..5a27be2491 100644 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@ -165,11 +165,8 @@ type ConnectionState struct { SignedCertificateTimestamps [][]byte // SCTs from the server, if any OCSPResponse []byte // stapled OCSP response from server, if any - // ExportKeyMaterial returns length bytes of exported key material as - // defined in https://tools.ietf.org/html/rfc5705. If context is nil, it is - // not used as part of the seed. If Config.Renegotiation was set to allow - // renegotiation, this function will always return nil, false. - ExportKeyingMaterial func(label string, context []byte, length int) ([]byte, bool) + // ekm is a closure exposed via ExportKeyingMaterial. + ekm func(label string, context []byte, length int) ([]byte, error) // TLSUnique contains the "tls-unique" channel binding value (see RFC // 5929, section 3). For resumed sessions this value will be nil @@ -180,6 +177,14 @@ type ConnectionState struct { TLSUnique []byte } +// ExportKeyingMaterial returns length bytes of exported key material in a new +// slice as defined in https://tools.ietf.org/html/rfc5705. If context is nil, +// it is not used as part of the seed. If the connection was set to allow +// renegotiation via Config.Renegotiation, this function will return an error. +func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) { + return cs.ekm(label, context, length) +} + // ClientAuthType declares the policy the server will follow for // TLS Client Authentication. type ClientAuthType int @@ -938,12 +943,7 @@ func initDefaultCipherSuites() { // Worst case, these variables will just all be false hasGCMAsmAMD64 := cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ - // TODO: enable the arm64 HasAES && HasPMULL feature check after the - // optimized AES-GCM implementation for arm64 is merged (CL 107298). - // This is explicitly set to false for now to prevent misprioritization - // of AES-GCM based cipher suites, which will be slower than chacha20-poly1305 - hasGCMAsmARM64 := false - // hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL + hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL // Keep in sync with crypto/aes/cipher_s390x.go. hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM) diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go index cdaa7aba97..6e27e695bd 100644 --- a/src/crypto/tls/conn.go +++ b/src/crypto/tls/conn.go @@ -27,15 +27,16 @@ type Conn struct { conn net.Conn isClient bool + // handshakeStatus is 1 if the connection is currently transferring + // application data (i.e. is not currently processing a handshake). + // This field is only to be accessed with sync/atomic. + handshakeStatus uint32 // constant after handshake; protected by handshakeMutex handshakeMutex sync.Mutex handshakeErr error // error resulting from handshake vers uint16 // TLS version haveVers bool // version has been negotiated config *Config // configuration passed to constructor - // handshakeComplete is true if the connection is currently transferring - // application data (i.e. is not currently processing a handshake). - handshakeComplete bool // handshakes counts the number of handshakes performed on the // connection so far. If renegotiation is disabled then this is either // zero or one. @@ -55,7 +56,7 @@ type Conn struct { // renegotiation is not supported in that case.) secureRenegotiation bool // ekm is a closure for exporting keying material. - ekm func(label string, context []byte, length int) ([]byte, bool) + ekm func(label string, context []byte, length int) ([]byte, error) // clientFinishedIsFirst is true if the client sent the first Finished // message during the most recent handshake. This is recorded because @@ -571,12 +572,12 @@ func (c *Conn) readRecord(want recordType) error { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: unknown record type requested")) case recordTypeHandshake, recordTypeChangeCipherSpec: - if c.handshakeComplete { + if c.handshakeComplete() { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake")) } case recordTypeApplicationData: - if !c.handshakeComplete { + if !c.handshakeComplete() { c.sendAlert(alertInternalError) return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake")) } @@ -1048,7 +1049,7 @@ func (c *Conn) Write(b []byte) (int, error) { return 0, err } - if !c.handshakeComplete { + if !c.handshakeComplete() { return 0, alertInternalError } @@ -1114,7 +1115,7 @@ func (c *Conn) handleRenegotiation() error { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() - c.handshakeComplete = false + atomic.StoreUint32(&c.handshakeStatus, 0) if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil { c.handshakes++ } @@ -1215,11 +1216,9 @@ func (c *Conn) Close() error { var alertErr error - c.handshakeMutex.Lock() - if c.handshakeComplete { + if c.handshakeComplete() { alertErr = c.closeNotify() } - c.handshakeMutex.Unlock() if err := c.conn.Close(); err != nil { return err @@ -1233,9 +1232,7 @@ var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake com // called once the handshake has completed and does not call CloseWrite on the // underlying connection. Most callers should just use Close. func (c *Conn) CloseWrite() error { - c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() - if !c.handshakeComplete { + if !c.handshakeComplete() { return errEarlyCloseWrite } @@ -1264,7 +1261,7 @@ func (c *Conn) Handshake() error { if err := c.handshakeErr; err != nil { return err } - if c.handshakeComplete { + if c.handshakeComplete() { return nil } @@ -1284,7 +1281,7 @@ func (c *Conn) Handshake() error { c.flush() } - if c.handshakeErr == nil && !c.handshakeComplete { + if c.handshakeErr == nil && !c.handshakeComplete() { panic("handshake should have had a result.") } @@ -1297,10 +1294,10 @@ func (c *Conn) ConnectionState() ConnectionState { defer c.handshakeMutex.Unlock() var state ConnectionState - state.HandshakeComplete = c.handshakeComplete + state.HandshakeComplete = c.handshakeComplete() state.ServerName = c.serverName - if c.handshakeComplete { + if state.HandshakeComplete { state.Version = c.vers state.NegotiatedProtocol = c.clientProtocol state.DidResume = c.didResume @@ -1318,9 +1315,9 @@ func (c *Conn) ConnectionState() ConnectionState { } } if c.config.Renegotiation != RenegotiateNever { - state.ExportKeyingMaterial = noExportedKeyingMaterial + state.ekm = noExportedKeyingMaterial } else { - state.ExportKeyingMaterial = c.ekm + state.ekm = c.ekm } } @@ -1345,7 +1342,7 @@ func (c *Conn) VerifyHostname(host string) error { if !c.isClient { return errors.New("tls: VerifyHostname called on TLS server connection") } - if !c.handshakeComplete { + if !c.handshakeComplete() { return errors.New("tls: handshake has not yet been performed") } if len(c.verifiedChains) == 0 { @@ -1353,3 +1350,7 @@ func (c *Conn) VerifyHostname(host string) error { } return c.peerCertificates[0].VerifyHostname(host) } + +func (c *Conn) handshakeComplete() bool { + return atomic.LoadUint32(&c.handshakeStatus) == 1 +} diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index b32f240a09..9f5731bb99 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -17,6 +17,7 @@ import ( "net" "strconv" "strings" + "sync/atomic" ) type clientHandshakeState struct { @@ -269,7 +270,7 @@ func (hs *clientHandshakeState) handshake() error { c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random) c.didResume = isResume - c.handshakeComplete = true + atomic.StoreUint32(&c.handshakeStatus, 1) return nil } diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go index 2ab4e474ec..1f1c93d102 100644 --- a/src/crypto/tls/handshake_client_test.go +++ b/src/crypto/tls/handshake_client_test.go @@ -979,6 +979,24 @@ func TestRenegotiateTwiceRejected(t *testing.T) { runClientTestTLS12(t, test) } +func TestHandshakeClientExportKeyingMaterial(t *testing.T) { + test := &clientTest{ + name: "ExportKeyingMaterial", + command: []string{"openssl", "s_server"}, + config: testConfig.Clone(), + validate: func(state ConnectionState) error { + if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil { + return fmt.Errorf("ExportKeyingMaterial failed: %v", err) + } else if len(km) != 42 { + return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42) + } + return nil + }, + } + runClientTestTLS10(t, test) + runClientTestTLS12(t, test) +} + var hostnameInSNITests = []struct { in, out string }{ @@ -1617,3 +1635,22 @@ RwBA9Xk1KBNF t.Error("A RSA-PSS certificate was parsed like a PKCS1 one, and it will be mistakenly used with rsa_pss_rsae_xxx signature algorithms") } } + +func TestCloseClientConnectionOnIdleServer(t *testing.T) { + clientConn, serverConn := net.Pipe() + client := Client(clientConn, testConfig.Clone()) + go func() { + var b [1]byte + serverConn.Read(b[:]) + client.Close() + }() + client.SetWriteDeadline(time.Now().Add(time.Second)) + err := client.Handshake() + if err != nil { + if !strings.Contains(err.Error(), "read/write on closed pipe") { + t.Errorf("Error expected containing 'read/write on closed pipe' but got '%s'", err.Error()) + } + } else { + t.Errorf("Error expected, but no error returned") + } +} diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index c5caab1224..f2ad2262f0 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -13,6 +13,7 @@ import ( "errors" "fmt" "io" + "sync/atomic" ) // serverHandshakeState contains details of a server handshake in progress. @@ -103,7 +104,7 @@ func (c *Conn) serverHandshake() error { } c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random) - c.handshakeComplete = true + atomic.StoreUint32(&c.handshakeStatus, 1) return nil } diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go index 69e6cc9bd6..c366f47b17 100644 --- a/src/crypto/tls/handshake_server_test.go +++ b/src/crypto/tls/handshake_server_test.go @@ -998,6 +998,24 @@ func TestFallbackSCSV(t *testing.T) { runServerTestTLS11(t, test) } +func TestHandshakeServerExportKeyingMaterial(t *testing.T) { + test := &serverTest{ + name: "ExportKeyingMaterial", + command: []string{"openssl", "s_client"}, + config: testConfig.Clone(), + validate: func(state ConnectionState) error { + if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil { + return fmt.Errorf("ExportKeyingMaterial failed: %v", err) + } else if len(km) != 42 { + return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42) + } + return nil + }, + } + runServerTestTLS10(t, test) + runServerTestTLS12(t, test) +} + func benchmarkHandshakeServer(b *testing.B, cipherSuite uint16, curve CurveID, cert []byte, key crypto.PrivateKey) { config := testConfig.Clone() config.CipherSuites = []uint16{cipherSuite} @@ -1403,3 +1421,21 @@ var testECDSAPrivateKey = &ecdsa.PrivateKey{ } var testP256PrivateKey, _ = x509.ParseECPrivateKey(fromHex("30770201010420012f3b52bc54c36ba3577ad45034e2e8efe1e6999851284cb848725cfe029991a00a06082a8648ce3d030107a14403420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75")) + +func TestCloseServerConnectionOnIdleClient(t *testing.T) { + clientConn, serverConn := net.Pipe() + server := Server(serverConn, testConfig.Clone()) + go func() { + clientConn.Write([]byte{'0'}) + server.Close() + }() + server.SetReadDeadline(time.Now().Add(time.Second)) + err := server.Handshake() + if err != nil { + if !strings.Contains(err.Error(), "read/write on closed pipe") { + t.Errorf("Error expected containing 'read/write on closed pipe' but got '%s'", err.Error()) + } + } else { + t.Errorf("Error expected, but no error returned") + } +} diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go index 98e9ab4292..a8cf21da15 100644 --- a/src/crypto/tls/prf.go +++ b/src/crypto/tls/prf.go @@ -347,20 +347,20 @@ func (h *finishedHash) discardHandshakeBuffer() { } // noExportedKeyingMaterial is used as a value of -// ConnectionState.ExportKeyingMaterial when renegotation is enabled and thus +// ConnectionState.ekm when renegotation is enabled and thus // we wish to fail all key-material export requests. -func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, bool) { - return nil, false +func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) { + return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled") } // ekmFromMasterSecret generates exported keying material as defined in // https://tools.ietf.org/html/rfc5705. -func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, bool) { - return func(label string, context []byte, length int) ([]byte, bool) { +func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) { + return func(label string, context []byte, length int) ([]byte, error) { switch label { case "client finished", "server finished", "master secret", "key expansion": // These values are reserved and may not be used. - return nil, false + return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label) } seedLen := len(serverRandom) + len(clientRandom) @@ -374,7 +374,7 @@ func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clien if context != nil { if len(context) >= 1<<16 { - return nil, false + return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long") } seed = append(seed, byte(len(context)>>8), byte(len(context))) seed = append(seed, context...) @@ -382,6 +382,6 @@ func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clien keyMaterial := make([]byte, length) prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed) - return keyMaterial, true + return keyMaterial, nil } } diff --git a/src/crypto/tls/prf_test.go b/src/crypto/tls/prf_test.go index 80af32c6ce..f201253f72 100644 --- a/src/crypto/tls/prf_test.go +++ b/src/crypto/tls/prf_test.go @@ -70,14 +70,14 @@ func TestKeysFromPreMasterSecret(t *testing.T) { } ekm := ekmFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom) - contextKeyingMaterial, ok := ekm("label", []byte("context"), 32) - if !ok { - t.Fatalf("ekmFromMasterSecret failed") + contextKeyingMaterial, err := ekm("label", []byte("context"), 32) + if err != nil { + t.Fatalf("ekmFromMasterSecret failed: %v", err) } - noContextKeyingMaterial, ok := ekm("label", nil, 32) - if !ok { - t.Fatalf("ekmFromMasterSecret failed") + noContextKeyingMaterial, err := ekm("label", nil, 32) + if err != nil { + t.Fatalf("ekmFromMasterSecret failed: %v", err) } if hex.EncodeToString(contextKeyingMaterial) != test.contextKeyingMaterial || diff --git a/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial b/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial new file mode 100644 index 0000000000..571769e125 --- /dev/null +++ b/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial @@ -0,0 +1,89 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| +00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| +00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| +00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| +>>> Flow 2 (server to client) +00000000 16 03 01 00 59 02 00 00 55 03 01 67 4f 02 da 87 |....Y...U..gO...| +00000010 52 30 9a f0 3b e0 63 42 bf 6c 18 58 00 06 70 cf |R0..;.cB.l.X..p.| +00000020 2a 27 5a 00 a7 57 49 fe 03 dd 3b 20 7c 2c 74 00 |*'Z..WI...; |,t.| +00000030 6e b2 35 ca 1b b5 8c 46 f7 78 ab 11 92 43 8c f6 |n.5....F.x...C..| +00000040 97 d3 b8 07 4c 9c 95 2b 08 fe e8 82 c0 13 00 00 |....L..+........| +00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| +00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| +00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| +00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....| +00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...| +000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go| +000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010| +000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100| +000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..| +000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G| +000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F| +00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...| +00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.| +00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...| +00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+| +00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<| +00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]| +00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.| +00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...| +00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....| +000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.| +00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.| +00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@| +00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X| +00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-| +00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....| +00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...| +00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C| +00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| +000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| +000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......| +000002c0 aa 0c 00 00 a6 03 00 1d 20 a0 0e 1d 92 2d b0 a5 |........ ....-..| +000002d0 f0 ab d5 79 a0 bb 12 ff 23 46 bc 27 0d 73 ff 3e |...y....#F.'.s.>| +000002e0 ad 06 d6 57 6b c2 11 76 2d 00 80 77 bf cd 2b cb |...Wk..v-..w..+.| +000002f0 66 c2 fa 30 ed b1 e7 44 79 1b 28 e6 89 62 17 07 |f..0...Dy.(..b..| +00000300 82 c1 5f dc b2 20 4e 42 ed 54 d6 28 3a 2a e3 a3 |.._.. NB.T.(:*..| +00000310 79 06 e3 08 3c c1 3e b9 c6 41 71 2f d0 29 82 36 |y...<.>..Aq/.).6| +00000320 ef 8d 67 c8 77 d0 32 d3 33 5f 77 92 dd 98 bb 03 |..g.w.2.3_w.....| +00000330 cc 0b a6 75 8f 4a 1d f5 6e 1b 06 5b 4a 8b 16 a4 |...u.J..n..[J...| +00000340 c1 ce 11 9d 70 bc 62 7f 58 a5 86 76 91 3d 3a 04 |....p.b.X..v.=:.| +00000350 93 92 89 42 9b a7 7d 9d 75 25 6d 98 f3 e6 68 7e |...B..}.u%m...h~| +00000360 a8 c6 b1 db a7 95 63 39 94 5a 05 16 03 01 00 04 |......c9.Z......| +00000370 0e 00 00 00 |....| +>>> Flow 3 (client to server) +00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| +00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| +00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......| +00000030 16 03 01 00 30 73 ad 46 66 66 e8 bd 44 e4 bf 71 |....0s.Fff..D..q| +00000040 a2 d4 87 e2 4b a3 4a b2 a0 ca ed ac 61 8c 1e 7f |....K.J.....a...| +00000050 68 bf 6f 98 b1 fb 10 1a 5a e6 36 61 91 ac c4 55 |h.o.....Z.6a...U| +00000060 a3 4d 69 66 6e |.Mifn| +>>> Flow 4 (server to client) +00000000 14 03 01 00 01 01 16 03 01 00 30 57 aa 5c d5 dc |..........0W.\..| +00000010 83 4b 23 80 34 4e 36 e8 d6 f3 40 7e ae 12 44 a6 |.K#.4N6...@~..D.| +00000020 c7 48 99 99 0a 85 3c 59 75 32 4e 88 3c 98 a0 23 |.H....>> Flow 5 (client to server) +00000000 17 03 01 00 20 e4 9c f4 fa 6b e8 85 87 6f 20 45 |.... ....k...o E| +00000010 71 d3 e2 9e e3 14 2a 7c 64 e8 11 53 fd 93 c1 4a |q.....*|d..S...J| +00000020 1b 94 f8 48 78 17 03 01 00 20 b9 41 32 1d e8 70 |...Hx.... .A2..p| +00000030 87 5f 2c c6 67 d1 77 3c 30 83 0c 66 35 eb 1d da |._,.g.w<0..f5...| +00000040 6e dd 30 ff 82 05 5f f1 cd e7 15 03 01 00 20 6c |n.0..._....... l| +00000050 47 82 5e 90 5b 84 15 78 05 bd 48 63 d5 46 2f 7e |G.^.[..x..Hc.F/~| +00000060 83 49 ce 3c 0f 04 92 52 5b e7 d5 cf 2c bf 65 |.I.<...R[...,.e| diff --git a/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial b/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial new file mode 100644 index 0000000000..29964f0d40 --- /dev/null +++ b/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial @@ -0,0 +1,84 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 95 01 00 00 91 03 03 00 00 00 00 00 |................| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2c cc a8 |.............,..| +00000030 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#| +00000040 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5| +00000050 c0 12 00 0a 00 05 c0 11 c0 07 01 00 00 3c 00 05 |.............<..| +00000060 00 05 01 00 00 00 00 00 0a 00 0a 00 08 00 1d 00 |................| +00000070 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 12 00 |................| +00000080 10 04 01 04 03 05 01 05 03 06 01 06 03 02 01 02 |................| +00000090 03 ff 01 00 01 00 00 12 00 00 |..........| +>>> Flow 2 (server to client) +00000000 16 03 03 00 59 02 00 00 55 03 03 fc 37 e8 a4 e3 |....Y...U...7...| +00000010 5d da a5 95 0b fb e0 c3 d9 78 8b 91 bd 5c 1c b1 |]........x...\..| +00000020 c6 8d 69 62 f9 c6 0f 12 da 46 ba 20 34 a3 22 f2 |..ib.....F. 4.".| +00000030 a9 f7 da 3a c4 5f 6f f7 4b be df 03 e5 b6 d0 ff |...:._o.K.......| +00000040 ca 54 68 59 57 53 63 a5 2f 91 1d 1e cc a8 00 00 |.ThYWSc./.......| +00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| +00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..| +00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............| +00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....| +00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...| +000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go| +000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010| +000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100| +000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..| +000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G| +000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F| +00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...| +00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.| +00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...| +00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+| +00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<| +00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]| +00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.| +00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...| +00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....| +000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.| +00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.| +00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@| +00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X| +00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-| +00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....| +00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...| +00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C| +00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.| +000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..| +000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......| +000002c0 ac 0c 00 00 a8 03 00 1d 20 cc e9 71 f5 36 52 5a |........ ..q.6RZ| +000002d0 d8 19 ce e4 0d 41 8d a6 9b f3 19 56 8d 81 fe 84 |.....A.....V....| +000002e0 71 2f d7 fb e7 86 23 4c 04 04 01 00 80 90 da 29 |q/....#L.......)| +000002f0 79 18 70 e8 81 66 83 70 97 f1 d1 5f dc 1d a2 0a |y.p..f.p..._....| +00000300 94 d8 e8 b8 32 4f 03 34 0b af e8 2d 94 b2 eb 30 |....2O.4...-...0| +00000310 57 b5 a5 92 9e 9a df a6 bc 3e 25 0e 18 cb ea 84 |W........>%.....| +00000320 34 89 08 8a d4 be 16 a3 5d 3a 7d 32 10 9b 41 1c |4.......]:}2..A.| +00000330 2a 1e 05 68 5f fa d9 56 30 b6 44 08 b0 a5 25 5a |*..h_..V0.D...%Z| +00000340 c3 60 c0 9a 98 fd 48 5f a4 18 d0 15 0f fb b3 ea |.`....H_........| +00000350 b9 c4 e3 c6 0c 27 51 64 01 de 65 78 c7 a0 57 df |.....'Qd..ex..W.| +00000360 9b de 2f 74 bc 72 e5 e0 57 7c 59 e6 ae 16 03 03 |../t.r..W|Y.....| +00000370 00 04 0e 00 00 00 |......| +>>> Flow 3 (client to server) +00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.| +00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....| +00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......| +00000030 16 03 03 00 20 92 0a 4e aa 2d b3 9b c8 b9 80 28 |.... ..N.-.....(| +00000040 f3 22 e2 57 15 ff a1 9a 33 9b e8 4c 5c dc f4 29 |.".W....3..L\..)| +00000050 7d 25 d7 df bc |}%...| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 20 91 85 06 0e 00 |.......... .....| +00000010 ad 96 2e 1c a5 4d f7 63 f9 84 1c 6e da 54 0b e0 |.....M.c...n.T..| +00000020 44 37 6a 90 4c fd f5 e8 45 1d ce |D7j.L...E..| +>>> Flow 5 (client to server) +00000000 17 03 03 00 16 4c e8 8a e0 a6 95 f3 df 37 8a 2d |.....L.......7.-| +00000010 4f 11 ce a6 53 16 2c b0 bb c5 7f 15 03 03 00 12 |O...S.,.........| +00000020 4e 91 d8 67 c5 16 d2 4e cc b8 0a 00 76 91 68 7a |N..g...N....v.hz| +00000030 85 2e |..| diff --git a/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial new file mode 100644 index 0000000000..84e0e37005 --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial @@ -0,0 +1,92 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 61 01 00 00 5d 03 01 f4 ec 99 73 ec |....a...].....s.| +00000010 36 30 c7 0b 26 33 a2 c4 26 8e 9f 04 f7 5b e7 4f |60..&3..&....[.O| +00000020 86 85 14 bf f7 49 96 a4 ae c9 1d 00 00 12 c0 0a |.....I..........| +00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..| +00000040 01 00 00 22 00 0b 00 04 03 00 01 02 00 0a 00 0a |..."............| +00000050 00 08 00 1d 00 17 00 19 00 18 00 23 00 00 00 16 |...........#....| +00000060 00 00 00 17 00 00 |......| +>>> Flow 2 (server to client) +00000000 16 03 01 00 35 02 00 00 31 03 01 00 00 00 00 00 |....5...1.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 01 02 59 0b |..#...........Y.| +00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..| +00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.| +00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| +00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1| +00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| +00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000| +000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| +000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go| +000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..| +000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........| +000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...| +000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R| +00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....| +00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.| +00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..| +00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.| +00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.| +00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C| +00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......| +00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......| +00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.| +00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...| +000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......| +000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........| +000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..| +000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~| +000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.| +000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g| +00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....| +00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.| +00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.| +00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....| +00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ | +00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\| +00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...| +00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.| +00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`| +00000290 84 5c 21 d3 3b e9 fa e7 16 03 01 00 aa 0c 00 00 |.\!.;...........| +000002a0 a6 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.| +000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........| +000002c0 5f 58 cb 3b 74 00 80 8e fe 28 f2 06 d8 b9 d6 74 |_X.;t....(.....t| +000002d0 72 34 dc fa 00 38 56 1a fc a1 68 e8 ca 8f 7a 61 |r4...8V...h...za| +000002e0 92 e2 2a 63 ce 4d 96 c6 bb 84 82 41 2d 97 35 13 |..*c.M.....A-.5.| +000002f0 e1 ff 4c ec f2 e6 62 16 15 35 da 8a 57 55 cb 28 |..L...b..5..WU.(| +00000300 26 35 e6 86 00 b0 92 44 b7 40 7b 6a c4 b0 b8 10 |&5.....D.@{j....| +00000310 b7 16 97 a7 26 eb 1e 0b 99 b3 22 4a 6b 7f 0b 69 |....&....."Jk..i| +00000320 0d 21 1e 33 6d fd 78 b5 62 68 53 db 62 69 ba b4 |.!.3m.x.bhS.bi..| +00000330 bc 74 b3 d4 ce a2 41 d7 ba 62 aa cc b2 39 65 86 |.t....A..b...9e.| +00000340 5f 00 68 e2 16 a5 13 16 03 01 00 04 0e 00 00 00 |_.h.............| +>>> Flow 3 (client to server) +00000000 16 03 01 00 25 10 00 00 21 20 81 08 e4 37 1d 03 |....%...! ...7..| +00000010 87 5a 00 68 ae 49 76 08 4a e2 20 82 0b e5 7c 3e |.Z.h.Iv.J. ...|>| +00000020 90 49 9b c3 b9 c7 c9 3c 29 24 14 03 01 00 01 01 |.I.....<)$......| +00000030 16 03 01 00 30 33 07 d5 08 ca ae f9 70 50 93 0a |....03......pP..| +00000040 55 2e e0 df 1d 88 ae 1e 06 17 47 64 a3 52 36 37 |U.........Gd.R67| +00000050 d5 ca f1 b1 d2 76 7b f8 89 59 13 e9 ab b1 cb dc |.....v{..Y......| +00000060 1f a8 89 f4 2f |..../| +>>> Flow 4 (server to client) +00000000 16 03 01 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6d ec a4 83 61 a4 a1 9c 14 de f8 59 c8 c7 f0 10 |m...a......Y....| +00000040 08 fe c9 37 29 ed 47 05 d2 bd a8 4c 05 b9 8c f8 |...7).G....L....| +00000050 b5 4d e4 a6 30 0f 49 4a b1 73 1f 89 73 c8 bb 36 |.M..0.IJ.s..s..6| +00000060 14 9d d2 95 70 33 94 fb 82 e6 fe 3e 64 8c 9d e8 |....p3.....>d...| +00000070 e3 e5 93 3d fe 4e 23 a3 97 8a a3 91 80 c9 00 01 |...=.N#.........| +00000080 a6 f0 47 cf 11 a6 90 14 03 01 00 01 01 16 03 01 |..G.............| +00000090 00 30 1f 70 17 a1 30 82 5a 32 e7 aa a1 7f 1b f6 |.0.p..0.Z2......| +000000a0 d8 aa 6a 51 64 1b 4a f1 94 12 08 2f 5d 95 fe 83 |..jQd.J..../]...| +000000b0 52 c8 3b d4 58 73 50 19 b8 08 61 b3 3a 5d f6 d3 |R.;.XsP...a.:]..| +000000c0 67 e6 17 03 01 00 20 bd 79 44 08 9d 86 cf 5e e9 |g..... .yD....^.| +000000d0 e4 3c 80 ed b7 18 10 07 0f 42 85 ca a4 51 fd 9b |.<.......B...Q..| +000000e0 38 3e 04 7e 72 6e 80 17 03 01 00 30 2c 46 c2 71 |8>.~rn.....0,F.q| +000000f0 4a 83 46 eb 63 87 f5 83 b4 72 70 4f a3 59 b3 ff |J.F.c....rpO.Y..| +00000100 3c 00 74 12 db 33 51 4c 7c e0 c1 27 44 20 68 25 |<.t..3QL|..'D h%| +00000110 95 f1 37 2a 24 f1 85 a3 5a e4 50 fe 15 03 01 00 |..7*$...Z.P.....| +00000120 20 72 01 cc 74 d5 b4 6b 05 ce de f0 b4 fe 4f 6b | r..t..k......Ok| +00000130 a8 8f ad 5a c2 7d 40 65 d6 a2 57 52 b8 8a c5 4f |...Z.}@e..WR...O| +00000140 d9 |.| diff --git a/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial new file mode 100644 index 0000000000..6415c42928 --- /dev/null +++ b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial @@ -0,0 +1,92 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 ab 01 00 00 a7 03 03 7a 49 9d 20 62 |...........zI. b| +00000010 45 8d 0c 1e 8e eb b1 5e 73 62 6d 48 61 31 cb 1a |E......^sbmHa1..| +00000020 89 b2 68 1b 2c cb 35 87 2a 17 fb 00 00 38 c0 2c |..h.,.5.*....8.,| +00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..| +00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....| +00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<| +00000060 00 35 00 2f 00 ff 01 00 00 46 00 0b 00 04 03 00 |.5./.....F......| +00000070 01 02 00 0a 00 0a 00 08 00 1d 00 17 00 19 00 18 |................| +00000080 00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 20 |.#............. | +00000090 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| +000000a0 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................| +>>> Flow 2 (server to client) +00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.| +00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..| +00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.| +00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| +00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1| +00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo| +00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000| +000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000| +000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go| +000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..| +000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........| +000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...| +000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R| +00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....| +00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.| +00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..| +00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.| +00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.| +00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C| +00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......| +00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......| +00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.| +00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...| +000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......| +000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........| +000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..| +000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~| +000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.| +000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g| +00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....| +00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.| +00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.| +00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....| +00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ | +00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\| +00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...| +00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.| +00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`| +00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 00 |.\!.;...........| +000002a0 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 28 da |.... /.}.G.bC.(.| +000002b0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........| +000002c0 5f 58 cb 3b 74 06 01 00 80 7f ee dd 6b 38 23 29 |_X.;t.......k8#)| +000002d0 56 ff d2 c2 08 86 52 b6 e3 8a d5 fe 47 79 5e ef |V.....R.....Gy^.| +000002e0 99 7a 0b d7 44 84 b9 2f 7a 2c 64 4f b3 7c aa 44 |.z..D../z,dO.|.D| +000002f0 aa 38 5d 1b 69 16 9f f2 7d f8 24 43 47 ad 31 bc |.8].i...}.$CG.1.| +00000300 f5 3d b8 c8 33 6e 3f 6f 2b ea 19 a2 30 32 2b 2a |.=..3n?o+...02+*| +00000310 81 64 3c ee ed 78 4c fa 80 fd e7 5f ef 85 98 d4 |.d<..xL...._....| +00000320 48 06 b8 f5 5e 1e e6 f3 42 a8 2f 99 5f ea b3 ba |H...^...B./._...| +00000330 8e a8 31 99 85 f2 46 11 a3 d2 c6 81 4b f1 22 7d |..1...F.....K."}| +00000340 d7 45 04 f1 a6 d6 7e 8f 9d 16 03 03 00 04 0e 00 |.E....~.........| +00000350 00 00 |..| +>>> Flow 3 (client to server) +00000000 16 03 03 00 25 10 00 00 21 20 22 e7 e7 61 a9 27 |....%...! "..a.'| +00000010 7b 93 d1 42 76 dd 16 32 e8 92 37 37 2f fd 0d 92 |{..Bv..2..77/...| +00000020 1f 8e b7 c5 69 40 d3 1a 7d 06 14 03 03 00 01 01 |....i@..}.......| +00000030 16 03 03 00 28 4e 7f b2 a2 20 5d cf a1 5a de 42 |....(N... ]..Z.B| +00000040 c5 72 c3 ef c3 23 a7 2c f3 5b 3d a4 81 21 ac db |.r...#.,.[=..!..| +00000050 44 1c f3 a1 83 aa a1 b7 85 9a c7 23 03 |D..........#.| +>>> Flow 4 (server to client) +00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f ec 80 83 61 3f 55 e3 9d ab 39 87 5b d0 ba 44 |o...a?U...9.[..D| +00000040 07 91 a8 d0 37 8a 7e 51 0d 00 97 ec 1b 61 f3 3b |....7.~Q.....a.;| +00000050 9f 29 24 d5 98 f7 4d 3b 80 ef 2f 4d aa 02 98 93 |.)$...M;../M....| +00000060 81 03 87 d8 06 33 94 f5 ed 5d cc 8f 57 97 70 26 |.....3...]..W.p&| +00000070 00 dc 0d d2 96 16 a2 6d fc be 8d 4b fa 5f b3 04 |.......m...K._..| +00000080 ce bb 48 ee c0 75 23 14 03 03 00 01 01 16 03 03 |..H..u#.........| +00000090 00 28 00 00 00 00 00 00 00 00 3a 69 e0 40 e2 d1 |.(........:i.@..| +000000a0 a6 96 33 0f b3 58 5a dc 41 ea d1 80 44 66 9f 2e |..3..XZ.A...Df..| +000000b0 00 e4 9e 10 13 56 b4 1b c9 42 17 03 03 00 25 00 |.....V...B....%.| +000000c0 00 00 00 00 00 00 01 88 f3 d9 5b ed 6b 3c 70 0c |..........[.k 0 { t.Errorf("#%d: unexpectedly succeeded against OpenSSL", i) @@ -1912,7 +1993,7 @@ func TestConstraintCases(t *testing.T) { if _, ok := err.(*exec.ExitError); !ok { t.Errorf("#%d: OpenSSL failed to run: %s", i, err) } else if len(test.expectedError) == 0 { - t.Errorf("#%d: OpenSSL unexpectedly failed: %q", i, output) + t.Errorf("#%d: OpenSSL unexpectedly failed: %v", i, output) if debugOpenSSLFailure { return } @@ -1920,6 +2001,7 @@ func TestConstraintCases(t *testing.T) { } } + ignoreCN = test.ignoreCN verifyOpts := VerifyOptions{ Roots: rootPool, Intermediates: intermediatePool, @@ -1949,7 +2031,7 @@ func TestConstraintCases(t *testing.T) { certAsPEM := func(cert *Certificate) string { var buf bytes.Buffer pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) - return string(buf.Bytes()) + return buf.String() } t.Errorf("#%d: root:\n%s", i, certAsPEM(rootPool.certs[0])) t.Errorf("#%d: leaf:\n%s", i, certAsPEM(leafCert)) @@ -2012,7 +2094,7 @@ func testChainAgainstOpenSSL(leaf *Certificate, intermediates, roots *CertPool) cmd.Stderr = &output err := cmd.Run() - return string(output.Bytes()), err + return output.String(), err } var rfc2821Tests = []struct { diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go index 2784ce2f0f..68300c7955 100644 --- a/src/crypto/x509/root_darwin_test.go +++ b/src/crypto/x509/root_darwin_test.go @@ -16,6 +16,11 @@ func TestSystemRoots(t *testing.T) { t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH) } + switch runtime.GOOS { + case "darwin": + t.Skipf("skipping on %s/%s until golang.org/issue/24652 has been resolved.", runtime.GOOS, runtime.GOARCH) + } + t0 := time.Now() sysRoots := systemRootsPool() // actual system roots sysRootsDuration := time.Since(t0) diff --git a/src/crypto/x509/sha2_windows_test.go b/src/crypto/x509/sha2_windows_test.go deleted file mode 100644 index 620b7b9e77..0000000000 --- a/src/crypto/x509/sha2_windows_test.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package x509 - -import "syscall" - -func init() { - v, err := syscall.GetVersion() - if err != nil { - return - } - if major := byte(v); major < 6 { - // Windows XP SP2 and Windows 2003 do not support SHA2. - // https://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx - supportSHA2 = false - } -} diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go index f5bb8592f2..94b68a4607 100644 --- a/src/crypto/x509/verify.go +++ b/src/crypto/x509/verify.go @@ -6,19 +6,21 @@ package x509 import ( "bytes" - "encoding/asn1" "errors" "fmt" "net" "net/url" + "os" "reflect" "runtime" - "strconv" "strings" "time" "unicode/utf8" ) +// ignoreCN disables interpreting Common Name as a hostname. See issue 24151. +var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1") + type InvalidReason int const ( @@ -43,7 +45,12 @@ const ( NameMismatch // NameConstraintsWithoutSANs results when a leaf certificate doesn't // contain a Subject Alternative Name extension, but a CA certificate - // contains name constraints. + // contains name constraints, and the Common Name can be interpreted as + // a hostname. + // + // You can avoid this error by setting the experimental GODEBUG environment + // variable to "x509ignoreCN=1", disabling Common Name matching entirely. + // This behavior might become the default in the future. NameConstraintsWithoutSANs // UnconstrainedName results when a CA certificate contains permitted // name constraints, but leaf certificate contains a name of an @@ -102,6 +109,12 @@ type HostnameError struct { func (h HostnameError) Error() string { c := h.Certificate + if !c.hasSANExtension() && !validHostname(c.Subject.CommonName) && + matchHostnames(toLowerCaseASCII(c.Subject.CommonName), toLowerCaseASCII(h.Host)) { + // This would have validated, if it weren't for the validHostname check on Common Name. + return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName + } + var valid string if ip := net.ParseIP(h.Host); ip != nil { // Trying to validate an IP @@ -115,10 +128,10 @@ func (h HostnameError) Error() string { valid += san.String() } } else { - if c.hasSANExtension() { - valid = strings.Join(c.DNSNames, ", ") - } else { + if c.commonNameAsHostname() { valid = c.Subject.CommonName + } else { + valid = strings.Join(c.DNSNames, ", ") } } @@ -588,17 +601,16 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V leaf = currentChain[0] } - if (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() { - sanExtension, ok := leaf.getSANExtension() - if !ok { - // This is the deprecated, legacy case of depending on - // the CN as a hostname. Chains modern enough to be - // using name constraints should not be depending on - // CNs. - return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""} - } - - err := forEachSAN(sanExtension, func(tag int, data []byte) error { + checkNameConstraints := (certType == intermediateCertificate || certType == rootCertificate) && c.hasNameConstraints() + if checkNameConstraints && leaf.commonNameAsHostname() { + // This is the deprecated, legacy case of depending on the commonName as + // a hostname. We don't enforce name constraints against the CN, but + // VerifyHostname will look for hostnames in there if there are no SANs. + // In order to ensure VerifyHostname will not accept an unchecked name, + // return an error here. + return CertificateInvalidError{c, NameConstraintsWithoutSANs, ""} + } else if checkNameConstraints && leaf.hasSANExtension() { + err := forEachSAN(leaf.getSANExtension(), func(tag int, data []byte) error { switch tag { case nameTypeEmail: name := string(data) @@ -704,18 +716,6 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V return nil } -// formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style. -func formatOID(oid asn1.ObjectIdentifier) string { - ret := "" - for i, v := range oid { - if i > 0 { - ret += "." - } - ret += strconv.Itoa(v) - } - return ret -} - // Verify attempts to verify c by building one or more chains from c to a // certificate in opts.Roots, using certificates in opts.Intermediates if // needed. If successful, it returns one or more chains where the first @@ -872,6 +872,64 @@ nextIntermediate: return } +// validHostname returns whether host is a valid hostname that can be matched or +// matched against according to RFC 6125 2.2, with some leniency to accommodate +// legacy values. +func validHostname(host string) bool { + host = strings.TrimSuffix(host, ".") + + if len(host) == 0 { + return false + } + + for i, part := range strings.Split(host, ".") { + if part == "" { + // Empty label. + return false + } + if i == 0 && part == "*" { + // Only allow full left-most wildcards, as those are the only ones + // we match, and matching literal '*' characters is probably never + // the expected behavior. + continue + } + for j, c := range part { + if 'a' <= c && c <= 'z' { + continue + } + if '0' <= c && c <= '9' { + continue + } + if 'A' <= c && c <= 'Z' { + continue + } + if c == '-' && j != 0 { + continue + } + if c == '_' { + // _ is not a valid character in hostnames, but it's commonly + // found in deployments outside the WebPKI. + continue + } + return false + } + } + + return true +} + +// commonNameAsHostname reports whether the Common Name field should be +// considered the hostname that the certificate is valid for. This is a legacy +// behavior, disabled if the Subject Alt Name extension is present. +// +// It applies the strict validHostname check to the Common Name field, so that +// certificates without SANs can still be validated against CAs with name +// constraints if there is no risk the CN would be matched as a hostname. +// See NameConstraintsWithoutSANs and issue 24151. +func (c *Certificate) commonNameAsHostname() bool { + return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName) +} + func matchHostnames(pattern, host string) bool { host = strings.TrimSuffix(host, ".") pattern = strings.TrimSuffix(pattern, ".") @@ -952,15 +1010,16 @@ func (c *Certificate) VerifyHostname(h string) error { lowered := toLowerCaseASCII(h) - if c.hasSANExtension() { + if c.commonNameAsHostname() { + if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { + return nil + } + } else { for _, match := range c.DNSNames { if matchHostnames(toLowerCaseASCII(match), lowered) { return nil } } - // If Subject Alt Name is given, we ignore the common name. - } else if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) { - return nil } return HostnameError{c, h} diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go index bd3df47907..7684145839 100644 --- a/src/crypto/x509/verify_test.go +++ b/src/crypto/x509/verify_test.go @@ -15,8 +15,6 @@ import ( "time" ) -var supportSHA2 = true - type verifyTest struct { leaf string intermediates []string @@ -27,6 +25,7 @@ type verifyTest struct { keyUsages []ExtKeyUsage testSystemRootsError bool sha2 bool + ignoreCN bool errorCallback func(*testing.T, int, error) bool expectedChains [][]string @@ -73,7 +72,16 @@ var verifyTests = []verifyTest{ currentTime: 1395785200, dnsName: "www.example.com", - errorCallback: expectHostnameError, + errorCallback: expectHostnameError("certificate is valid for"), + }, + { + leaf: googleLeaf, + intermediates: []string{giag2Intermediate}, + roots: []string{geoTrustRoot}, + currentTime: 1395785200, + dnsName: "1.2.3.4", + + errorCallback: expectHostnameError("doesn't contain any IP SANs"), }, { leaf: googleLeaf, @@ -250,7 +258,7 @@ var verifyTests = []verifyTest{ dnsName: "notfoo.example", systemSkip: true, - errorCallback: expectHostnameError, + errorCallback: expectHostnameError("certificate is valid for"), }, { // The issuer name in the leaf doesn't exactly match the @@ -283,7 +291,7 @@ var verifyTests = []verifyTest{ currentTime: 1486684488, systemSkip: true, - errorCallback: expectHostnameError, + errorCallback: expectHostnameError("certificate is not valid for any names"), }, { // Test that excluded names are respected. @@ -320,19 +328,77 @@ var verifyTests = []verifyTest{ errorCallback: expectUnhandledCriticalExtension, }, + { + // Test that invalid CN are ignored. + leaf: invalidCNWithoutSAN, + dnsName: "foo,invalid", + roots: []string{invalidCNRoot}, + currentTime: 1540000000, + systemSkip: true, + + errorCallback: expectHostnameError("Common Name is not a valid hostname"), + }, + { + // Test that valid CN are respected. + leaf: validCNWithoutSAN, + dnsName: "foo.example.com", + roots: []string{invalidCNRoot}, + currentTime: 1540000000, + systemSkip: true, + + expectedChains: [][]string{ + {"foo.example.com", "Test root"}, + }, + }, + // Replicate CN tests with ignoreCN = true + { + leaf: ignoreCNWithSANLeaf, + dnsName: "foo.example.com", + roots: []string{ignoreCNWithSANRoot}, + currentTime: 1486684488, + systemSkip: true, + ignoreCN: true, + + errorCallback: expectHostnameError("certificate is not valid for any names"), + }, + { + leaf: invalidCNWithoutSAN, + dnsName: "foo,invalid", + roots: []string{invalidCNRoot}, + currentTime: 1540000000, + systemSkip: true, + ignoreCN: true, + + errorCallback: expectHostnameError("Common Name is not a valid hostname"), + }, + { + leaf: validCNWithoutSAN, + dnsName: "foo.example.com", + roots: []string{invalidCNRoot}, + currentTime: 1540000000, + systemSkip: true, + ignoreCN: true, + + errorCallback: expectHostnameError("not valid for any names"), + }, } -func expectHostnameError(t *testing.T, i int, err error) (ok bool) { - if _, ok := err.(HostnameError); !ok { - t.Errorf("#%d: error was not a HostnameError: %s", i, err) - return false +func expectHostnameError(msg string) func(*testing.T, int, error) bool { + return func(t *testing.T, i int, err error) (ok bool) { + if _, ok := err.(HostnameError); !ok { + t.Errorf("#%d: error was not a HostnameError: %v", i, err) + return false + } + if !strings.Contains(err.Error(), msg) { + t.Errorf("#%d: HostnameError did not contain %q: %v", i, msg, err) + } + return true } - return true } func expectExpired(t *testing.T, i int, err error) (ok bool) { if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired { - t.Errorf("#%d: error was not Expired: %s", i, err) + t.Errorf("#%d: error was not Expired: %v", i, err) return false } return true @@ -340,7 +406,7 @@ func expectExpired(t *testing.T, i int, err error) (ok bool) { func expectUsageError(t *testing.T, i int, err error) (ok bool) { if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage { - t.Errorf("#%d: error was not IncompatibleUsage: %s", i, err) + t.Errorf("#%d: error was not IncompatibleUsage: %v", i, err) return false } return true @@ -349,11 +415,11 @@ func expectUsageError(t *testing.T, i int, err error) (ok bool) { func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) { e, ok := err.(UnknownAuthorityError) if !ok { - t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err) + t.Errorf("#%d: error was not UnknownAuthorityError: %v", i, err) return false } if e.Cert == nil { - t.Errorf("#%d: error was UnknownAuthorityError, but missing Cert: %s", i, err) + t.Errorf("#%d: error was UnknownAuthorityError, but missing Cert: %v", i, err) return false } return true @@ -361,7 +427,7 @@ func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) { func expectSystemRootsError(t *testing.T, i int, err error) bool { if _, ok := err.(SystemRootsError); !ok { - t.Errorf("#%d: error was not SystemRootsError: %s", i, err) + t.Errorf("#%d: error was not SystemRootsError: %v", i, err) return false } return true @@ -373,7 +439,7 @@ func expectHashError(t *testing.T, i int, err error) bool { return false } if expected := "algorithm unimplemented"; !strings.Contains(err.Error(), expected) { - t.Errorf("#%d: error resulting from invalid hash didn't contain '%s', rather it was: %s", i, expected, err) + t.Errorf("#%d: error resulting from invalid hash didn't contain '%s', rather it was: %v", i, expected, err) return false } return true @@ -381,7 +447,7 @@ func expectHashError(t *testing.T, i int, err error) bool { func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) { if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NameMismatch { - t.Errorf("#%d: error was not a NameMismatch: %s", i, err) + t.Errorf("#%d: error was not a NameMismatch: %v", i, err) return false } return true @@ -389,7 +455,7 @@ func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) func expectNameConstraintsError(t *testing.T, i int, err error) (ok bool) { if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName { - t.Errorf("#%d: error was not a CANotAuthorizedForThisName: %s", i, err) + t.Errorf("#%d: error was not a CANotAuthorizedForThisName: %v", i, err) return false } return true @@ -397,7 +463,7 @@ func expectNameConstraintsError(t *testing.T, i int, err error) (ok bool) { func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) { if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign { - t.Errorf("#%d: error was not a NotAuthorizedToSign: %s", i, err) + t.Errorf("#%d: error was not a NotAuthorizedToSign: %v", i, err) return false } return true @@ -405,7 +471,7 @@ func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) { func expectUnhandledCriticalExtension(t *testing.T, i int, err error) (ok bool) { if _, ok := err.(UnhandledCriticalExtension); !ok { - t.Errorf("#%d: error was not an UnhandledCriticalExtension: %s", i, err) + t.Errorf("#%d: error was not an UnhandledCriticalExtension: %v", i, err) return false } return true @@ -420,6 +486,9 @@ func certificateFromPEM(pemBytes string) (*Certificate, error) { } func testVerify(t *testing.T, useSystemRoots bool) { + defer func(savedIgnoreCN bool) { + ignoreCN = savedIgnoreCN + }(ignoreCN) for i, test := range verifyTests { if useSystemRoots && test.systemSkip { continue @@ -427,10 +496,8 @@ func testVerify(t *testing.T, useSystemRoots bool) { if runtime.GOOS == "windows" && test.testSystemRootsError { continue } - if useSystemRoots && !supportSHA2 && test.sha2 { - continue - } + ignoreCN = test.ignoreCN opts := VerifyOptions{ Intermediates: NewCertPool(), DNSName: test.dnsName, @@ -459,7 +526,7 @@ func testVerify(t *testing.T, useSystemRoots bool) { leaf, err := certificateFromPEM(test.leaf) if err != nil { - t.Errorf("#%d: failed to parse leaf: %s", i, err) + t.Errorf("#%d: failed to parse leaf: %v", i, err) return } @@ -477,7 +544,7 @@ func testVerify(t *testing.T, useSystemRoots bool) { } if test.errorCallback == nil && err != nil { - t.Errorf("#%d: unexpected error: %s", i, err) + t.Errorf("#%d: unexpected error: %v", i, err) } if test.errorCallback != nil { if !test.errorCallback(t, i, err) { @@ -1518,6 +1585,95 @@ yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT +NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy -----END CERTIFICATE-----` +const invalidCNRoot = ` +-----BEGIN CERTIFICATE----- +MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg +cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM +CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj +QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg +oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI +XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6 +-----END CERTIFICATE----- +` + +const invalidCNWithoutSAN = ` +Certificate: + Data: + Version: 1 (0x0) + Serial Number: + 07:ba:bc:b7:d9:ab:0c:02:fe:50:1d:4e:15:a3:0d:e4:11:16:14:a2 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: OU = Test root + Validity + Not Before: Jul 11 18:35:21 2018 GMT + Not After : Jul 8 18:35:21 2028 GMT + Subject: CN = "foo,invalid" + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:a7:a6:7c:22:33:a7:47:7f:08:93:2d:5f:61:35: + 2e:da:45:67:76:f2:97:73:18:b0:01:12:4a:1a:d5: + b7:6f:41:3c:bb:05:69:f4:06:5d:ff:eb:2b:a7:85: + 0b:4c:f7:45:4e:81:40:7a:a9:c6:1d:bb:ba:d9:b9: + 26:b3:ca:50:90 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Signature Algorithm: ecdsa-with-SHA256 + 30:45:02:21:00:85:96:75:b6:72:3c:67:12:a0:7f:86:04:81: + d2:dd:c8:67:50:d7:5f:85:c0:54:54:fc:e6:6b:45:08:93:d3: + 2a:02:20:60:86:3e:d6:28:a6:4e:da:dd:6e:95:89:cc:00:76: + 78:1c:03:80:85:a6:5a:0b:eb:c5:f3:9c:2e:df:ef:6e:fa +-----BEGIN CERTIFICATE----- +MIIBJDCBywIUB7q8t9mrDAL+UB1OFaMN5BEWFKIwCgYIKoZIzj0EAwIwFDESMBAG +A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4MzUyMVoXDTI4MDcwODE4MzUyMVow +FjEUMBIGA1UEAwwLZm9vLGludmFsaWQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC +AASnpnwiM6dHfwiTLV9hNS7aRWd28pdzGLABEkoa1bdvQTy7BWn0Bl3/6yunhQtM +90VOgUB6qcYdu7rZuSazylCQMAoGCCqGSM49BAMCA0gAMEUCIQCFlnW2cjxnEqB/ +hgSB0t3IZ1DXX4XAVFT85mtFCJPTKgIgYIY+1iimTtrdbpWJzAB2eBwDgIWmWgvr +xfOcLt/vbvo= +-----END CERTIFICATE----- +` + +const validCNWithoutSAN = ` +Certificate: + Data: + Version: 1 (0x0) + Serial Number: + 07:ba:bc:b7:d9:ab:0c:02:fe:50:1d:4e:15:a3:0d:e4:11:16:14:a4 + Signature Algorithm: ecdsa-with-SHA256 + Issuer: OU = Test root + Validity + Not Before: Jul 11 18:47:24 2018 GMT + Not After : Jul 8 18:47:24 2028 GMT + Subject: CN = foo.example.com + Subject Public Key Info: + Public Key Algorithm: id-ecPublicKey + Public-Key: (256 bit) + pub: + 04:a7:a6:7c:22:33:a7:47:7f:08:93:2d:5f:61:35: + 2e:da:45:67:76:f2:97:73:18:b0:01:12:4a:1a:d5: + b7:6f:41:3c:bb:05:69:f4:06:5d:ff:eb:2b:a7:85: + 0b:4c:f7:45:4e:81:40:7a:a9:c6:1d:bb:ba:d9:b9: + 26:b3:ca:50:90 + ASN1 OID: prime256v1 + NIST CURVE: P-256 + Signature Algorithm: ecdsa-with-SHA256 + 30:44:02:20:53:6c:d7:b7:59:61:51:72:a5:18:a3:4b:0d:52: + ea:15:fa:d0:93:30:32:54:4b:ed:0f:58:85:b8:a8:1a:82:3b: + 02:20:14:77:4b:0e:7e:4f:0a:4f:64:26:97:dc:d0:ed:aa:67: + 1d:37:85:da:b4:87:ba:25:1c:2a:58:f7:23:11:8b:3d +-----BEGIN CERTIFICATE----- +MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG +A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow +GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D +AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr +p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR +cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0 +h7olHCpY9yMRiz0= +-----END CERTIFICATE----- +` + var unknownAuthorityErrorTests = []struct { cert string expected string @@ -1535,7 +1691,7 @@ func TestUnknownAuthorityError(t *testing.T) { } c, err := ParseCertificate(der.Bytes) if err != nil { - t.Errorf("#%d: Unable to parse certificate -> %s", i, err) + t.Errorf("#%d: Unable to parse certificate -> %v", i, err) } uae := &UnknownAuthorityError{ Cert: c, @@ -1707,3 +1863,28 @@ UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA 2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc= -----END CERTIFICATE-----` + +func TestValidHostname(t *testing.T) { + tests := []struct { + host string + want bool + }{ + {"example.com", true}, + {"eXample123-.com", true}, + {"-eXample123-.com", false}, + {"", false}, + {".", false}, + {"example..com", false}, + {".example.com", false}, + {"*.example.com", true}, + {"*foo.example.com", false}, + {"foo.*.example.com", false}, + {"exa_mple.com", true}, + {"foo,bar", false}, + } + for _, tt := range tests { + if got := validHostname(tt.host); got != tt.want { + t.Errorf("validHostname(%q) = %v, want %v", tt.host, got, tt.want) + } + } +} diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 34eb8b0105..2e72471de2 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -843,23 +843,16 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature } func (c *Certificate) hasNameConstraints() bool { - for _, e := range c.Extensions { - if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 30 { - return true - } - } - - return false + return oidInExtensions(oidExtensionNameConstraints, c.Extensions) } -func (c *Certificate) getSANExtension() ([]byte, bool) { +func (c *Certificate) getSANExtension() []byte { for _, e := range c.Extensions { - if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 && e.Id[3] == 17 { - return e.Value, true + if e.Id.Equal(oidExtensionSubjectAltName) { + return e.Value } } - - return nil, false + return nil } func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error { diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go index 1e7a989089..7537f87d47 100644 --- a/src/database/sql/sql.go +++ b/src/database/sql/sql.go @@ -540,7 +540,7 @@ type driverStmt struct { closeErr error // return value of previous Close call } -// Close ensures dirver.Stmt is only closed once any always returns the same +// Close ensures driver.Stmt is only closed once and always returns the same // result. func (ds *driverStmt) Close() error { ds.Lock() @@ -2735,8 +2735,7 @@ func (rs *Rows) Err() error { } // Columns returns the column names. -// Columns returns an error if the rows are closed, or if the rows -// are from QueryRow and there was a deferred error. +// Columns returns an error if the rows are closed. func (rs *Rows) Columns() ([]string, error) { rs.closemu.RLock() defer rs.closemu.RUnlock() diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go index 2f5efae4e6..1c308b3dc3 100644 --- a/src/debug/pe/file.go +++ b/src/debug/pe/file.go @@ -91,7 +91,7 @@ func NewFile(r io.ReaderAt) (*File, error) { return nil, err } switch f.FileHeader.Machine { - case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386: + case IMAGE_FILE_MACHINE_UNKNOWN, IMAGE_FILE_MACHINE_ARMNT, IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_I386: default: return nil, fmt.Errorf("Unrecognised COFF file header machine value of 0x%x.", f.FileHeader.Machine) } diff --git a/src/debug/pe/pe.go b/src/debug/pe/pe.go index e933ae1c2a..3f8099dfab 100644 --- a/src/debug/pe/pe.go +++ b/src/debug/pe/pe.go @@ -91,6 +91,7 @@ const ( IMAGE_FILE_MACHINE_AM33 = 0x1d3 IMAGE_FILE_MACHINE_AMD64 = 0x8664 IMAGE_FILE_MACHINE_ARM = 0x1c0 + IMAGE_FILE_MACHINE_ARMNT = 0x1c4 IMAGE_FILE_MACHINE_ARM64 = 0xaa64 IMAGE_FILE_MACHINE_EBC = 0xebc IMAGE_FILE_MACHINE_I386 = 0x14c diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go index 9a99370f1e..e8afc48859 100644 --- a/src/encoding/base64/base64.go +++ b/src/encoding/base64/base64.go @@ -465,10 +465,9 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { } si := 0 - ilen := len(src) - olen := len(dst) - for strconv.IntSize >= 64 && ilen-si >= 8 && olen-n >= 8 { - if ok := enc.decode64(dst[n:], src[si:]); ok { + for strconv.IntSize >= 64 && len(src)-si >= 8 && len(dst)-n >= 8 { + if dn, ok := enc.decode64(src[si:]); ok { + binary.BigEndian.PutUint64(dst[n:], dn) n += 6 si += 8 } else { @@ -481,8 +480,9 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { } } - for ilen-si >= 4 && olen-n >= 4 { - if ok := enc.decode32(dst[n:], src[si:]); ok { + for len(src)-si >= 4 && len(dst)-n >= 4 { + if dn, ok := enc.decode32(src[si:]); ok { + binary.BigEndian.PutUint32(dst[n:], dn) n += 3 si += 4 } else { @@ -506,72 +506,70 @@ func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { return n, err } -// decode32 tries to decode 4 base64 char into 3 bytes. -// len(dst) and len(src) must both be >= 4. -// Returns true if decode succeeded. -func (enc *Encoding) decode32(dst, src []byte) bool { - var dn, n uint32 +// decode32 tries to decode 4 base64 characters into 3 bytes, and returns those +// bytes. len(src) must be >= 4. +// Returns (0, false) if decoding failed. +func (enc *Encoding) decode32(src []byte) (dn uint32, ok bool) { + var n uint32 + _ = src[3] if n = uint32(enc.decodeMap[src[0]]); n == 0xff { - return false + return 0, false } dn |= n << 26 if n = uint32(enc.decodeMap[src[1]]); n == 0xff { - return false + return 0, false } dn |= n << 20 if n = uint32(enc.decodeMap[src[2]]); n == 0xff { - return false + return 0, false } dn |= n << 14 if n = uint32(enc.decodeMap[src[3]]); n == 0xff { - return false + return 0, false } dn |= n << 8 - - binary.BigEndian.PutUint32(dst, dn) - return true + return dn, true } -// decode64 tries to decode 8 base64 char into 6 bytes. -// len(dst) and len(src) must both be >= 8. -// Returns true if decode succeeded. -func (enc *Encoding) decode64(dst, src []byte) bool { - var dn, n uint64 +// decode64 tries to decode 8 base64 characters into 6 bytes, and returns those +// bytes. len(src) must be >= 8. +// Returns (0, false) if decoding failed. +func (enc *Encoding) decode64(src []byte) (dn uint64, ok bool) { + var n uint64 + _ = src[7] if n = uint64(enc.decodeMap[src[0]]); n == 0xff { - return false + return 0, false } dn |= n << 58 if n = uint64(enc.decodeMap[src[1]]); n == 0xff { - return false + return 0, false } dn |= n << 52 if n = uint64(enc.decodeMap[src[2]]); n == 0xff { - return false + return 0, false } dn |= n << 46 if n = uint64(enc.decodeMap[src[3]]); n == 0xff { - return false + return 0, false } dn |= n << 40 if n = uint64(enc.decodeMap[src[4]]); n == 0xff { - return false + return 0, false } dn |= n << 34 if n = uint64(enc.decodeMap[src[5]]); n == 0xff { - return false + return 0, false } dn |= n << 28 if n = uint64(enc.decodeMap[src[6]]); n == 0xff { - return false + return 0, false } dn |= n << 22 if n = uint64(enc.decodeMap[src[7]]); n == 0xff { - return false + return 0, false } dn |= n << 16 - - binary.BigEndian.PutUint64(dst, dn) - return true + return dn, true } type newlineFilteringReader struct { diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go index 85b3bc2295..8c2d1d9da4 100644 --- a/src/encoding/binary/binary.go +++ b/src/encoding/binary/binary.go @@ -161,23 +161,17 @@ func (bigEndian) GoString() string { return "binary.BigEndian" } func Read(r io.Reader, order ByteOrder, data interface{}) error { // Fast path for basic types and slices. if n := intDataSize(data); n != 0 { - var b [8]byte - var bs []byte - if n > len(b) { - bs = make([]byte, n) - } else { - bs = b[:n] - } + bs := make([]byte, n) if _, err := io.ReadFull(r, bs); err != nil { return err } switch data := data.(type) { case *bool: - *data = b[0] != 0 + *data = bs[0] != 0 case *int8: - *data = int8(b[0]) + *data = int8(bs[0]) case *uint8: - *data = b[0] + *data = bs[0] case *int16: *data = int16(order.Uint16(bs)) case *uint16: @@ -260,25 +254,19 @@ func Read(r io.Reader, order ByteOrder, data interface{}) error { func Write(w io.Writer, order ByteOrder, data interface{}) error { // Fast path for basic types and slices. if n := intDataSize(data); n != 0 { - var b [8]byte - var bs []byte - if n > len(b) { - bs = make([]byte, n) - } else { - bs = b[:n] - } + bs := make([]byte, n) switch v := data.(type) { case *bool: if *v { - b[0] = 1 + bs[0] = 1 } else { - b[0] = 0 + bs[0] = 0 } case bool: if v { - b[0] = 1 + bs[0] = 1 } else { - b[0] = 0 + bs[0] = 0 } case []bool: for i, x := range v { @@ -289,19 +277,19 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error { } } case *int8: - b[0] = byte(*v) + bs[0] = byte(*v) case int8: - b[0] = byte(v) + bs[0] = byte(v) case []int8: for i, x := range v { bs[i] = byte(x) } case *uint8: - b[0] = *v + bs[0] = *v case uint8: - b[0] = v + bs[0] = v case []uint8: - bs = v + bs = v // TODO(josharian): avoid allocating bs in this case? case *int16: order.PutUint16(bs, uint16(*v)) case int16: diff --git a/src/encoding/hex/hex.go b/src/encoding/hex/hex.go index aee5aecb1a..2bb2b57df9 100644 --- a/src/encoding/hex/hex.go +++ b/src/encoding/hex/hex.go @@ -6,10 +6,10 @@ package hex import ( - "bytes" "errors" "fmt" "io" + "strings" ) const hextable = "0123456789abcdef" @@ -116,7 +116,16 @@ func DecodeString(s string) ([]byte, error) { // Dump returns a string that contains a hex dump of the given data. The format // of the hex dump matches the output of `hexdump -C` on the command line. func Dump(data []byte) string { - var buf bytes.Buffer + if len(data) == 0 { + return "" + } + + var buf strings.Builder + // Dumper will write 79 bytes per complete 16 byte chunk, and at least + // 64 bytes for whatever remains. Round the allocation up, since only a + // maximum of 15 bytes will be wasted. + buf.Grow((1 + ((len(data) - 1) / 16)) * 79) + dumper := Dumper(&buf) dumper.Write(data) dumper.Close() diff --git a/src/encoding/hex/hex_test.go b/src/encoding/hex/hex_test.go index 6ba054ef9a..e9f4b3a53a 100644 --- a/src/encoding/hex/hex_test.go +++ b/src/encoding/hex/hex_test.go @@ -248,3 +248,16 @@ func BenchmarkEncode(b *testing.B) { }) } } + +func BenchmarkDump(b *testing.B) { + for _, size := range []int{256, 1024, 4096, 16384} { + src := bytes.Repeat([]byte{2, 3, 5, 7, 9, 11, 13, 17}, size/8) + sink = make([]byte, 2*size) + + b.Run(fmt.Sprintf("%v", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + Dump(src) + } + }) + } +} diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go index bd322db2e6..72cb349062 100644 --- a/src/encoding/json/bench_test.go +++ b/src/encoding/json/bench_test.go @@ -114,6 +114,34 @@ func BenchmarkCodeMarshal(b *testing.B) { b.SetBytes(int64(len(codeJSON))) } +func benchMarshalBytes(n int) func(*testing.B) { + sample := []byte("hello world") + // Use a struct pointer, to avoid an allocation when passing it as an + // interface parameter to Marshal. + v := &struct { + Bytes []byte + }{ + bytes.Repeat(sample, (n/len(sample))+1)[:n], + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + if _, err := Marshal(v); err != nil { + b.Fatal("Marshal:", err) + } + } + } +} + +func BenchmarkMarshalBytes(b *testing.B) { + // 32 fits within encodeState.scratch. + b.Run("32", benchMarshalBytes(32)) + // 256 doesn't fit in encodeState.scratch, but is small enough to + // allocate and avoid the slower base64.NewEncoder. + b.Run("256", benchMarshalBytes(256)) + // 4096 is large enough that we want to avoid allocating for it. + b.Run("4096", benchMarshalBytes(4096)) +} + func BenchmarkCodeDecoder(b *testing.B) { if codeJSON == nil { b.StopTimer() diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 0b29249218..82dc78083a 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -179,7 +179,7 @@ func (d *decodeState) unmarshal(v interface{}) error { // test must be applied at the top level of the value. err := d.value(rv) if err != nil { - return err + return d.addErrorContext(err) } return d.savedError } @@ -267,7 +267,7 @@ type decodeState struct { opcode int // last read result scan scanner errorContext struct { // provides context for type errors - Struct string + Struct reflect.Type Field string } savedError error @@ -289,7 +289,7 @@ func (d *decodeState) init(data []byte) *decodeState { d.data = data d.off = 0 d.savedError = nil - d.errorContext.Struct = "" + d.errorContext.Struct = nil d.errorContext.Field = "" return d } @@ -304,10 +304,10 @@ func (d *decodeState) saveError(err error) { // addErrorContext returns a new error enhanced with information from d.errorContext func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != "" || d.errorContext.Field != "" { + if d.errorContext.Struct != nil || d.errorContext.Field != "" { switch err := err.(type) { case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct + err.Struct = d.errorContext.Struct.Name() err.Field = d.errorContext.Field return err } @@ -332,13 +332,12 @@ func (d *decodeState) skip() { // scanNext processes the byte at d.data[d.off]. func (d *decodeState) scanNext() { - s, data, i := &d.scan, d.data, d.off - if i < len(data) { - d.opcode = s.step(s, data[i]) - d.off = i + 1 + if d.off < len(d.data) { + d.opcode = d.scan.step(&d.scan, d.data[d.off]) + d.off++ } else { - d.opcode = s.eof() - d.off = len(data) + 1 // mark processed EOF with len+1 + d.opcode = d.scan.eof() + d.off = len(d.data) + 1 // mark processed EOF with len+1 } } @@ -346,7 +345,7 @@ func (d *decodeState) scanNext() { // receives a scan code not equal to op. func (d *decodeState) scanWhile(op int) { s, data, i := &d.scan, d.data, d.off - for i < len(d.data) { + for i < len(data) { newOp := s.step(s, data[i]) i++ if newOp != op { @@ -356,7 +355,7 @@ func (d *decodeState) scanWhile(op int) { } } - d.off = len(d.data) + 1 // mark processed EOF with len+1 + d.off = len(data) + 1 // mark processed EOF with len+1 d.opcode = d.scan.eof() } @@ -413,11 +412,7 @@ func (d *decodeState) valueQuoted() (interface{}, error) { default: return nil, errPhase - case scanBeginArray: - d.skip() - d.scanNext() - - case scanBeginObject: + case scanBeginArray, scanBeginObject: d.skip() d.scanNext() @@ -611,7 +606,7 @@ func (d *decodeState) array(v reflect.Value) error { } var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem() +var textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() // object consumes an object from d.data[d.off-1:], decoding into v. // The first byte ('{') of the object has been read already. @@ -629,6 +624,7 @@ func (d *decodeState) object(v reflect.Value) error { return nil } v = pv + t := v.Type() // Decoding into nil interface? Switch to non-reflect code. if v.Kind() == reflect.Interface && v.NumMethod() == 0 { @@ -640,6 +636,8 @@ func (d *decodeState) object(v reflect.Value) error { return nil } + var fields []field + // Check type of target: // struct or // map[T1]T2 where T1 is string, an integer type, @@ -648,14 +646,13 @@ func (d *decodeState) object(v reflect.Value) error { case reflect.Map: // Map key must either have string kind, have an integer kind, // or be an encoding.TextUnmarshaler. - t := v.Type() switch t.Key().Kind() { case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: default: if !reflect.PtrTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) d.skip() return nil } @@ -664,14 +661,16 @@ func (d *decodeState) object(v reflect.Value) error { v.Set(reflect.MakeMap(t)) } case reflect.Struct: + fields = cachedTypeFields(t) // ok default: - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) + d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) d.skip() return nil } var mapElem reflect.Value + originalErrorContext := d.errorContext for { // Read opening " of string key or closing }. @@ -698,7 +697,7 @@ func (d *decodeState) object(v reflect.Value) error { destring := false // whether the value is wrapped in a string to be decoded first if v.Kind() == reflect.Map { - elemType := v.Type().Elem() + elemType := t.Elem() if !mapElem.IsValid() { mapElem = reflect.New(elemType).Elem() } else { @@ -707,7 +706,6 @@ func (d *decodeState) object(v reflect.Value) error { subv = mapElem } else { var f *field - fields := cachedTypeFields(v.Type()) for i := range fields { ff := &fields[i] if bytes.Equal(ff.nameBytes, key) { @@ -744,7 +742,7 @@ func (d *decodeState) object(v reflect.Value) error { subv = subv.Field(i) } d.errorContext.Field = f.name - d.errorContext.Struct = v.Type().Name() + d.errorContext.Struct = t } else if d.disallowUnknownFields { d.saveError(fmt.Errorf("json: unknown field %q", key)) } @@ -785,13 +783,13 @@ func (d *decodeState) object(v reflect.Value) error { // Write value back to map; // if using struct, subv points into struct already. if v.Kind() == reflect.Map { - kt := v.Type().Key() + kt := t.Key() var kv reflect.Value switch { case kt.Kind() == reflect.String: kv = reflect.ValueOf(key).Convert(kt) case reflect.PtrTo(kt).Implements(textUnmarshalerType): - kv = reflect.New(v.Type().Key()) + kv = reflect.New(kt) if err := d.literalStore(item, kv, true); err != nil { return err } @@ -832,8 +830,7 @@ func (d *decodeState) object(v reflect.Value) error { return errPhase } - d.errorContext.Struct = "" - d.errorContext.Field = "" + d.errorContext = originalErrorContext } return nil } @@ -991,7 +988,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) } - return &UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())} + d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) case reflect.Interface: n, err := d.convertNumber(s) if err != nil { diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index ab83b81bb3..defa97e40f 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -41,6 +41,16 @@ type VOuter struct { V V } +type W struct { + S SS +} + +type SS string + +func (*SS) UnmarshalJSON(data []byte) error { + return &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(SS(""))} +} + // ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and // without UseNumber var ifaceNumAsFloat64 = map[string]interface{}{ @@ -142,7 +152,7 @@ var ( umstructXY = ustructText{unmarshalerText{"x", "y"}} ummapType = map[unmarshalerText]bool{} - ummapXY = map[unmarshalerText]bool{unmarshalerText{"x", "y"}: true} + ummapXY = map[unmarshalerText]bool{{"x", "y"}: true} ) // Test data structures for anonymous fields. @@ -371,6 +381,10 @@ func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { return (*intWithMarshalText)(b).UnmarshalText(data) } +type mapStringToStringData struct { + Data map[string]string `json:"data"` +} + type unmarshalTest struct { in string ptr interface{} @@ -401,8 +415,10 @@ var unmarshalTests = []unmarshalTest{ {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, {in: "null", ptr: new(interface{}), out: nil}, {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7, "T", "X"}}, + {in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(""), 8, "T", "X"}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, + {in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeOf(SS("")), 0, "W", "S"}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, {in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64}, @@ -866,6 +882,18 @@ var unmarshalTests = []unmarshalTest{ err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, + // issue 26444 + // UnmarshalTypeError without field & struct values + { + in: `{"data":{"test1": "bob", "test2": 123}}`, + ptr: new(mapStringToStringData), + err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, + }, + { + in: `{"data":{"test1": 123, "test2": "bob"}}`, + ptr: new(mapStringToStringData), + err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, + }, } func TestMarshal(t *testing.T) { diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go index 28ca5fe9e0..f10124e67d 100644 --- a/src/encoding/json/encode.go +++ b/src/encoding/json/encode.go @@ -381,8 +381,8 @@ func typeEncoder(t reflect.Type) encoderFunc { } var ( - marshalerType = reflect.TypeOf(new(Marshaler)).Elem() - textMarshalerType = reflect.TypeOf(new(encoding.TextMarshaler)).Elem() + marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() + textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() ) // newTypeEncoder constructs an encoderFunc for a type. @@ -624,40 +624,49 @@ func unsupportedTypeEncoder(e *encodeState, v reflect.Value, _ encOpts) { } type structEncoder struct { - fields []field - fieldEncs []encoderFunc + fields []field } -func (se *structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { - e.WriteByte('{') - first := true - for i, f := range se.fields { - fv := fieldByIndex(v, f.index) - if !fv.IsValid() || f.omitEmpty && isEmptyValue(fv) { +func (se structEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { + next := byte('{') +FieldLoop: + for i := range se.fields { + f := &se.fields[i] + + // Find the nested struct field by following f.index. + fv := v + for _, i := range f.index { + if fv.Kind() == reflect.Ptr { + if fv.IsNil() { + continue FieldLoop + } + fv = fv.Elem() + } + fv = fv.Field(i) + } + + if f.omitEmpty && isEmptyValue(fv) { continue } - if first { - first = false + e.WriteByte(next) + next = ',' + if opts.escapeHTML { + e.WriteString(f.nameEscHTML) } else { - e.WriteByte(',') + e.WriteString(f.nameNonEsc) } - e.string(f.name, opts.escapeHTML) - e.WriteByte(':') opts.quoted = f.quoted - se.fieldEncs[i](e, fv, opts) + f.encoder(e, fv, opts) + } + if next == '{' { + e.WriteString("{}") + } else { + e.WriteByte('}') } - e.WriteByte('}') } func newStructEncoder(t reflect.Type) encoderFunc { - fields := cachedTypeFields(t) - se := &structEncoder{ - fields: fields, - fieldEncs: make([]encoderFunc, len(fields)), - } - for i, f := range fields { - se.fieldEncs[i] = typeEncoder(typeByIndex(t, f.index)) - } + se := structEncoder{fields: cachedTypeFields(t)} return se.encode } @@ -665,7 +674,7 @@ type mapEncoder struct { elemEnc encoderFunc } -func (me *mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { +func (me mapEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return @@ -704,7 +713,7 @@ func newMapEncoder(t reflect.Type) encoderFunc { return unsupportedTypeEncoder } } - me := &mapEncoder{typeEncoder(t.Elem())} + me := mapEncoder{typeEncoder(t.Elem())} return me.encode } @@ -715,14 +724,22 @@ func encodeByteSlice(e *encodeState, v reflect.Value, _ encOpts) { } s := v.Bytes() e.WriteByte('"') - if len(s) < 1024 { - // for small buffers, using Encode directly is much faster. - dst := make([]byte, base64.StdEncoding.EncodedLen(len(s))) + encodedLen := base64.StdEncoding.EncodedLen(len(s)) + if encodedLen <= len(e.scratch) { + // If the encoded bytes fit in e.scratch, avoid an extra + // allocation and use the cheaper Encoding.Encode. + dst := e.scratch[:encodedLen] + base64.StdEncoding.Encode(dst, s) + e.Write(dst) + } else if encodedLen <= 1024 { + // The encoded bytes are short enough to allocate for, and + // Encoding.Encode is still cheaper. + dst := make([]byte, encodedLen) base64.StdEncoding.Encode(dst, s) e.Write(dst) } else { - // for large buffers, avoid unnecessary extra temporary - // buffer space. + // The encoded bytes are too long to cheaply allocate, and + // Encoding.Encode is no longer noticeably cheaper. enc := base64.NewEncoder(base64.StdEncoding, e) enc.Write(s) enc.Close() @@ -735,7 +752,7 @@ type sliceEncoder struct { arrayEnc encoderFunc } -func (se *sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { +func (se sliceEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return @@ -751,7 +768,7 @@ func newSliceEncoder(t reflect.Type) encoderFunc { return encodeByteSlice } } - enc := &sliceEncoder{newArrayEncoder(t)} + enc := sliceEncoder{newArrayEncoder(t)} return enc.encode } @@ -759,7 +776,7 @@ type arrayEncoder struct { elemEnc encoderFunc } -func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { +func (ae arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { e.WriteByte('[') n := v.Len() for i := 0; i < n; i++ { @@ -772,7 +789,7 @@ func (ae *arrayEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { } func newArrayEncoder(t reflect.Type) encoderFunc { - enc := &arrayEncoder{typeEncoder(t.Elem())} + enc := arrayEncoder{typeEncoder(t.Elem())} return enc.encode } @@ -780,7 +797,7 @@ type ptrEncoder struct { elemEnc encoderFunc } -func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { +func (pe ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.IsNil() { e.WriteString("null") return @@ -789,7 +806,7 @@ func (pe *ptrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { } func newPtrEncoder(t reflect.Type) encoderFunc { - enc := &ptrEncoder{typeEncoder(t.Elem())} + enc := ptrEncoder{typeEncoder(t.Elem())} return enc.encode } @@ -797,7 +814,7 @@ type condAddrEncoder struct { canAddrEnc, elseEnc encoderFunc } -func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { +func (ce condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) { if v.CanAddr() { ce.canAddrEnc(e, v, opts) } else { @@ -808,7 +825,7 @@ func (ce *condAddrEncoder) encode(e *encodeState, v reflect.Value, opts encOpts) // newCondAddrEncoder returns an encoder that checks whether its value // CanAddr and delegates to canAddrEnc if so, else to elseEnc. func newCondAddrEncoder(canAddrEnc, elseEnc encoderFunc) encoderFunc { - enc := &condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} + enc := condAddrEncoder{canAddrEnc: canAddrEnc, elseEnc: elseEnc} return enc.encode } @@ -822,28 +839,13 @@ func isValidTag(s string) bool { // Backslash and quote chars are reserved, but // otherwise any punctuation chars are allowed // in a tag name. - default: - if !unicode.IsLetter(c) && !unicode.IsDigit(c) { - return false - } + case !unicode.IsLetter(c) && !unicode.IsDigit(c): + return false } } return true } -func fieldByIndex(v reflect.Value, index []int) reflect.Value { - for _, i := range index { - if v.Kind() == reflect.Ptr { - if v.IsNil() { - return reflect.Value{} - } - v = v.Elem() - } - v = v.Field(i) - } - return v -} - func typeByIndex(t reflect.Type, index []int) reflect.Type { for _, i := range index { if t.Kind() == reflect.Ptr { @@ -893,18 +895,15 @@ func (e *encodeState) string(s string, escapeHTML bool) { if start < i { e.WriteString(s[start:i]) } + e.WriteByte('\\') switch b { case '\\', '"': - e.WriteByte('\\') e.WriteByte(b) case '\n': - e.WriteByte('\\') e.WriteByte('n') case '\r': - e.WriteByte('\\') e.WriteByte('r') case '\t': - e.WriteByte('\\') e.WriteByte('t') default: // This encodes bytes < 0x20 except for \t, \n and \r. @@ -912,7 +911,7 @@ func (e *encodeState) string(s string, escapeHTML bool) { // because they can lead to security holes when // user-controlled strings are rendered into JSON // and served to some browsers. - e.WriteString(`\u00`) + e.WriteString(`u00`) e.WriteByte(hex[b>>4]) e.WriteByte(hex[b&0xF]) } @@ -968,18 +967,15 @@ func (e *encodeState) stringBytes(s []byte, escapeHTML bool) { if start < i { e.Write(s[start:i]) } + e.WriteByte('\\') switch b { case '\\', '"': - e.WriteByte('\\') e.WriteByte(b) case '\n': - e.WriteByte('\\') e.WriteByte('n') case '\r': - e.WriteByte('\\') e.WriteByte('r') case '\t': - e.WriteByte('\\') e.WriteByte('t') default: // This encodes bytes < 0x20 except for \t, \n and \r. @@ -987,7 +983,7 @@ func (e *encodeState) stringBytes(s []byte, escapeHTML bool) { // because they can lead to security holes when // user-controlled strings are rendered into JSON // and served to some browsers. - e.WriteString(`\u00`) + e.WriteString(`u00`) e.WriteByte(hex[b>>4]) e.WriteByte(hex[b&0xF]) } @@ -1036,17 +1032,16 @@ type field struct { nameBytes []byte // []byte(name) equalFold func(s, t []byte) bool // bytes.EqualFold or equivalent + nameNonEsc string // `"` + name + `":` + nameEscHTML string // `"` + HTMLEscape(name) + `":` + tag bool index []int typ reflect.Type omitEmpty bool quoted bool -} -func fillField(f field) field { - f.nameBytes = []byte(f.name) - f.equalFold = foldFunc(f.nameBytes) - return f + encoder encoderFunc } // byIndex sorts field by index sequence. @@ -1086,6 +1081,9 @@ func typeFields(t reflect.Type) []field { // Fields found. var fields []field + // Buffer to run HTMLEscape on field names. + var nameEscBuf bytes.Buffer + for len(next) > 0 { current, next = next, current[:0] count, nextCount = nextCount, map[reflect.Type]int{} @@ -1152,14 +1150,26 @@ func typeFields(t reflect.Type) []field { if name == "" { name = sf.Name } - fields = append(fields, fillField(field{ + field := field{ name: name, tag: tagged, index: index, typ: ft, omitEmpty: opts.Contains("omitempty"), quoted: quoted, - })) + } + field.nameBytes = []byte(field.name) + field.equalFold = foldFunc(field.nameBytes) + + // Build nameEscHTML and nameNonEsc ahead of time. + nameEscBuf.Reset() + nameEscBuf.WriteString(`"`) + HTMLEscape(&nameEscBuf, field.nameBytes) + nameEscBuf.WriteString(`":`) + field.nameEscHTML = nameEscBuf.String() + field.nameNonEsc = `"` + field.name + `":` + + fields = append(fields, field) if count[f.typ] > 1 { // If there were multiple instances, add a second, // so that the annihilation code will see a duplicate. @@ -1173,7 +1183,7 @@ func typeFields(t reflect.Type) []field { // Record new anonymous struct to explore in next round. nextCount[ft]++ if nextCount[ft] == 1 { - next = append(next, fillField(field{name: ft.Name(), index: index, typ: ft})) + next = append(next, field{name: ft.Name(), index: index, typ: ft}) } } } @@ -1227,6 +1237,10 @@ func typeFields(t reflect.Type) []field { fields = out sort.Sort(byIndex(fields)) + for i := range fields { + f := &fields[i] + f.encoder = typeEncoder(typeByIndex(t, f.index)) + } return fields } diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go index b90483cf35..cd5eadf3c1 100644 --- a/src/encoding/json/encode_test.go +++ b/src/encoding/json/encode_test.go @@ -405,6 +405,19 @@ func TestAnonymousFields(t *testing.T) { return S{s1{1, 2, s2{3, 4}}, 6} }, want: `{"MyInt1":1,"MyInt2":3}`, + }, { + // If an anonymous struct pointer field is nil, we should ignore + // the embedded fields behind it. Not properly doing so may + // result in the wrong output or reflect panics. + label: "EmbeddedFieldBehindNilPointer", + makeInput: func() interface{} { + type ( + S2 struct{ Field string } + S struct{ *S2 } + ) + return S{} + }, + want: `{}`, }} for _, tt := range tests { @@ -995,3 +1008,18 @@ func TestMarshalPanic(t *testing.T) { Marshal(&marshalPanic{}) t.Error("Marshal should have panicked") } + +func TestMarshalUncommonFieldNames(t *testing.T) { + v := struct { + A0, À, Aβ int + }{} + b, err := Marshal(v) + if err != nil { + t.Fatal("Marshal:", err) + } + want := `{"A0":0,"À":0,"Aβ":0}` + got := string(b) + if got != want { + t.Fatalf("Marshal: got %s want %s", got, want) + } +} diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go index 75a4270df7..7d5137fbc7 100644 --- a/src/encoding/json/stream.go +++ b/src/encoding/json/stream.go @@ -96,19 +96,19 @@ Input: // Look in the buffer for a new value. for i, c := range dec.buf[scanp:] { dec.scan.bytes++ - v := dec.scan.step(&dec.scan, c) - if v == scanEnd { + switch dec.scan.step(&dec.scan, c) { + case scanEnd: scanp += i break Input - } - // scanEnd is delayed one byte. - // We might block trying to get that byte from src, - // so instead invent a space byte. - if (v == scanEndObject || v == scanEndArray) && dec.scan.step(&dec.scan, ' ') == scanEnd { - scanp += i + 1 - break Input - } - if v == scanError { + case scanEndObject, scanEndArray: + // scanEnd is delayed one byte. + // We might block trying to get that byte from src, + // so instead invent a space byte. + if stateEndValue(&dec.scan, ' ') == scanEnd { + scanp += i + 1 + break Input + } + case scanError: dec.err = dec.scan.err return 0, dec.scan.err } @@ -471,7 +471,7 @@ func (dec *Decoder) tokenError(c byte) (Token, error) { case tokenObjectComma: context = " after object key:value pair" } - return nil, &SyntaxError{"invalid character " + quoteChar(c) + " " + context, dec.offset()} + return nil, &SyntaxError{"invalid character " + quoteChar(c) + context, dec.offset()} } // More reports whether there is another element in the diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go index 83c01d170c..aaf32e0a24 100644 --- a/src/encoding/json/stream_test.go +++ b/src/encoding/json/stream_test.go @@ -93,6 +93,10 @@ func TestEncoderIndent(t *testing.T) { func TestEncoderSetEscapeHTML(t *testing.T) { var c C var ct CText + var tagStruct struct { + Valid int `json:"<>&#! "` + Invalid int `json:"\\"` + } for _, tt := range []struct { name string v interface{} @@ -102,6 +106,11 @@ func TestEncoderSetEscapeHTML(t *testing.T) { {"c", c, `"\u003c\u0026\u003e"`, `"<&>"`}, {"ct", ct, `"\"\u003c\u0026\u003e\""`, `"\"<&>\""`}, {`"<&>"`, "<&>", `"\u003c\u0026\u003e"`, `"<&>"`}, + { + "tagStruct", tagStruct, + `{"\u003c\u003e\u0026#! ":0,"Invalid":0}`, + `{"<>&#! ":0,"Invalid":0}`, + }, } { var buf bytes.Buffer enc := NewEncoder(&buf) @@ -192,10 +201,9 @@ func nlines(s string, n int) string { } func TestRawMessage(t *testing.T) { - // TODO(rsc): Should not need the * in *RawMessage var data struct { X float64 - Id *RawMessage + Id RawMessage Y float32 } const raw = `["\u0056",null]` @@ -204,8 +212,8 @@ func TestRawMessage(t *testing.T) { if err != nil { t.Fatalf("Unmarshal: %v", err) } - if string([]byte(*data.Id)) != raw { - t.Fatalf("Raw mismatch: have %#q want %#q", []byte(*data.Id), raw) + if string([]byte(data.Id)) != raw { + t.Fatalf("Raw mismatch: have %#q want %#q", []byte(data.Id), raw) } b, err := Marshal(&data) if err != nil { @@ -217,20 +225,22 @@ func TestRawMessage(t *testing.T) { } func TestNullRawMessage(t *testing.T) { - // TODO(rsc): Should not need the * in *RawMessage var data struct { - X float64 - Id *RawMessage - Y float32 + X float64 + Id RawMessage + IdPtr *RawMessage + Y float32 } - data.Id = new(RawMessage) - const msg = `{"X":0.1,"Id":null,"Y":0.2}` + const msg = `{"X":0.1,"Id":null,"IdPtr":null,"Y":0.2}` err := Unmarshal([]byte(msg), &data) if err != nil { t.Fatalf("Unmarshal: %v", err) } - if data.Id != nil { - t.Fatalf("Raw mismatch: have non-nil, want nil") + if want, got := "null", string(data.Id); want != got { + t.Fatalf("Raw mismatch: have %q, want %q", got, want) + } + if data.IdPtr != nil { + t.Fatalf("Raw pointer mismatch: have non-nil, want nil") } b, err := Marshal(&data) if err != nil { diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go index 6a17516218..a1b5afac08 100644 --- a/src/encoding/pem/pem_test.go +++ b/src/encoding/pem/pem_test.go @@ -213,7 +213,9 @@ func TestFuzz(t *testing.T) { } testRoundtrip := func(block Block) bool { - if isBad(block.Type) { + // Reject bad Type + // Type with colons will proceed as key/val pair and cause an error. + if isBad(block.Type) || strings.Contains(block.Type, ":") { return true } for key, val := range block.Headers { diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 452caefab4..ca059440a1 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -167,9 +167,9 @@ type Decoder struct { // // Setting: // - // d.Strict = false; - // d.AutoClose = HTMLAutoClose; - // d.Entity = HTMLEntity + // d.Strict = false + // d.AutoClose = xml.HTMLAutoClose + // d.Entity = xml.HTMLEntity // // creates a parser that can handle typical HTML. // @@ -1581,7 +1581,9 @@ var second = &unicode.RangeTable{ // HTMLEntity is an entity map containing translations for the // standard HTML entity characters. -var HTMLEntity = htmlEntity +// +// See the Decoder.Strict and Decoder.Entity fields' documentation. +var HTMLEntity map[string]string = htmlEntity var htmlEntity = map[string]string{ /* @@ -1848,7 +1850,9 @@ var htmlEntity = map[string]string{ // HTMLAutoClose is the set of HTML elements that // should be considered to close automatically. -var HTMLAutoClose = htmlAutoClose +// +// See the Decoder.Strict and Decoder.Entity fields' documentation. +var HTMLAutoClose []string = htmlAutoClose var htmlAutoClose = []string{ /* diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go index 174873a7d4..b7928aab17 100644 --- a/src/expvar/expvar.go +++ b/src/expvar/expvar.go @@ -221,7 +221,7 @@ func (v *String) Value() string { return p } -// String implements the Val interface. To get the unquoted string +// String implements the Var interface. To get the unquoted string // use Value. func (v *String) String() string { s := v.Value() diff --git a/src/fmt/doc.go b/src/fmt/doc.go index f8e4766a65..3b657f3681 100644 --- a/src/fmt/doc.go +++ b/src/fmt/doc.go @@ -97,10 +97,11 @@ For floating-point values, width sets the minimum width of the field and precision sets the number of places after the decimal, if appropriate, - except that for %g/%G precision sets the total number of significant - digits. For example, given 12.345 the format %6.3f prints 12.345 while - %.3g prints 12.3. The default precision for %e, %f and %#g is 6; for %g it - is the smallest number of digits necessary to identify the value uniquely. + except that for %g/%G precision sets the maximum number of significant + digits (trailing zeros are removed). For example, given 12.345 the format + %6.3f prints 12.345 while %.3g prints 12.3. The default precision for %e, %f + and %#g is 6; for %g it is the smallest number of digits necessary to identify + the value uniquely. For complex numbers, the width and precision apply to the two components independently and the result is parenthesized, so %f applied diff --git a/src/fmt/example_test.go b/src/fmt/example_test.go index c77e78809c..1479b761b6 100644 --- a/src/fmt/example_test.go +++ b/src/fmt/example_test.go @@ -6,24 +6,97 @@ package fmt_test import ( "fmt" + "io" + "os" + "strings" ) -// Animal has a Name and an Age to represent an animal. -type Animal struct { - Name string - Age uint +// The Errorf function lets us use formatting features +// to create descriptive error messages. +func ExampleErrorf() { + const name, id = "bueller", 17 + err := fmt.Errorf("user %q (id %d) not found", name, id) + fmt.Println(err.Error()) + // Output: user "bueller" (id 17) not found } -// String makes Animal satisfy the Stringer interface. -func (a Animal) String() string { - return fmt.Sprintf("%v (%d)", a.Name, a.Age) -} - -func ExampleStringer() { - a := Animal{ - Name: "Gopher", - Age: 2, +func ExampleFscanf() { + var ( + i int + b bool + s string + ) + r := strings.NewReader("5 true gophers") + n, err := fmt.Fscanf(r, "%d %t %s", &i, &b, &s) + if err != nil { + panic(err) } - fmt.Println(a) - // Output: Gopher (2) + fmt.Println(i, b, s) + fmt.Println(n) + // Output: + // 5 true gophers + // 3 +} + +func ExampleSprintf() { + i := 30 + s := "Aug" + sf := fmt.Sprintf("Today is %d %s", i, s) + fmt.Println(sf) + fmt.Println(len(sf)) + // Output: + // Today is 30 Aug + // 15 +} + +func ExamplePrintln() { + n, err := fmt.Println("there", "are", 99, "gophers") + if err != nil { + panic(err) + } + fmt.Print(n) + // Output: + // there are 99 gophers + // 21 +} + +func ExampleSprintln() { + s := "Aug" + sl := fmt.Sprintln("Today is 30", s) + fmt.Printf("%q", sl) + // Output: + // "Today is 30 Aug\n" +} + +func ExampleFprintln() { + n, err := fmt.Fprintln(os.Stdout, "there", "are", 99, "gophers") + if err != nil { + panic(err) + } + fmt.Print(n) + // Output: + // there are 99 gophers + // 21 +} + +func ExampleFscanln() { + s := `dmr 1771 1.61803398875 + ken 271828 3.14159` + r := strings.NewReader(s) + var a string + var b int + var c float64 + for { + n, err := fmt.Fscanln(r, &a, &b, &c) + if err == io.EOF { + break + } + if err != nil { + panic(err) + } + fmt.Printf("%d: %s, %d, %f\n", n, a, b, c) + } + // Output: + // 3: dmr, 1771, 1.618034 + // 3: ken, 271828, 3.141590 } diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go index 08e46b4e93..9581becd32 100644 --- a/src/fmt/fmt_test.go +++ b/src/fmt/fmt_test.go @@ -690,6 +690,14 @@ var fmtTests = []struct { {"%#v", []int32(nil), "[]int32(nil)"}, {"%#v", 1.2345678, "1.2345678"}, {"%#v", float32(1.2345678), "1.2345678"}, + + // Whole number floats should have a single trailing zero added, but not + // for exponent notation. + {"%#v", 1.0, "1.0"}, + {"%#v", 1000000.0, "1e+06"}, + {"%#v", float32(1.0), "1.0"}, + {"%#v", float32(1000000.0), "1e+06"}, + // Only print []byte and []uint8 as type []byte if they appear at the top level. {"%#v", []byte(nil), "[]byte(nil)"}, {"%#v", []uint8(nil), "[]byte(nil)"}, @@ -861,13 +869,8 @@ var fmtTests = []struct { // Extra argument errors should format without flags set. {"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"}, - // The "" show up because maps are printed by - // first obtaining a list of keys and then looking up - // each key. Since NaNs can be map keys but cannot - // be fetched directly, the lookup fails and returns a - // zero reflect.Value, which formats as . - // This test is just to check that it shows the two NaNs at all. - {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN: NaN:]"}, + // Test that maps with non-reflexive keys print all keys and values. + {"%v", map[float64]int{NaN: 1, NaN: 1}, "map[NaN:1 NaN:1]"}, // Comparison of padding rules with C printf. /* @@ -1033,7 +1036,7 @@ var fmtTests = []struct { {"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(fmt_test.I=1) %!☠(fmt_test.G=2)]"}, {"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"}, {"%☠", reflect.Value{}, ""}, - {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠()]"}, + {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(int=1)]"}, } // zeroFill generates zero-filled strings of the specified width. The length diff --git a/src/fmt/format.go b/src/fmt/format.go index 91103f2c07..3a3cd8d1a1 100644 --- a/src/fmt/format.go +++ b/src/fmt/format.go @@ -481,15 +481,19 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { return } // The sharp flag forces printing a decimal point for non-binary formats - // and retains trailing zeros, which we may need to restore. - if f.sharp && verb != 'b' { + // and retains trailing zeros, which we may need to restore. For the sharpV + // flag, we ensure a single trailing zero is present if the output is not + // in exponent notation. + if f.sharpV || (f.sharp && verb != 'b') { digits := 0 - switch verb { - case 'v', 'g', 'G': - digits = prec - // If no precision is set explicitly use a precision of 6. - if digits == -1 { - digits = 6 + if !f.sharpV { + switch verb { + case 'g', 'G': + digits = prec + // If no precision is set explicitly use a precision of 6. + if digits == -1 { + digits = 6 + } } } @@ -498,25 +502,32 @@ func (f *fmt) fmtFloat(v float64, size int, verb rune, prec int) { var tailBuf [5]byte tail := tailBuf[:0] - hasDecimalPoint := false + var hasDecimalPoint, hasExponent bool // Starting from i = 1 to skip sign at num[0]. for i := 1; i < len(num); i++ { switch num[i] { case '.': hasDecimalPoint = true case 'e', 'E': + hasExponent = true tail = append(tail, num[i:]...) num = num[:i] default: digits-- } } - if !hasDecimalPoint { - num = append(num, '.') - } - for digits > 0 { - num = append(num, '0') - digits-- + if f.sharpV { + if !hasDecimalPoint && !hasExponent { + num = append(num, '.', '0') + } + } else { + if !hasDecimalPoint { + num = append(num, '.') + } + for digits > 0 { + num = append(num, '0') + digits-- + } } num = append(num, tail...) } diff --git a/src/fmt/gostringer_example_test.go b/src/fmt/gostringer_example_test.go new file mode 100644 index 0000000000..ab19ee3b94 --- /dev/null +++ b/src/fmt/gostringer_example_test.go @@ -0,0 +1,59 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fmt_test + +import ( + "fmt" +) + +// Address has a City, State and a Country. +type Address struct { + City string + State string + Country string +} + +// Person has a Name, Age and Address. +type Person struct { + Name string + Age uint + Addr *Address +} + +// GoString makes Person satisfy the GoStringer interface. +// The return value is valid Go code that can be used to reproduce the Person struct. +func (p Person) GoString() string { + if p.Addr != nil { + return fmt.Sprintf("Person{Name: %q, Age: %d, Addr: &Address{City: %q, State: %q, Country: %q}}", p.Name, int(p.Age), p.Addr.City, p.Addr.State, p.Addr.Country) + } + return fmt.Sprintf("Person{Name: %q, Age: %d}", p.Name, int(p.Age)) +} + +func ExampleGoStringer() { + p1 := Person{ + Name: "Warren", + Age: 31, + Addr: &Address{ + City: "Denver", + State: "CO", + Country: "U.S.A.", + }, + } + // If GoString() wasn't implemented, the output of `fmt.Printf("%#v", p1)` would be similar to + // Person{Name:"Warren", Age:0x1f, Addr:(*main.Address)(0x10448240)} + fmt.Printf("%#v\n", p1) + + p2 := Person{ + Name: "Theia", + Age: 4, + } + // If GoString() wasn't implemented, the output of `fmt.Printf("%#v", p2)` would be similar to + // Person{Name:"Theia", Age:0x4, Addr:(*main.Address)(nil)} + fmt.Printf("%#v\n", p2) + + // Output: + // Person{Name: "Warren", Age: 31, Addr: &Address{City: "Denver", State: "CO", Country: "U.S.A."}} + // Person{Name: "Theia", Age: 4} +} diff --git a/src/fmt/print.go b/src/fmt/print.go index f67f805603..c9d694b07d 100644 --- a/src/fmt/print.go +++ b/src/fmt/print.go @@ -743,8 +743,8 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { } else { p.buf.WriteString(mapString) } - keys := f.MapKeys() - for i, key := range keys { + iter := f.MapRange() + for i := 0; iter.Next(); i++ { if i > 0 { if p.fmt.sharpV { p.buf.WriteString(commaSpaceString) @@ -752,9 +752,9 @@ func (p *pp) printValue(value reflect.Value, verb rune, depth int) { p.buf.WriteByte(' ') } } - p.printValue(key, verb, depth+1) + p.printValue(iter.Key(), verb, depth+1) p.buf.WriteByte(':') - p.printValue(f.MapIndex(key), verb, depth+1) + p.printValue(iter.Value(), verb, depth+1) } if p.fmt.sharpV { p.buf.WriteByte('}') diff --git a/src/fmt/stringer_example_test.go b/src/fmt/stringer_example_test.go new file mode 100644 index 0000000000..c77e78809c --- /dev/null +++ b/src/fmt/stringer_example_test.go @@ -0,0 +1,29 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package fmt_test + +import ( + "fmt" +) + +// Animal has a Name and an Age to represent an animal. +type Animal struct { + Name string + Age uint +} + +// String makes Animal satisfy the Stringer interface. +func (a Animal) String() string { + return fmt.Sprintf("%v (%d)", a.Name, a.Age) +} + +func ExampleStringer() { + a := Animal{ + Name: "Gopher", + Age: 2, + } + fmt.Println(a) + // Output: Gopher (2) +} diff --git a/src/go/build/build.go b/src/go/build/build.go index b19df28a63..b68a712a7d 100644 --- a/src/go/build/build.go +++ b/src/go/build/build.go @@ -16,6 +16,7 @@ import ( "io/ioutil" "log" "os" + "os/exec" pathpkg "path" "path/filepath" "runtime" @@ -277,6 +278,8 @@ func defaultGOPATH() string { return "" } +var defaultReleaseTags []string + func defaultContext() Context { var c Context @@ -297,6 +300,8 @@ func defaultContext() Context { c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i)) } + defaultReleaseTags = append([]string{}, c.ReleaseTags...) // our own private copy + env := os.Getenv("CGO_ENABLED") if env == "" { env = defaultCGO_ENABLED @@ -583,13 +588,19 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa return p, fmt.Errorf("import %q: cannot import absolute path", path) } + gopath := ctxt.gopath() // needed by both importGo and below; avoid computing twice + if err := ctxt.importGo(p, path, srcDir, mode, gopath); err == nil { + goto Found + } else if err != errNoModules { + return p, err + } + // tried records the location of unsuccessful package lookups var tried struct { vendor []string goroot string gopath []string } - gopath := ctxt.gopath() // Vendor directories get first chance to satisfy import. if mode&IgnoreVendor == 0 && srcDir != "" { @@ -930,6 +941,116 @@ Found: return p, pkgerr } +var errNoModules = errors.New("not using modules") + +// importGo checks whether it can use the go command to find the directory for path. +// If using the go command is not appopriate, importGo returns errNoModules. +// Otherwise, importGo tries using the go command and reports whether that succeeded. +// Using the go command lets build.Import and build.Context.Import find code +// in Go modules. In the long term we want tools to use go/packages (currently golang.org/x/tools/go/packages), +// which will also use the go command. +// Invoking the go command here is not very efficient in that it computes information +// about the requested package and all dependencies and then only reports about the requested package. +// Then we reinvoke it for every dependency. But this is still better than not working at all. +// See golang.org/issue/26504. +func (ctxt *Context) importGo(p *Package, path, srcDir string, mode ImportMode, gopath []string) error { + const debugImportGo = false + + // To invoke the go command, we must know the source directory, + // we must not being doing special things like AllowBinary or IgnoreVendor, + // and all the file system callbacks must be nil (we're meant to use the local file system). + if srcDir == "" || mode&AllowBinary != 0 || mode&IgnoreVendor != 0 || + ctxt.JoinPath != nil || ctxt.SplitPathList != nil || ctxt.IsAbsPath != nil || ctxt.IsDir != nil || ctxt.HasSubdir != nil || ctxt.ReadDir != nil || ctxt.OpenFile != nil || !equal(ctxt.ReleaseTags, defaultReleaseTags) { + return errNoModules + } + + // If modules are not enabled, then the in-process code works fine and we should keep using it. + switch os.Getenv("GO111MODULE") { + case "off": + return errNoModules + case "on": + // ok + default: // "", "auto", anything else + // Automatic mode: no module use in $GOPATH/src. + for _, root := range gopath { + sub, ok := ctxt.hasSubdir(root, srcDir) + if ok && strings.HasPrefix(sub, "src/") { + return errNoModules + } + } + } + + // For efficiency, if path is a standard library package, let the usual lookup code handle it. + if ctxt.GOROOT != "" { + dir := ctxt.joinPath(ctxt.GOROOT, "src", path) + if ctxt.isDir(dir) { + return errNoModules + } + } + + // Look to see if there is a go.mod. + abs, err := filepath.Abs(srcDir) + if err != nil { + return errNoModules + } + for { + info, err := os.Stat(filepath.Join(abs, "go.mod")) + if err == nil && !info.IsDir() { + break + } + d := filepath.Dir(abs) + if len(d) >= len(abs) { + return errNoModules // reached top of file system, no go.mod + } + abs = d + } + + cmd := exec.Command("go", "list", "-compiler="+ctxt.Compiler, "-tags="+strings.Join(ctxt.BuildTags, ","), "-installsuffix="+ctxt.InstallSuffix, "-f={{.Dir}}\n{{.ImportPath}}\n{{.Root}}\n{{.Goroot}}\n", path) + cmd.Dir = srcDir + var stdout, stderr strings.Builder + cmd.Stdout = &stdout + cmd.Stderr = &stderr + + cgo := "0" + if ctxt.CgoEnabled { + cgo = "1" + } + cmd.Env = append(os.Environ(), + "GOOS="+ctxt.GOOS, + "GOARCH="+ctxt.GOARCH, + "GOROOT="+ctxt.GOROOT, + "GOPATH="+ctxt.GOPATH, + "CGO_ENABLED="+cgo, + ) + + if err := cmd.Run(); err != nil { + return fmt.Errorf("go/build: importGo %s: %v\n%s\n", path, err, stderr.String()) + } + + f := strings.Split(stdout.String(), "\n") + if len(f) != 5 || f[4] != "" { + return fmt.Errorf("go/build: importGo %s: unexpected output:\n%s\n", path, stdout.String()) + } + + p.Dir = f[0] + p.ImportPath = f[1] + p.Root = f[2] + p.Goroot = f[3] == "true" + return nil +} + +func equal(x, y []string) bool { + if len(x) != len(y) { + return false + } + for i, xi := range x { + if xi != y[i] { + return false + } + } + return true +} + // hasGoFiles reports whether dir contains any files with names ending in .go. // For a vendor check we must exclude directories that contain no .go files. // Otherwise it is not possible to vendor just a/b/c and still import the @@ -1384,7 +1505,8 @@ func (ctxt *Context) makePathsAbsolute(args []string, srcDir string) { // See golang.org/issue/6038. // The @ is for OS X. See golang.org/issue/13720. // The % is for Jenkins. See golang.org/issue/16959. -const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@% " +// The ! is because module paths may use them. See golang.org/issue/26716. +const safeString = "+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:$@%! " func safeCgoName(s string) bool { if s == "" { diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 08ab218610..f0e584585b 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -38,7 +38,7 @@ var pkgDeps = map[string][]string{ "io": {"errors", "sync", "sync/atomic"}, "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "internal/cpu", "internal/bytealg"}, "runtime/internal/sys": {}, - "runtime/internal/atomic": {"unsafe", "runtime/internal/sys"}, + "runtime/internal/atomic": {"unsafe", "internal/cpu"}, "internal/race": {"runtime", "unsafe"}, "sync": {"internal/race", "runtime", "sync/atomic", "unsafe"}, "sync/atomic": {"unsafe"}, @@ -100,7 +100,7 @@ var pkgDeps = map[string][]string{ // and interface definitions, but nothing that makes // system calls. "crypto": {"L2", "hash"}, // interfaces - "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"}, + "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle", "encoding/binary"}, "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag "crypto/subtle": {}, "encoding/base32": {"L2"}, @@ -211,7 +211,7 @@ var pkgDeps = map[string][]string{ // Go parser. "go/ast": {"L4", "OS", "go/scanner", "go/token"}, - "go/doc": {"L4", "go/ast", "go/token", "regexp", "text/template"}, + "go/doc": {"L4", "OS", "go/ast", "go/token", "regexp", "text/template"}, "go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"}, "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"}, "go/scanner": {"L4", "OS", "go/token"}, diff --git a/src/go/doc/comment.go b/src/go/doc/comment.go index 4228e8cd9c..d9268b87fb 100644 --- a/src/go/doc/comment.go +++ b/src/go/doc/comment.go @@ -8,7 +8,6 @@ package doc import ( "io" - "regexp" "strings" "text/template" // for HTMLEscape "unicode" @@ -63,7 +62,7 @@ const ( urlRx = protoPart + `://` + hostPart + pathPart ) -var matchRx = regexp.MustCompile(`(` + urlRx + `)|(` + identRx + `)`) +var matchRx = newLazyRE(`(` + urlRx + `)|(` + identRx + `)`) var ( html_a = []byte(`\\") { + // exclude lines with illegal characters. we allow "()," + if strings.ContainsAny(line, ";:!?+*/=[]{}_^°&§~%#@<\">\\") { return "" } @@ -248,6 +247,18 @@ func heading(line string) string { b = b[i+2:] } + // allow "." when followed by non-space + for b := line;; { + i := strings.IndexRune(b, '.') + if i < 0 { + break + } + if i+1 >= len(b) || b[i+1] == ' ' { + return "" // not followed by non-space + } + b = b[i+1:] + } + return line } @@ -264,7 +275,7 @@ type block struct { lines []string } -var nonAlphaNumRx = regexp.MustCompile(`[^a-zA-Z0-9]`) +var nonAlphaNumRx = newLazyRE(`[^a-zA-Z0-9]`) func anchorID(line string) string { // Add a "hdr-" prefix to avoid conflicting with IDs used for package symbols. @@ -281,7 +292,7 @@ func anchorID(line string) string { // a single paragraph. There is one exception to the rule: a span that // consists of a single line, is followed by another paragraph span, // begins with a capital letter, and contains no punctuation -// is formatted as a heading. +// other than parentheses and commas is formatted as a heading. // // A span of indented lines is converted into a
     block,
     // with the common indent prefix removed.
    diff --git a/src/go/doc/doc_test.go b/src/go/doc/doc_test.go
    index ad8ba5378f..902a79f63f 100644
    --- a/src/go/doc/doc_test.go
    +++ b/src/go/doc/doc_test.go
    @@ -144,3 +144,12 @@ func Test(t *testing.T) {
     	test(t, AllDecls)
     	test(t, AllMethods)
     }
    +
    +func TestAnchorID(t *testing.T) {
    +	const in = "Important Things 2 Know & Stuff"
    +	const want = "hdr-Important_Things_2_Know___Stuff"
    +	got := anchorID(in)
    +	if got != want {
    +		t.Errorf("anchorID(%q) = %q; want %q", in, got, want)
    +	}
    +}
    diff --git a/src/go/doc/example.go b/src/go/doc/example.go
    index 7fc6dedf7f..5b40bb0fb2 100644
    --- a/src/go/doc/example.go
    +++ b/src/go/doc/example.go
    @@ -56,7 +56,7 @@ func Examples(files ...*ast.File) []*Example {
     				continue
     			}
     			f, ok := decl.(*ast.FuncDecl)
    -			if !ok {
    +			if !ok || f.Recv != nil {
     				continue
     			}
     			numDecl++
    @@ -188,7 +188,7 @@ func playExample(file *ast.File, f *ast.FuncDecl) *ast.File {
     	inspectFunc = func(n ast.Node) bool {
     		switch e := n.(type) {
     		case *ast.Ident:
    -			if e.Obj == nil {
    +			if e.Obj == nil && e.Name != "_" {
     				unresolved[e.Name] = true
     			} else if d := topDecls[e.Obj]; d != nil {
     				if !hasDepDecls[d] {
    diff --git a/src/go/doc/example_test.go b/src/go/doc/example_test.go
    index f0c3000504..552a51bf74 100644
    --- a/src/go/doc/example_test.go
    +++ b/src/go/doc/example_test.go
    @@ -6,6 +6,7 @@ package doc_test
     
     import (
     	"bytes"
    +	"go/ast"
     	"go/doc"
     	"go/format"
     	"go/parser"
    @@ -280,16 +281,7 @@ func TestExamples(t *testing.T) {
     			t.Errorf("got Name == %q, want %q", e.Name, c.Name)
     		}
     		if w := c.Play; w != "" {
    -			var g string // hah
    -			if e.Play == nil {
    -				g = ""
    -			} else {
    -				var buf bytes.Buffer
    -				if err := format.Node(&buf, fset, e.Play); err != nil {
    -					t.Fatal(err)
    -				}
    -				g = buf.String()
    -			}
    +			g := formatFile(t, fset, e.Play)
     			if g != w {
     				t.Errorf("%s: got Play == %q, want %q", c.Name, g, w)
     			}
    @@ -299,3 +291,73 @@ func TestExamples(t *testing.T) {
     		}
     	}
     }
    +
    +const exampleWholeFile = `package foo_test
    +
    +type X int
    +
    +func (X) Foo() {
    +}
    +
    +func (X) TestBlah() {
    +}
    +
    +func (X) BenchmarkFoo() {
    +}
    +
    +func Example() {
    +	fmt.Println("Hello, world!")
    +	// Output: Hello, world!
    +}
    +`
    +
    +const exampleWholeFileOutput = `package main
    +
    +type X int
    +
    +func (X) Foo() {
    +}
    +
    +func (X) TestBlah() {
    +}
    +
    +func (X) BenchmarkFoo() {
    +}
    +
    +func main() {
    +	fmt.Println("Hello, world!")
    +}
    +`
    +
    +func TestExamplesWholeFile(t *testing.T) {
    +	fset := token.NewFileSet()
    +	file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleWholeFile), parser.ParseComments)
    +	if err != nil {
    +		t.Fatal(err)
    +	}
    +	es := doc.Examples(file)
    +	if len(es) != 1 {
    +		t.Fatalf("wrong number of examples; got %d want 1", len(es))
    +	}
    +	e := es[0]
    +	if e.Name != "" {
    +		t.Errorf("got Name == %q, want %q", e.Name, "")
    +	}
    +	if g, w := formatFile(t, fset, e.Play), exampleWholeFileOutput; g != w {
    +		t.Errorf("got Play == %q, want %q", g, w)
    +	}
    +	if g, w := e.Output, "Hello, world!\n"; g != w {
    +		t.Errorf("got Output == %q, want %q", g, w)
    +	}
    +}
    +
    +func formatFile(t *testing.T, fset *token.FileSet, n *ast.File) string {
    +	if n == nil {
    +		return ""
    +	}
    +	var buf bytes.Buffer
    +	if err := format.Node(&buf, fset, n); err != nil {
    +		t.Fatal(err)
    +	}
    +	return buf.String()
    +}
    diff --git a/src/go/doc/lazyre.go b/src/go/doc/lazyre.go
    new file mode 100644
    index 0000000000..3fd97d42de
    --- /dev/null
    +++ b/src/go/doc/lazyre.go
    @@ -0,0 +1,51 @@
    +// Copyright 2018 The Go Authors. All rights reserved.
    +// Use of this source code is governed by a BSD-style
    +// license that can be found in the LICENSE file.
    +
    +package doc
    +
    +import (
    +	"os"
    +	"regexp"
    +	"strings"
    +	"sync"
    +)
    +
    +type lazyRE struct {
    +	str  string
    +	once sync.Once
    +	rx   *regexp.Regexp
    +}
    +
    +func (r *lazyRE) re() *regexp.Regexp {
    +	r.once.Do(r.build)
    +	return r.rx
    +}
    +
    +func (r *lazyRE) build() {
    +	r.rx = regexp.MustCompile(r.str)
    +	r.str = ""
    +}
    +
    +func (r *lazyRE) FindStringSubmatchIndex(s string) []int {
    +	return r.re().FindStringSubmatchIndex(s)
    +}
    +
    +func (r *lazyRE) ReplaceAllString(src, repl string) string {
    +	return r.re().ReplaceAllString(src, repl)
    +}
    +
    +func (r *lazyRE) MatchString(s string) bool {
    +	return r.re().MatchString(s)
    +}
    +
    +var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test")
    +
    +func newLazyRE(str string) *lazyRE {
    +	lr := &lazyRE{str: str}
    +	if inTest {
    +		// In tests, always compile the regexps early.
    +		lr.re()
    +	}
    +	return lr
    +}
    diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go
    index 21c02920ab..21d5907a03 100644
    --- a/src/go/doc/reader.go
    +++ b/src/go/doc/reader.go
    @@ -7,7 +7,6 @@ package doc
     import (
     	"go/ast"
     	"go/token"
    -	"regexp"
     	"sort"
     	"strconv"
     )
    @@ -425,9 +424,9 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
     }
     
     var (
    -	noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`                    // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
    -	noteMarkerRx  = regexp.MustCompile(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start
    -	noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
    +	noteMarker    = `([A-Z][A-Z]+)\(([^)]+)\):?`           // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
    +	noteMarkerRx  = newLazyRE(`^[ \t]*` + noteMarker)      // MARKER(uid) at text start
    +	noteCommentRx = newLazyRE(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
     )
     
     // readNote collects a single note from a sequence of comments.
    diff --git a/src/go/format/format.go b/src/go/format/format.go
    index cad5958e5c..9aa28fc63b 100644
    --- a/src/go/format/format.go
    +++ b/src/go/format/format.go
    @@ -3,6 +3,15 @@
     // license that can be found in the LICENSE file.
     
     // Package format implements standard formatting of Go source.
    +//
    +// Note that formatting of Go source code changes over time, so tools relying on
    +// consistent formatting should execute a specific version of the gofmt binary
    +// instead of using this package. That way, the formatting will be stable, and
    +// the tools won't need to be recompiled each time gofmt changes.
    +//
    +// For example, pre-submit checks that use this package directly would behave
    +// differently depending on what Go version each developer uses, causing the
    +// check to be inherently fragile.
     package format
     
     import (
    @@ -79,10 +88,6 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
     // space as src), and the result is indented by the same amount as the first
     // line of src containing code. Imports are not sorted for partial source files.
     //
    -// Caution: Tools relying on consistent formatting based on the installed
    -// version of gofmt (for instance, such as for presubmit checks) should
    -// execute that gofmt binary instead of calling Source.
    -//
     func Source(src []byte) ([]byte, error) {
     	fset := token.NewFileSet()
     	file, sourceAdj, indentAdj, err := parse(fset, "", src, true)
    diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
    index 18f2371d24..1de7cd81b2 100644
    --- a/src/go/printer/nodes.go
    +++ b/src/go/printer/nodes.go
    @@ -32,8 +32,10 @@ import (
     
     // Print as many newlines as necessary (but at least min newlines) to get to
     // the current line. ws is printed before the first line break. If newSection
    -// is set, the first line break is printed as formfeed. Returns true if any
    -// line break was printed; returns false otherwise.
    +// is set, the first line break is printed as formfeed. Returns 0 if no line
    +// breaks were printed, returns 1 if there was exactly one newline printed,
    +// and returns a value > 1 if there was a formfeed or more than one newline
    +// printed.
     //
     // TODO(gri): linebreak may add too many lines if the next statement at "line"
     //            is preceded by comments because the computation of n assumes
    @@ -43,7 +45,7 @@ import (
     //            linebreaks. At the moment there is no easy way to know about
     //            future (not yet interspersed) comments in this function.
     //
    -func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (printedBreak bool) {
    +func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (nbreaks int) {
     	n := nlimit(line - p.pos.Line)
     	if n < min {
     		n = min
    @@ -53,11 +55,12 @@ func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (prin
     		if newSection {
     			p.print(formfeed)
     			n--
    +			nbreaks = 2
     		}
    +		nbreaks += n
     		for ; n > 0; n-- {
     			p.print(newline)
     		}
    -		printedBreak = true
     	}
     	return
     }
    @@ -173,7 +176,7 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
     	// The first linebreak is always a formfeed since this section must not
     	// depend on any previous formatting.
     	prevBreak := -1 // index of last expression that was followed by a linebreak
    -	if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) {
    +	if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) > 0 {
     		ws = ignore
     		prevBreak = 0
     	}
    @@ -234,14 +237,6 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
     				useFF = r*ratio <= 1 || r <= ratio
     			}
     		}
    -		if useFF {
    -			lnsum = 0
    -			count = 0
    -		}
    -		if size > 0 {
    -			lnsum += math.Log(float64(size))
    -			count++
    -		}
     
     		needsLinebreak := 0 < prevLine && prevLine < line
     		if i > 0 {
    @@ -257,11 +252,20 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
     				// Lines are broken using newlines so comments remain aligned
     				// unless useFF is set or there are multiple expressions on
     				// the same line in which case formfeed is used.
    -				if p.linebreak(line, 0, ws, useFF || prevBreak+1 < i) {
    +				nbreaks := p.linebreak(line, 0, ws, useFF || prevBreak+1 < i)
    +				if nbreaks > 0 {
     					ws = ignore
     					prevBreak = i
     					needsBlank = false // we got a line break instead
     				}
    +				// If there was a new section or more than one new line
    +				// (which means that the tabwriter will implicitly break
    +				// the section), reset the geomean variables since we are
    +				// starting a new group of elements with the next element.
    +				if nbreaks > 1 {
    +					lnsum = 0
    +					count = 0
    +				}
     			}
     			if needsBlank {
     				p.print(blank)
    @@ -281,6 +285,11 @@ func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exp
     			p.expr0(x, depth)
     		}
     
    +		if size > 0 {
    +			lnsum += math.Log(float64(size))
    +			count++
    +		}
    +
     		prevLine = line
     	}
     
    @@ -338,7 +347,7 @@ func (p *printer) parameters(fields *ast.FieldList) {
     				p.print(token.COMMA)
     			}
     			// separator if needed (linebreak or blank)
    -			if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) {
    +			if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
     				// break line if the opening "(" or previous parameter ended on a different line
     				ws = ignore
     			} else if i > 0 {
    @@ -709,7 +718,7 @@ func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
     	if xline != yline && xline > 0 && yline > 0 {
     		// at least one line break, but respect an extra empty line
     		// in the source
    -		if p.linebreak(yline, 1, ws, true) {
    +		if p.linebreak(yline, 1, ws, true) > 0 {
     			ws = ignore
     			printBlank = false // no blank after line break
     		}
    diff --git a/src/go/printer/testdata/alignment.golden b/src/go/printer/testdata/alignment.golden
    index c65defe6ae..96086ed906 100644
    --- a/src/go/printer/testdata/alignment.golden
    +++ b/src/go/printer/testdata/alignment.golden
    @@ -128,3 +128,45 @@ func main() {
     		abcdefghijklmnopqrstuvwxyz:		"foo",
     	}
     }
    +
    +// ----------------------------------------------------------------------------
    +// Examples from issue #26352.
    +
    +var _ = map[int]string{
    +	1:	"",
    +
    +	12345678901234567890123456789:		"",
    +	12345678901234567890123456789012345678:	"",
    +}
    +
    +func f() {
    +	_ = map[int]string{
    +		1:	"",
    +
    +		12345678901234567:				"",
    +		12345678901234567890123456789012345678901:	"",
    +	}
    +}
    +
    +// ----------------------------------------------------------------------------
    +// Examples from issue #26930.
    +
    +var _ = S{
    +	F1:	[]string{},
    +	F2____:	[]string{},
    +}
    +
    +var _ = S{
    +	F1:	[]string{},
    +	F2____:	[]string{},
    +}
    +
    +var _ = S{
    +	F1____:	[]string{},
    +	F2:	[]string{},
    +}
    +
    +var _ = S{
    +	F1____:	[]string{},
    +	F2:	[]string{},
    +}
    diff --git a/src/go/printer/testdata/alignment.input b/src/go/printer/testdata/alignment.input
    index 9b0aae6bec..323d2689e0 100644
    --- a/src/go/printer/testdata/alignment.input
    +++ b/src/go/printer/testdata/alignment.input
    @@ -128,3 +128,52 @@ func main() {
     		abcdefghijklmnopqrstuvwxyz: "foo",
     	}
     }
    +
    +// ----------------------------------------------------------------------------
    +// Examples from issue #26352.
    +
    +var _ = map[int]string{
    +	1: "",
    +
    +	12345678901234567890123456789: "",
    +	12345678901234567890123456789012345678: "",
    +}
    +
    +func f() {
    +	_ = map[int]string{
    +		1: "",
    +
    +		12345678901234567: "",
    +		12345678901234567890123456789012345678901: "",
    +	}
    +}
    +
    +// ----------------------------------------------------------------------------
    +// Examples from issue #26930.
    +
    +var _ = S{
    +	F1: []string{
    +	},
    +	F2____: []string{},
    +}
    +
    +var _ = S{
    +	F1: []string{
    +
    +
    +	},
    +	F2____: []string{},
    +}
    +
    +var _ = S{
    +	F1____: []string{
    +	},
    +	F2: []string{},
    +}
    +
    +var _ = S{
    +	F1____: []string{
    +
    +	},
    +	F2: []string{},
    +}
    diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
    index 9f5855662d..23bbb2885f 100644
    --- a/src/go/scanner/scanner.go
    +++ b/src/go/scanner/scanner.go
    @@ -259,6 +259,14 @@ func (s *Scanner) updateLineInfo(next, offs int, text []byte) {
     	filename := string(text[:i-1]) // lop off ":line", and trim white space
     	if filename == "" && ok2 {
     		filename = s.file.Position(s.file.Pos(offs)).Filename
    +	} else if filename != "" {
    +		// Put a relative filename in the current directory.
    +		// This is for compatibility with earlier releases.
    +		// See issue 26671.
    +		filename = filepath.Clean(filename)
    +		if !filepath.IsAbs(filename) {
    +			filename = filepath.Join(s.dir, filename)
    +		}
     	}
     
     	s.file.AddLineColumnInfo(next, filename, line, col)
    diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
    index 7cc79fa820..0aad368099 100644
    --- a/src/go/scanner/scanner_test.go
    +++ b/src/go/scanner/scanner_test.go
    @@ -9,6 +9,7 @@ import (
     	"io/ioutil"
     	"os"
     	"path/filepath"
    +	"runtime"
     	"testing"
     )
     
    @@ -204,7 +205,9 @@ func newlineCount(s string) int {
     
     func checkPos(t *testing.T, lit string, p token.Pos, expected token.Position) {
     	pos := fset.Position(p)
    -	if pos.Filename != expected.Filename {
    +	// Check cleaned filenames so that we don't have to worry about
    +	// different os.PathSeparator values.
    +	if pos.Filename != expected.Filename && filepath.Clean(pos.Filename) != filepath.Clean(expected.Filename) {
     		t.Errorf("bad filename for %q: got %s, expected %s", lit, pos.Filename, expected.Filename)
     	}
     	if pos.Offset != expected.Offset {
    @@ -520,7 +523,7 @@ var segments = []segment{
     	{"\n //line foo:42\n  line43", "foo\t", 44, 0}, // bad line comment, ignored (use existing, prior filename)
     	{"\n//line foo 42\n  line44", "foo\t", 46, 0},  // bad line comment, ignored (use existing, prior filename)
     	{"\n//line /bar:42\n  line45", "/bar", 42, 0},
    -	{"\n//line ./foo:42\n  line46", "./foo", 42, 0},
    +	{"\n//line ./foo:42\n  line46", "foo", 42, 0},
     	{"\n//line a/b/c/File1.go:100\n  line100", "a/b/c/File1.go", 100, 0},
     	{"\n//line c:\\bar:42\n  line200", "c:\\bar", 42, 0},
     	{"\n//line c:\\dir\\File1.go:100\n  line201", "c:\\dir\\File1.go", 100, 0},
    @@ -539,9 +542,32 @@ var segments = []segment{
     	{"\n/*line foo:100:10*/\n\nf2", "foo", 102, 1},  // absolute column since on new line
     }
     
    +var dirsegments = []segment{
    +	// exactly one token per line since the test consumes one token per segment
    +	{"  line1", "TestLineDir/TestLineDirectives", 1, 3},
    +	{"\n//line File1.go:100\n  line100", "TestLineDir/File1.go", 100, 0},
    +}
    +
    +var dirUnixSegments = []segment{
    +	{"\n//line /bar:42\n  line42", "/bar", 42, 0},
    +}
    +
    +var dirWindowsSegments = []segment{
    +	{"\n//line c:\\bar:42\n  line42", "c:\\bar", 42, 0},
    +}
    +
     // Verify that line directives are interpreted correctly.
     func TestLineDirectives(t *testing.T) {
    -	// make source
    +	testSegments(t, segments, "TestLineDirectives")
    +	testSegments(t, dirsegments, "TestLineDir/TestLineDirectives")
    +	if runtime.GOOS == "windows" {
    +		testSegments(t, dirWindowsSegments, "TestLineDir/TestLineDirectives")
    +	} else {
    +		testSegments(t, dirUnixSegments, "TestLineDir/TestLineDirectives")
    +	}
    +}
    +
    +func testSegments(t *testing.T, segments []segment, filename string) {
     	var src string
     	for _, e := range segments {
     		src += e.srcline
    @@ -549,7 +575,7 @@ func TestLineDirectives(t *testing.T) {
     
     	// verify scan
     	var S Scanner
    -	file := fset.AddFile("TestLineDirectives", fset.Base(), len(src))
    +	file := fset.AddFile(filename, fset.Base(), len(src))
     	S.Init(file, []byte(src), func(pos token.Position, msg string) { t.Error(Error{pos, msg}) }, dontInsertSemis)
     	for _, s := range segments {
     		p, _, lit := S.Scan()
    diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
    index 1d3c32520a..c34ecbf9d1 100644
    --- a/src/go/types/api_test.go
    +++ b/src/go/types/api_test.go
    @@ -26,7 +26,6 @@ func pkgFor(path, source string, info *Info) (*Package, error) {
     	if err != nil {
     		return nil, err
     	}
    -
     	conf := Config{Importer: importer.Default()}
     	return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
     }
    @@ -43,6 +42,20 @@ func mustTypecheck(t *testing.T, path, source string, info *Info) string {
     	return pkg.Name()
     }
     
    +func mayTypecheck(t *testing.T, path, source string, info *Info) string {
    +	fset := token.NewFileSet()
    +	f, err := parser.ParseFile(fset, path, source, 0)
    +	if f == nil { // ignore errors unless f is nil
    +		t.Fatalf("%s: unable to parse: %s", path, err)
    +	}
    +	conf := Config{
    +		Error:    func(err error) {},
    +		Importer: importer.Default(),
    +	}
    +	pkg, _ := conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
    +	return pkg.Name()
    +}
    +
     func TestValuesInfo(t *testing.T) {
     	var tests = []struct {
     		src  string
    @@ -243,11 +256,19 @@ func TestTypesInfo(t *testing.T) {
     			`<-ch`,
     			`(string, bool)`,
     		},
    +
    +		// tests for broken code that doesn't parse or type-check
    +		{`package x0; func _() { var x struct {f string}; x.f := 0 }`, `x.f`, `string`},
    +		{`package x1; func _() { var z string; type x struct {f string}; y := &x{q: z}}`, `z`, `string`},
    +		{`package x2; func _() { var a, b string; type x struct {f string}; z := &x{f: a; f: b;}}`, `b`, `string`},
    +		{`package x3; var x = panic("");`, `panic`, `func(interface{})`},
    +		{`package x4; func _() { panic("") }`, `panic`, `func(interface{})`},
    +		{`package x5; func _() { var x map[string][...]int; x = map[string][...]int{"": {1,2,3}} }`, `x`, `map[string][-1]int`},
     	}
     
     	for _, test := range tests {
     		info := Info{Types: make(map[ast.Expr]TypeAndValue)}
    -		name := mustTypecheck(t, "TypesInfo", test.src, &info)
    +		name := mayTypecheck(t, "TypesInfo", test.src, &info)
     
     		// look for expression type
     		var typ Type
    diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
    index cb0fe3bc3a..27002f6699 100644
    --- a/src/go/types/assignments.go
    +++ b/src/go/types/assignments.go
    @@ -310,6 +310,7 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
     				check.recordDef(ident, obj)
     			}
     		} else {
    +			check.useLHS(lhs)
     			check.errorf(lhs.Pos(), "cannot declare %s", lhs)
     		}
     		if obj == nil {
    diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
    index 05e032423c..d3f0c4d40d 100644
    --- a/src/go/types/builtins.go
    +++ b/src/go/types/builtins.go
    @@ -476,7 +476,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
     		// panic(x)
     		// record panic call if inside a function with result parameters
     		// (for use in Checker.isTerminating)
    -		if check.sig.results.Len() > 0 {
    +		if check.sig != nil && check.sig.results.Len() > 0 {
     			// function has result parameters
     			p := check.isPanic
     			if p == nil {
    diff --git a/src/go/types/call.go b/src/go/types/call.go
    index 1b40651b73..d5c196afe8 100644
    --- a/src/go/types/call.go
    +++ b/src/go/types/call.go
    @@ -34,6 +34,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
     				check.conversion(x, T)
     			}
     		default:
    +			check.use(e.Args...)
     			check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
     		}
     		x.expr = e
    diff --git a/src/go/types/check.go b/src/go/types/check.go
    index 286b1f36a9..91df94dcbc 100644
    --- a/src/go/types/check.go
    +++ b/src/go/types/check.go
    @@ -76,7 +76,7 @@ type Checker struct {
     	fset *token.FileSet
     	pkg  *Package
     	*Info
    -	objMap map[Object]*declInfo   // maps package-level object to declaration info
    +	objMap map[Object]*declInfo   // maps package-level objects and (non-interface) methods to declaration info
     	impMap map[importKey]*Package // maps (import path, source directory) to (complete or fake) package
     
     	// information collected during type-checking of a set of package files
    @@ -160,18 +160,6 @@ func (check *Checker) pop() Object {
     	return obj
     }
     
    -// pathString returns a string of the form a->b-> ... ->g for an object path [a, b, ... g].
    -func (check *Checker) pathString() string {
    -	var s string
    -	for i, p := range check.objPath {
    -		if i > 0 {
    -			s += "->"
    -		}
    -		s += p.Name()
    -	}
    -	return s
    -}
    -
     // NewChecker returns a new Checker instance for a given package.
     // Package files may be added incrementally via checker.Files.
     func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
    diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
    index fb18ac87d2..2bdfc150f4 100644
    --- a/src/go/types/check_test.go
    +++ b/src/go/types/check_test.go
    @@ -91,6 +91,7 @@ var tests = [][]string{
     	{"testdata/issues.src"},
     	{"testdata/blank.src"},
     	{"testdata/issue25008b.src", "testdata/issue25008a.src"}, // order (b before a) is crucial!
    +	{"testdata/issue26390.src"},                              // stand-alone test to ensure case is triggered
     }
     
     var fset = token.NewFileSet()
    diff --git a/src/go/types/decl.go b/src/go/types/decl.go
    index e8e01541a3..d37a460a4e 100644
    --- a/src/go/types/decl.go
    +++ b/src/go/types/decl.go
    @@ -38,6 +38,8 @@ func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token
     }
     
     // pathString returns a string of the form a->b-> ... ->g for a path [a, b, ... g].
    +// TODO(gri) remove once we don't need the old cycle detection (explicitly passed
    +//           []*TypeName path) anymore
     func pathString(path []*TypeName) string {
     	var s string
     	for i, p := range path {
    @@ -49,18 +51,24 @@ func pathString(path []*TypeName) string {
     	return s
     }
     
    -// useCycleMarking enables the new coloring-based cycle marking scheme
    -// for package-level objects. Set this flag to false to disable this
    -// code quickly and revert to the existing mechanism (and comment out
    -// some of the new tests in cycles5.src that will fail again).
    -// TODO(gri) remove this for Go 1.12
    -const useCycleMarking = true
    +// objPathString returns a string of the form a->b-> ... ->g for a path [a, b, ... g].
    +// TODO(gri) s/objPathString/pathString/ once we got rid of pathString above
    +func objPathString(path []Object) string {
    +	var s string
    +	for i, p := range path {
    +		if i > 0 {
    +			s += "->"
    +		}
    +		s += p.Name()
    +	}
    +	return s
    +}
     
     // objDecl type-checks the declaration of obj in its respective (file) context.
     // See check.typ for the details on def and path.
    -func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
    +func (check *Checker) objDecl(obj Object, def *Named) {
     	if trace {
    -		check.trace(obj.Pos(), "-- checking %s %s (path = %s, objPath = %s)", obj.color(), obj, pathString(path), check.pathString())
    +		check.trace(obj.Pos(), "-- checking %s %s (objPath = %s)", obj.color(), obj, objPathString(check.objPath))
     		check.indent++
     		defer func() {
     			check.indent--
    @@ -132,7 +140,7 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     		// order code.
     		switch obj := obj.(type) {
     		case *Const:
    -			if useCycleMarking && check.typeCycle(obj) {
    +			if check.typeCycle(obj) {
     				obj.typ = Typ[Invalid]
     				break
     			}
    @@ -141,7 +149,7 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     			}
     
     		case *Var:
    -			if useCycleMarking && check.typeCycle(obj) {
    +			if check.typeCycle(obj) {
     				obj.typ = Typ[Invalid]
     				break
     			}
    @@ -150,7 +158,32 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     			}
     
     		case *TypeName:
    -			if useCycleMarking && check.typeCycle(obj) {
    +			// fixFor26390 enables a temporary work-around to handle alias type names
    +			// that have not been given a type yet even though the underlying type
    +			// is already known. See testdata/issue26390.src for a simple example.
    +			// Set this flag to false to disable this code quickly (and comment
    +			// out the new test in decls4.src that will fail again).
    +			// TODO(gri) remove this for Go 1.12 in favor of a more comprehensive fix
    +			const fixFor26390 = true
    +			if fixFor26390 {
    +				// If we have a package-level alias type name that has not been
    +				// given a type yet but the underlying type is a type name that
    +				// has been given a type already, don't report a cycle but use
    +				// the underlying type name's type instead. The cycle shouldn't
    +				// exist in the first place in this case and is due to the way
    +				// methods are type-checked at the moment. See also the comment
    +				// at the end of Checker.typeDecl below.
    +				if d := check.objMap[obj]; d != nil && d.alias && obj.typ == Typ[Invalid] {
    +					// If we can find the underlying type name syntactically
    +					// and it has a type, use that type.
    +					if tname := check.resolveBaseTypeName(ast.NewIdent(obj.name)); tname != nil && tname.typ != nil {
    +						obj.typ = tname.typ
    +						break
    +					}
    +				}
    +			}
    +
    +			if check.typeCycle(obj) {
     				// break cycle
     				// (without this, calling underlying()
     				// below may lead to an endless loop
    @@ -160,7 +193,7 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     			}
     
     		case *Func:
    -			if useCycleMarking && check.typeCycle(obj) {
    +			if check.typeCycle(obj) {
     				// Don't set obj.typ to Typ[Invalid] here
     				// because plenty of code type-asserts that
     				// functions have a *Signature type. Grey
    @@ -204,7 +237,7 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     		check.varDecl(obj, d.lhs, d.typ, d.init)
     	case *TypeName:
     		// invalid recursive types are detected via path
    -		check.typeDecl(obj, d.typ, def, path, d.alias)
    +		check.typeDecl(obj, d.typ, def, d.alias)
     	case *Func:
     		// functions may be recursive - no need to track dependencies
     		check.funcDecl(obj, d)
    @@ -220,20 +253,35 @@ func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
     // Indirections are used to break type cycles.
     var indir = NewTypeName(token.NoPos, nil, "*", nil)
     
    +// cutCycle is a sentinel type name that is pushed onto the object path
    +// to indicate that a cycle doesn't actually exist. This is currently
    +// needed to break cycles formed via method declarations because they
    +// are type-checked together with their receiver base types. Once methods
    +// are type-checked separately (see also TODO in Checker.typeDecl), we
    +// can get rid of this.
    +var cutCycle = NewTypeName(token.NoPos, nil, "!", nil)
    +
     // typeCycle checks if the cycle starting with obj is valid and
     // reports an error if it is not.
     // TODO(gri) rename s/typeCycle/cycle/ once we don't need the other
     // cycle method anymore.
    -func (check *Checker) typeCycle(obj Object) bool {
    -	d := check.objMap[obj]
    -	if d == nil {
    -		check.dump("%v: %s should have been declared", obj.Pos(), obj)
    -		unreachable()
    +func (check *Checker) typeCycle(obj Object) (isCycle bool) {
    +	// The object map contains the package scope objects and the non-interface methods.
    +	if debug {
    +		info := check.objMap[obj]
    +		inObjMap := info != nil && (info.fdecl == nil || info.fdecl.Recv == nil) // exclude methods
    +		isPkgObj := obj.Parent() == check.pkg.scope
    +		if isPkgObj != inObjMap {
    +			check.dump("%v: inconsistent object map for %s (isPkgObj = %v, inObjMap = %v)", obj.Pos(), obj, isPkgObj, inObjMap)
    +			unreachable()
    +		}
     	}
     
    -	// We distinguish between cycles involving only constants and variables
    -	// (nval = len(cycle)), cycles involving types (and functions) only
    -	// (nval == 0), and mixed cycles (nval != 0 && nval != len(cycle)).
    +	// Given the number of constants and variables (nval) in the cycle
    +	// and the cycle length (ncycle = number of named objects in the cycle),
    +	// we distinguish between cycles involving only constants and variables
    +	// (nval = ncycle), cycles involving types (and functions) only
    +	// (nval == 0), and mixed cycles (nval != 0 && nval != ncycle).
     	// We ignore functions at the moment (taking them into account correctly
     	// is complicated and it doesn't improve error reporting significantly).
     	//
    @@ -242,20 +290,45 @@ func (check *Checker) typeCycle(obj Object) bool {
     	// cannot be computed (it's either infinite or 0); if there is no type
     	// definition, we have a sequence of alias type names which will expand
     	// ad infinitum.
    -	var nval int
    +	var nval, ncycle int
     	var hasIndir, hasTDef bool
     	assert(obj.color() >= grey)
     	start := obj.color() - grey // index of obj in objPath
     	cycle := check.objPath[start:]
    +	ncycle = len(cycle) // including indirections
     	for _, obj := range cycle {
     		switch obj := obj.(type) {
     		case *Const, *Var:
     			nval++
     		case *TypeName:
    -			if obj == indir {
    +			switch {
    +			case obj == indir:
    +				ncycle-- // don't count (indirections are not objects)
     				hasIndir = true
    -			} else if !check.objMap[obj].alias {
    -				hasTDef = true
    +			case obj == cutCycle:
    +				// The cycle is not real and only caused by the fact
    +				// that we type-check methods when we type-check their
    +				// receiver base types.
    +				return false
    +			default:
    +				// Determine if the type name is an alias or not. For
    +				// package-level objects, use the object map which
    +				// provides syntactic information (which doesn't rely
    +				// on the order in which the objects are set up). For
    +				// local objects, we can rely on the order, so use
    +				// the object's predicate.
    +				// TODO(gri) It would be less fragile to always access
    +				// the syntactic information. We should consider storing
    +				// this information explicitly in the object.
    +				var alias bool
    +				if d := check.objMap[obj]; d != nil {
    +					alias = d.alias // package-level object
    +				} else {
    +					alias = obj.IsAlias() // function local object
    +				}
    +				if !alias {
    +					hasTDef = true
    +				}
     			}
     		case *Func:
     			// ignored for now
    @@ -264,10 +337,20 @@ func (check *Checker) typeCycle(obj Object) bool {
     		}
     	}
     
    +	if trace {
    +		check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", objPathString(cycle), obj.Name(), ncycle)
    +		check.trace(obj.Pos(), "## cycle contains: %d values, has indirection = %v, has type definition = %v", nval, hasIndir, hasTDef)
    +		defer func() {
    +			if isCycle {
    +				check.trace(obj.Pos(), "=> error: cycle is invalid")
    +			}
    +		}()
    +	}
    +
     	// A cycle involving only constants and variables is invalid but we
     	// ignore them here because they are reported via the initialization
     	// cycle check.
    -	if nval == len(cycle) {
    +	if nval == ncycle {
     		return false
     	}
     
    @@ -406,13 +489,13 @@ func (n *Named) setUnderlying(typ Type) {
     	}
     }
     
    -func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName, alias bool) {
    +func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, alias bool) {
     	assert(obj.typ == nil)
     
     	if alias {
     
     		obj.typ = Typ[Invalid]
    -		obj.typ = check.typExpr(typ, nil, append(path, obj))
    +		obj.typ = check.typ(typ)
     
     	} else {
     
    @@ -421,7 +504,7 @@ func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*
     		obj.typ = named // make sure recursive type declarations terminate
     
     		// determine underlying type of named
    -		check.typExpr(typ, named, append(path, obj))
    +		check.definedType(typ, named)
     
     		// The underlying type of named may be itself a named type that is
     		// incomplete:
    @@ -484,6 +567,14 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
     		}
     	}
     
    +	// Suppress detection of type cycles occurring through method
    +	// declarations - they wouldn't exist if methods were type-
    +	// checked separately from their receiver base types. See also
    +	// comment at the end of Checker.typeDecl.
    +	// TODO(gri) Remove this once methods are type-checked separately.
    +	check.push(cutCycle)
    +	defer check.pop()
    +
     	// type-check methods
     	for _, m := range methods {
     		// spec: "For a base type, the non-blank names of methods bound
    @@ -503,7 +594,7 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
     		}
     
     		// type-check
    -		check.objDecl(m, nil, nil)
    +		check.objDecl(m, nil)
     
     		if base != nil {
     			base.methods = append(base.methods, m)
    @@ -652,8 +743,10 @@ func (check *Checker) declStmt(decl ast.Decl) {
     				// the innermost containing block."
     				scopePos := s.Name.Pos()
     				check.declare(check.scope, s.Name, obj, scopePos)
    -				check.typeDecl(obj, s.Type, nil, nil, s.Assign.IsValid())
    -
    +				// mark and unmark type before calling typeDecl; its type is still nil (see Checker.objDecl)
    +				obj.setColor(grey + color(check.push(obj)))
    +				check.typeDecl(obj, s.Type, nil, s.Assign.IsValid())
    +				check.pop().setColor(black)
     			default:
     				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
     			}
    diff --git a/src/go/types/expr.go b/src/go/types/expr.go
    index 3f3c4f83c6..c65c9e7681 100644
    --- a/src/go/types/expr.go
    +++ b/src/go/types/expr.go
    @@ -1010,7 +1010,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
     		goto Error // error was reported before
     
     	case *ast.Ident:
    -		check.ident(x, e, nil, nil)
    +		check.ident(x, e, nil)
     
     	case *ast.Ellipsis:
     		// ellipses are handled explicitly where they are legal
    @@ -1064,7 +1064,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
     					break
     				}
     			}
    -			typ = check.typExpr(e.Type, nil, nil)
    +			typ = check.typ(e.Type)
     			base = typ
     
     		case hint != nil:
    @@ -1094,6 +1094,9 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
     						continue
     					}
     					key, _ := kv.Key.(*ast.Ident)
    +					// do all possible checks early (before exiting due to errors)
    +					// so we don't drop information on the floor
    +					check.expr(x, kv.Value)
     					if key == nil {
     						check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
     						continue
    @@ -1105,15 +1108,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
     					}
     					fld := fields[i]
     					check.recordUse(key, fld)
    +					etyp := fld.typ
    +					check.assignment(x, etyp, "struct literal")
     					// 0 <= i < len(fields)
     					if visited[i] {
     						check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
     						continue
     					}
     					visited[i] = true
    -					check.expr(x, kv.Value)
    -					etyp := fld.typ
    -					check.assignment(x, etyp, "struct literal")
     				}
     			} else {
     				// no element must have a key
    @@ -1154,12 +1156,23 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
     				goto Error
     			}
     			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
    -			// If we have an "open" [...]T array, set the length now that we know it
    -			// and record the type for [...] (usually done by check.typExpr which is
    -			// not called for [...]).
    +			// If we have an array of unknown length (usually [...]T arrays, but also
    +			// arrays [n]T where n is invalid) set the length now that we know it and
    +			// record the type for the array (usually done by check.typ which is not
    +			// called for [...]T). We handle [...]T arrays and arrays with invalid
    +			// length the same here because it makes sense to "guess" the length for
    +			// the latter if we have a composite literal; e.g. for [n]int{1, 2, 3}
    +			// where n is invalid for some reason, it seems fair to assume it should
    +			// be 3 (see also Checked.arrayLength and issue #27346).
     			if utyp.len < 0 {
     				utyp.len = n
    -				check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
    +				// e.Type is missing if we have a composite literal element
    +				// that is itself a composite literal with omitted type. In
    +				// that case there is nothing to record (there is no type in
    +				// the source at that point).
    +				if e.Type != nil {
    +					check.recordTypeAndValue(e.Type, typexpr, utyp, nil)
    +				}
     			}
     
     		case *Slice:
    diff --git a/src/go/types/interfaces.go b/src/go/types/interfaces.go
    index e4b42dc5a3..57dc1bccdc 100644
    --- a/src/go/types/interfaces.go
    +++ b/src/go/types/interfaces.go
    @@ -144,7 +144,7 @@ func (check *Checker) infoFromTypeLit(scope *Scope, iface *ast.InterfaceType, tn
     	}
     
     	if trace {
    -		check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), check.pathString())
    +		check.trace(iface.Pos(), "-- collect methods for %v (path = %s, objPath = %s)", iface, pathString(path), objPathString(check.objPath))
     		check.indent++
     		defer func() {
     			check.indent--
    diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
    index 5cbaba187b..ec7e4ed1c5 100644
    --- a/src/go/types/resolver.go
    +++ b/src/go/types/resolver.go
    @@ -420,6 +420,10 @@ func (check *Checker) collectObjects() {
     					check.recordDef(d.Name, obj)
     				}
     				info := &declInfo{file: fileScope, fdecl: d}
    +				// Methods are not package-level objects but we still track them in the
    +				// object map so that we can handle them like regular functions (if the
    +				// receiver is invalid); also we need their fdecl info when associating
    +				// them with their receiver base type, below.
     				check.objMap[obj] = info
     				obj.setOrder(uint32(len(check.objMap)))
     
    @@ -517,6 +521,26 @@ func (check *Checker) resolveBaseTypeName(name *ast.Ident) *TypeName {
     	}
     }
     
    +// cycle reports whether obj appears in path or not.
    +// If it does, and report is set, it also reports a cycle error.
    +func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool {
    +	// (it's ok to iterate forward because each named type appears at most once in path)
    +	for i, prev := range path {
    +		if prev == obj {
    +			if report {
    +				check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
    +				// print cycle
    +				for _, obj := range path[i:] {
    +					check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
    +				}
    +				check.errorf(obj.Pos(), "\t%s", obj.Name())
    +			}
    +			return true
    +		}
    +	}
    +	return false
    +}
    +
     // packageObjects typechecks all package objects, but not function bodies.
     func (check *Checker) packageObjects() {
     	// process package objects in source order for reproducible results
    @@ -535,11 +559,8 @@ func (check *Checker) packageObjects() {
     		}
     	}
     
    -	// pre-allocate space for type declaration paths so that the underlying array is reused
    -	typePath := make([]*TypeName, 0, 8)
    -
     	for _, obj := range objList {
    -		check.objDecl(obj, nil, typePath)
    +		check.objDecl(obj, nil)
     	}
     
     	// At this point we may have a non-empty check.methods map; this means that not all
    diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
    index 59f112dba1..a9af46a933 100644
    --- a/src/go/types/testdata/cycles.src
    +++ b/src/go/types/testdata/cycles.src
    @@ -158,6 +158,8 @@ type T20 chan [unsafe.Sizeof(func(ch T20){ _ = <-ch })]byte
     type T22 = chan [unsafe.Sizeof(func(ch T20){ _ = <-ch })]byte
     
     func _() {
    -	type T1 chan [unsafe.Sizeof(func(ch T1){ _ = <-ch })]byte
    -	type T2 = chan [unsafe.Sizeof(func(ch T2){ _ = <-ch })]byte
    +	type T0 func(T0)
    +	type T1 /* ERROR cycle */ = func(T1)
    +	type T2 chan [unsafe.Sizeof(func(ch T2){ _ = <-ch })]byte
    +	type T3 /* ERROR cycle */ = chan [unsafe.Sizeof(func(ch T3){ _ = <-ch })]byte
     }
    diff --git a/src/go/types/testdata/issue26390.src b/src/go/types/testdata/issue26390.src
    new file mode 100644
    index 0000000000..b8e67e9bdd
    --- /dev/null
    +++ b/src/go/types/testdata/issue26390.src
    @@ -0,0 +1,11 @@
    +// Copyright 2018 The Go Authors. All rights reserved.
    +// Use of this source code is governed by a BSD-style
    +// license that can be found in the LICENSE file.
    +
    +package issue26390
    +
    +type A = T
    +
    +func (t *T) m() *A { return t }
    +
    +type T struct{}
    diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
    index d727c3b3e2..13f8309c82 100644
    --- a/src/go/types/testdata/issues.src
    +++ b/src/go/types/testdata/issues.src
    @@ -97,7 +97,7 @@ func issue10979() {
     
     // issue11347
     // These should not crash.
    -var a1, b1 /* ERROR cycle */ /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1
    +var a1, b1 /* ERROR cycle */ , c1 /* ERROR cycle */ b1 = 0 > 0<<""[""[c1]]>c1
     var a2, b2 /* ERROR cycle */ = 0 /* ERROR cannot initialize */ /* ERROR cannot initialize */ > 0<<""[b2]
     var a3, b3 /* ERROR cycle */ = int /* ERROR cannot initialize */ /* ERROR cannot initialize */ (1<<""[b3])
     
    @@ -270,3 +270,35 @@ type issue25301c interface {
     }
     
     type notE = struct{}
    +
    +// Test that method declarations don't introduce artificial cycles
    +// (issue #26124).
    +const CC TT = 1
    +type TT int
    +func (TT) MM() [CC]TT
    +
    +// Reduced test case from issue #26124.
    +const preloadLimit LNumber = 128
    +type LNumber float64
    +func (LNumber) assertFunction() *LFunction
    +type LFunction struct {
    +	GFunction LGFunction
    +}
    +type LGFunction func(*LState)
    +type LState struct {
    +	reg *registry
    +}
    +type registry struct {
    +	alloc *allocator
    +}
    +type allocator struct {
    +	_ [int(preloadLimit)]int
    +}
    +
    +// Test that we don't crash when type-checking composite literals
    +// containing errors in the type.
    +var issue27346 = [][n /* ERROR undeclared */ ]int{
    +	0: {},
    +}
    +
    +var issue22467 = map[int][... /* ERROR invalid use of ... */ ]int{0: {}}
    diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
    index 45ada5874b..83848099c2 100644
    --- a/src/go/types/typexpr.go
    +++ b/src/go/types/typexpr.go
    @@ -16,9 +16,9 @@ import (
     
     // ident type-checks identifier e and initializes x with the value or type of e.
     // If an error occurred, x.mode is set to invalid.
    -// For the meaning of def and path, see check.typ, below.
    +// For the meaning of def, see check.typExpr, below.
     //
    -func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
    +func (check *Checker) ident(x *operand, e *ast.Ident, def *Named) {
     	x.mode = invalid
     	x.expr = e
     
    @@ -35,7 +35,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
     	}
     	check.recordUse(e, obj)
     
    -	check.objDecl(obj, def, path)
    +	check.objDecl(obj, def)
     	typ := obj.Type()
     	assert(typ != nil)
     
    @@ -71,17 +71,6 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
     
     	case *TypeName:
     		x.mode = typexpr
    -		// package-level alias cycles are now checked by Checker.objDecl
    -		if useCycleMarking {
    -			if check.objMap[obj] != nil {
    -				break
    -			}
    -		}
    -		if check.cycle(obj, path, true) {
    -			// maintain x.mode == typexpr despite error
    -			typ = Typ[Invalid]
    -			break
    -		}
     
     	case *Var:
     		// It's ok to mark non-local variables, but ignore variables
    @@ -114,37 +103,17 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeNa
     	x.typ = typ
     }
     
    -// cycle reports whether obj appears in path or not.
    -// If it does, and report is set, it also reports a cycle error.
    -func (check *Checker) cycle(obj *TypeName, path []*TypeName, report bool) bool {
    -	// (it's ok to iterate forward because each named type appears at most once in path)
    -	for i, prev := range path {
    -		if prev == obj {
    -			if report {
    -				check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
    -				// print cycle
    -				for _, obj := range path[i:] {
    -					check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
    -				}
    -				check.errorf(obj.Pos(), "\t%s", obj.Name())
    -			}
    -			return true
    -		}
    -	}
    -	return false
    +// typ type-checks the type expression e and returns its type, or Typ[Invalid].
    +func (check *Checker) typ(e ast.Expr) Type {
    +	return check.definedType(e, nil)
     }
     
    -// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
    -// If def != nil, e is the type specification for the named type def, declared
    +// definedType is like typ but also accepts a type name def.
    +// If def != nil, e is the type specification for the defined type def, declared
     // in a type declaration, and def.underlying will be set to the type of e before
    -// any components of e are type-checked. Path contains the path of named types
    -// referring to this type; i.e. it is the path of named types directly containing
    -// each other and leading to the current type e. Indirect containment (e.g. via
    -// pointer indirection, function parameter, etc.) breaks the path (leads to a new
    -// path, and usually via calling Checker.typ below) and those types are not found
    -// in the path.
    +// any components of e are type-checked.
     //
    -func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
    +func (check *Checker) definedType(e ast.Expr, def *Named) (T Type) {
     	if trace {
     		check.trace(e.Pos(), "%s", e)
     		check.indent++
    @@ -154,26 +123,21 @@ func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type)
     		}()
     	}
     
    -	T = check.typExprInternal(e, def, path)
    +	T = check.typInternal(e, def)
     	assert(isTyped(T))
     	check.recordTypeAndValue(e, typexpr, T, nil)
     
     	return
     }
     
    -// typ is like typExpr (with a nil argument for the def parameter),
    -// but typ breaks type cycles. It should be called for components of
    -// types that break cycles, such as pointer base types, slice or map
    -// element types, etc. See the comment in typExpr for details.
    -//
    -func (check *Checker) typ(e ast.Expr) Type {
    -	// typExpr is called with a nil path indicating an indirection:
    -	// push indir sentinel on object path
    -	if useCycleMarking {
    -		check.push(indir)
    -		defer check.pop()
    -	}
    -	return check.typExpr(e, nil, nil)
    +// indirectType is like typ but it also breaks the (otherwise) infinite size of recursive
    +// types by introducing an indirection. It should be called for components of types that
    +// are not laid out in place in memory, such as pointer base types, slice or map element
    +// types, function parameter types, etc.
    +func (check *Checker) indirectType(e ast.Expr) Type {
    +	check.push(indir)
    +	defer check.pop()
    +	return check.definedType(e, nil)
     }
     
     // funcType type-checks a function or method type.
    @@ -241,17 +205,17 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
     	sig.variadic = variadic
     }
     
    -// typExprInternal drives type checking of types.
    -// Must only be called by typExpr.
    +// typInternal drives type checking of types.
    +// Must only be called by definedType.
     //
    -func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
    +func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
     	switch e := e.(type) {
     	case *ast.BadExpr:
     		// ignore - error reported before
     
     	case *ast.Ident:
     		var x operand
    -		check.ident(&x, e, def, path)
    +		check.ident(&x, e, def)
     
     		switch x.mode {
     		case typexpr:
    @@ -284,33 +248,33 @@ func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName)
     		}
     
     	case *ast.ParenExpr:
    -		return check.typExpr(e.X, def, path)
    +		return check.definedType(e.X, def)
     
     	case *ast.ArrayType:
     		if e.Len != nil {
     			typ := new(Array)
     			def.setUnderlying(typ)
     			typ.len = check.arrayLength(e.Len)
    -			typ.elem = check.typExpr(e.Elt, nil, path)
    +			typ.elem = check.typ(e.Elt)
     			return typ
     
     		} else {
     			typ := new(Slice)
     			def.setUnderlying(typ)
    -			typ.elem = check.typ(e.Elt)
    +			typ.elem = check.indirectType(e.Elt)
     			return typ
     		}
     
     	case *ast.StructType:
     		typ := new(Struct)
     		def.setUnderlying(typ)
    -		check.structType(typ, e, path)
    +		check.structType(typ, e)
     		return typ
     
     	case *ast.StarExpr:
     		typ := new(Pointer)
     		def.setUnderlying(typ)
    -		typ.base = check.typ(e.X)
    +		typ.base = check.indirectType(e.X)
     		return typ
     
     	case *ast.FuncType:
    @@ -322,15 +286,15 @@ func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName)
     	case *ast.InterfaceType:
     		typ := new(Interface)
     		def.setUnderlying(typ)
    -		check.interfaceType(typ, e, def, path)
    +		check.interfaceType(typ, e, def)
     		return typ
     
     	case *ast.MapType:
     		typ := new(Map)
     		def.setUnderlying(typ)
     
    -		typ.key = check.typ(e.Key)
    -		typ.elem = check.typ(e.Value)
    +		typ.key = check.indirectType(e.Key)
    +		typ.elem = check.indirectType(e.Value)
     
     		// spec: "The comparison operators == and != must be fully defined
     		// for operands of the key type; thus the key type must not be a
    @@ -364,7 +328,7 @@ func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName)
     		}
     
     		typ.dir = dir
    -		typ.elem = check.typ(e.Value)
    +		typ.elem = check.indirectType(e.Value)
     		return typ
     
     	default:
    @@ -445,7 +409,7 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
     				// ignore ... and continue
     			}
     		}
    -		typ := check.typ(ftype)
    +		typ := check.indirectType(ftype)
     		// The parser ensures that f.Tag is nil and we don't
     		// care if a constructed AST contains a non-nil tag.
     		if len(field.Names) > 0 {
    @@ -492,7 +456,7 @@ func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool
     	return true
     }
     
    -func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named, path []*TypeName) {
    +func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
     	// fast-track empty interface
     	if iface.Methods.List == nil {
     		ityp.allMethods = markComplete
    @@ -525,7 +489,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
     
     		for _, f := range iface.Methods.List {
     			if len(f.Names) == 0 {
    -				typ := check.typ(f.Type)
    +				typ := check.indirectType(f.Type)
     				// typ should be a named type denoting an interface
     				// (the parser will make sure it's a named type but
     				// constructed ASTs may be wrong).
    @@ -555,8 +519,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
     
     	// compute method set
     	var tname *TypeName
    +	var path []*TypeName
     	if def != nil {
     		tname = def.obj
    +		path = []*TypeName{tname}
     	}
     	info := check.infoFromTypeLit(check.scope, iface, tname, path)
     	if info == nil || info == &emptyIfaceInfo {
    @@ -606,7 +572,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
     		// (possibly embedded) methods must be type-checked within their scope and
     		// type-checking them must not affect the current context (was issue #23914)
     		check.context = context{scope: minfo.scope}
    -		typ := check.typ(minfo.src.Type)
    +		typ := check.indirectType(minfo.src.Type)
     		sig, _ := typ.(*Signature)
     		if sig == nil {
     			if typ != Typ[Invalid] {
    @@ -665,7 +631,7 @@ func (check *Checker) tag(t *ast.BasicLit) string {
     	return ""
     }
     
    -func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
    +func (check *Checker) structType(styp *Struct, e *ast.StructType) {
     	list := e.Fields
     	if list == nil {
     		return
    @@ -709,7 +675,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeNa
     	}
     
     	for _, f := range list.List {
    -		typ = check.typExpr(f.Type, nil, path)
    +		typ = check.typ(f.Type)
     		tag = check.tag(f.Tag)
     		if len(f.Names) > 0 {
     			// named fields
    diff --git a/src/hash/crc32/crc32_arm64.go b/src/hash/crc32/crc32_arm64.go
    index 1f8779d506..0242d1d8a7 100644
    --- a/src/hash/crc32/crc32_arm64.go
    +++ b/src/hash/crc32/crc32_arm64.go
    @@ -13,20 +13,18 @@ import "internal/cpu"
     func castagnoliUpdate(crc uint32, p []byte) uint32
     func ieeeUpdate(crc uint32, p []byte) uint32
     
    -var hasCRC32 = cpu.ARM64.HasCRC32
    -
     func archAvailableCastagnoli() bool {
    -	return hasCRC32
    +	return cpu.ARM64.HasCRC32
     }
     
     func archInitCastagnoli() {
    -	if !hasCRC32 {
    +	if !cpu.ARM64.HasCRC32 {
     		panic("arch-specific crc32 instruction for Catagnoli not available")
     	}
     }
     
     func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
    -	if !hasCRC32 {
    +	if !cpu.ARM64.HasCRC32 {
     		panic("arch-specific crc32 instruction for Castagnoli not available")
     	}
     
    @@ -34,17 +32,17 @@ func archUpdateCastagnoli(crc uint32, p []byte) uint32 {
     }
     
     func archAvailableIEEE() bool {
    -	return hasCRC32
    +	return cpu.ARM64.HasCRC32
     }
     
     func archInitIEEE() {
    -	if !hasCRC32 {
    +	if !cpu.ARM64.HasCRC32 {
     		panic("arch-specific crc32 instruction for IEEE not available")
     	}
     }
     
     func archUpdateIEEE(crc uint32, p []byte) uint32 {
    -	if !hasCRC32 {
    +	if !cpu.ARM64.HasCRC32 {
     		panic("arch-specific crc32 instruction for IEEE not available")
     	}
     
    diff --git a/src/hash/crc64/crc64.go b/src/hash/crc64/crc64.go
    index a799a017c9..063c63c6a3 100644
    --- a/src/hash/crc64/crc64.go
    +++ b/src/hash/crc64/crc64.go
    @@ -10,6 +10,7 @@ package crc64
     import (
     	"errors"
     	"hash"
    +	"sync"
     )
     
     // The size of a CRC-64 checksum in bytes.
    @@ -28,13 +29,24 @@ const (
     type Table [256]uint64
     
     var (
    -	slicing8TableISO  = makeSlicingBy8Table(makeTable(ISO))
    -	slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
    +	slicing8TablesBuildOnce sync.Once
    +	slicing8TableISO        *[8]Table
    +	slicing8TableECMA       *[8]Table
     )
     
    +func buildSlicing8TablesOnce() {
    +	slicing8TablesBuildOnce.Do(buildSlicing8Tables)
    +}
    +
    +func buildSlicing8Tables() {
    +	slicing8TableISO = makeSlicingBy8Table(makeTable(ISO))
    +	slicing8TableECMA = makeSlicingBy8Table(makeTable(ECMA))
    +}
    +
     // MakeTable returns a Table constructed from the specified polynomial.
     // The contents of this Table must not be modified.
     func MakeTable(poly uint64) *Table {
    +	buildSlicing8TablesOnce()
     	switch poly {
     	case ISO:
     		return &slicing8TableISO[0]
    @@ -141,6 +153,7 @@ func readUint64(b []byte) uint64 {
     }
     
     func update(crc uint64, tab *Table, p []byte) uint64 {
    +	buildSlicing8TablesOnce()
     	crc = ^crc
     	// Table comparison is somewhat expensive, so avoid it for small sizes
     	for len(p) >= 64 {
    diff --git a/src/html/entity.go b/src/html/entity.go
    index d123794335..f0f9a6a973 100644
    --- a/src/html/entity.go
    +++ b/src/html/entity.go
    @@ -4,6 +4,8 @@
     
     package html
     
    +import "sync"
    +
     // All entities that do not end with ';' are 6 or fewer bytes long.
     const longestEntityWithoutSemicolon = 6
     
    @@ -13,2241 +15,2251 @@ const longestEntityWithoutSemicolon = 6
     //
     // Note that the HTML5 list is larger than the HTML4 list at
     // http://www.w3.org/TR/html4/sgml/entities.html
    -var entity = map[string]rune{
    -	"AElig;":                           '\U000000C6',
    -	"AMP;":                             '\U00000026',
    -	"Aacute;":                          '\U000000C1',
    -	"Abreve;":                          '\U00000102',
    -	"Acirc;":                           '\U000000C2',
    -	"Acy;":                             '\U00000410',
    -	"Afr;":                             '\U0001D504',
    -	"Agrave;":                          '\U000000C0',
    -	"Alpha;":                           '\U00000391',
    -	"Amacr;":                           '\U00000100',
    -	"And;":                             '\U00002A53',
    -	"Aogon;":                           '\U00000104',
    -	"Aopf;":                            '\U0001D538',
    -	"ApplyFunction;":                   '\U00002061',
    -	"Aring;":                           '\U000000C5',
    -	"Ascr;":                            '\U0001D49C',
    -	"Assign;":                          '\U00002254',
    -	"Atilde;":                          '\U000000C3',
    -	"Auml;":                            '\U000000C4',
    -	"Backslash;":                       '\U00002216',
    -	"Barv;":                            '\U00002AE7',
    -	"Barwed;":                          '\U00002306',
    -	"Bcy;":                             '\U00000411',
    -	"Because;":                         '\U00002235',
    -	"Bernoullis;":                      '\U0000212C',
    -	"Beta;":                            '\U00000392',
    -	"Bfr;":                             '\U0001D505',
    -	"Bopf;":                            '\U0001D539',
    -	"Breve;":                           '\U000002D8',
    -	"Bscr;":                            '\U0000212C',
    -	"Bumpeq;":                          '\U0000224E',
    -	"CHcy;":                            '\U00000427',
    -	"COPY;":                            '\U000000A9',
    -	"Cacute;":                          '\U00000106',
    -	"Cap;":                             '\U000022D2',
    -	"CapitalDifferentialD;":            '\U00002145',
    -	"Cayleys;":                         '\U0000212D',
    -	"Ccaron;":                          '\U0000010C',
    -	"Ccedil;":                          '\U000000C7',
    -	"Ccirc;":                           '\U00000108',
    -	"Cconint;":                         '\U00002230',
    -	"Cdot;":                            '\U0000010A',
    -	"Cedilla;":                         '\U000000B8',
    -	"CenterDot;":                       '\U000000B7',
    -	"Cfr;":                             '\U0000212D',
    -	"Chi;":                             '\U000003A7',
    -	"CircleDot;":                       '\U00002299',
    -	"CircleMinus;":                     '\U00002296',
    -	"CirclePlus;":                      '\U00002295',
    -	"CircleTimes;":                     '\U00002297',
    -	"ClockwiseContourIntegral;":        '\U00002232',
    -	"CloseCurlyDoubleQuote;":           '\U0000201D',
    -	"CloseCurlyQuote;":                 '\U00002019',
    -	"Colon;":                           '\U00002237',
    -	"Colone;":                          '\U00002A74',
    -	"Congruent;":                       '\U00002261',
    -	"Conint;":                          '\U0000222F',
    -	"ContourIntegral;":                 '\U0000222E',
    -	"Copf;":                            '\U00002102',
    -	"Coproduct;":                       '\U00002210',
    -	"CounterClockwiseContourIntegral;": '\U00002233',
    -	"Cross;":                           '\U00002A2F',
    -	"Cscr;":                            '\U0001D49E',
    -	"Cup;":                             '\U000022D3',
    -	"CupCap;":                          '\U0000224D',
    -	"DD;":                              '\U00002145',
    -	"DDotrahd;":                        '\U00002911',
    -	"DJcy;":                            '\U00000402',
    -	"DScy;":                            '\U00000405',
    -	"DZcy;":                            '\U0000040F',
    -	"Dagger;":                          '\U00002021',
    -	"Darr;":                            '\U000021A1',
    -	"Dashv;":                           '\U00002AE4',
    -	"Dcaron;":                          '\U0000010E',
    -	"Dcy;":                             '\U00000414',
    -	"Del;":                             '\U00002207',
    -	"Delta;":                           '\U00000394',
    -	"Dfr;":                             '\U0001D507',
    -	"DiacriticalAcute;":                '\U000000B4',
    -	"DiacriticalDot;":                  '\U000002D9',
    -	"DiacriticalDoubleAcute;":          '\U000002DD',
    -	"DiacriticalGrave;":                '\U00000060',
    -	"DiacriticalTilde;":                '\U000002DC',
    -	"Diamond;":                         '\U000022C4',
    -	"DifferentialD;":                   '\U00002146',
    -	"Dopf;":                            '\U0001D53B',
    -	"Dot;":                             '\U000000A8',
    -	"DotDot;":                          '\U000020DC',
    -	"DotEqual;":                        '\U00002250',
    -	"DoubleContourIntegral;":           '\U0000222F',
    -	"DoubleDot;":                       '\U000000A8',
    -	"DoubleDownArrow;":                 '\U000021D3',
    -	"DoubleLeftArrow;":                 '\U000021D0',
    -	"DoubleLeftRightArrow;":            '\U000021D4',
    -	"DoubleLeftTee;":                   '\U00002AE4',
    -	"DoubleLongLeftArrow;":             '\U000027F8',
    -	"DoubleLongLeftRightArrow;":        '\U000027FA',
    -	"DoubleLongRightArrow;":            '\U000027F9',
    -	"DoubleRightArrow;":                '\U000021D2',
    -	"DoubleRightTee;":                  '\U000022A8',
    -	"DoubleUpArrow;":                   '\U000021D1',
    -	"DoubleUpDownArrow;":               '\U000021D5',
    -	"DoubleVerticalBar;":               '\U00002225',
    -	"DownArrow;":                       '\U00002193',
    -	"DownArrowBar;":                    '\U00002913',
    -	"DownArrowUpArrow;":                '\U000021F5',
    -	"DownBreve;":                       '\U00000311',
    -	"DownLeftRightVector;":             '\U00002950',
    -	"DownLeftTeeVector;":               '\U0000295E',
    -	"DownLeftVector;":                  '\U000021BD',
    -	"DownLeftVectorBar;":               '\U00002956',
    -	"DownRightTeeVector;":              '\U0000295F',
    -	"DownRightVector;":                 '\U000021C1',
    -	"DownRightVectorBar;":              '\U00002957',
    -	"DownTee;":                         '\U000022A4',
    -	"DownTeeArrow;":                    '\U000021A7',
    -	"Downarrow;":                       '\U000021D3',
    -	"Dscr;":                            '\U0001D49F',
    -	"Dstrok;":                          '\U00000110',
    -	"ENG;":                             '\U0000014A',
    -	"ETH;":                             '\U000000D0',
    -	"Eacute;":                          '\U000000C9',
    -	"Ecaron;":                          '\U0000011A',
    -	"Ecirc;":                           '\U000000CA',
    -	"Ecy;":                             '\U0000042D',
    -	"Edot;":                            '\U00000116',
    -	"Efr;":                             '\U0001D508',
    -	"Egrave;":                          '\U000000C8',
    -	"Element;":                         '\U00002208',
    -	"Emacr;":                           '\U00000112',
    -	"EmptySmallSquare;":                '\U000025FB',
    -	"EmptyVerySmallSquare;":            '\U000025AB',
    -	"Eogon;":                           '\U00000118',
    -	"Eopf;":                            '\U0001D53C',
    -	"Epsilon;":                         '\U00000395',
    -	"Equal;":                           '\U00002A75',
    -	"EqualTilde;":                      '\U00002242',
    -	"Equilibrium;":                     '\U000021CC',
    -	"Escr;":                            '\U00002130',
    -	"Esim;":                            '\U00002A73',
    -	"Eta;":                             '\U00000397',
    -	"Euml;":                            '\U000000CB',
    -	"Exists;":                          '\U00002203',
    -	"ExponentialE;":                    '\U00002147',
    -	"Fcy;":                             '\U00000424',
    -	"Ffr;":                             '\U0001D509',
    -	"FilledSmallSquare;":               '\U000025FC',
    -	"FilledVerySmallSquare;":           '\U000025AA',
    -	"Fopf;":                            '\U0001D53D',
    -	"ForAll;":                          '\U00002200',
    -	"Fouriertrf;":                      '\U00002131',
    -	"Fscr;":                            '\U00002131',
    -	"GJcy;":                            '\U00000403',
    -	"GT;":                              '\U0000003E',
    -	"Gamma;":                           '\U00000393',
    -	"Gammad;":                          '\U000003DC',
    -	"Gbreve;":                          '\U0000011E',
    -	"Gcedil;":                          '\U00000122',
    -	"Gcirc;":                           '\U0000011C',
    -	"Gcy;":                             '\U00000413',
    -	"Gdot;":                            '\U00000120',
    -	"Gfr;":                             '\U0001D50A',
    -	"Gg;":                              '\U000022D9',
    -	"Gopf;":                            '\U0001D53E',
    -	"GreaterEqual;":                    '\U00002265',
    -	"GreaterEqualLess;":                '\U000022DB',
    -	"GreaterFullEqual;":                '\U00002267',
    -	"GreaterGreater;":                  '\U00002AA2',
    -	"GreaterLess;":                     '\U00002277',
    -	"GreaterSlantEqual;":               '\U00002A7E',
    -	"GreaterTilde;":                    '\U00002273',
    -	"Gscr;":                            '\U0001D4A2',
    -	"Gt;":                              '\U0000226B',
    -	"HARDcy;":                          '\U0000042A',
    -	"Hacek;":                           '\U000002C7',
    -	"Hat;":                             '\U0000005E',
    -	"Hcirc;":                           '\U00000124',
    -	"Hfr;":                             '\U0000210C',
    -	"HilbertSpace;":                    '\U0000210B',
    -	"Hopf;":                            '\U0000210D',
    -	"HorizontalLine;":                  '\U00002500',
    -	"Hscr;":                            '\U0000210B',
    -	"Hstrok;":                          '\U00000126',
    -	"HumpDownHump;":                    '\U0000224E',
    -	"HumpEqual;":                       '\U0000224F',
    -	"IEcy;":                            '\U00000415',
    -	"IJlig;":                           '\U00000132',
    -	"IOcy;":                            '\U00000401',
    -	"Iacute;":                          '\U000000CD',
    -	"Icirc;":                           '\U000000CE',
    -	"Icy;":                             '\U00000418',
    -	"Idot;":                            '\U00000130',
    -	"Ifr;":                             '\U00002111',
    -	"Igrave;":                          '\U000000CC',
    -	"Im;":                              '\U00002111',
    -	"Imacr;":                           '\U0000012A',
    -	"ImaginaryI;":                      '\U00002148',
    -	"Implies;":                         '\U000021D2',
    -	"Int;":                             '\U0000222C',
    -	"Integral;":                        '\U0000222B',
    -	"Intersection;":                    '\U000022C2',
    -	"InvisibleComma;":                  '\U00002063',
    -	"InvisibleTimes;":                  '\U00002062',
    -	"Iogon;":                           '\U0000012E',
    -	"Iopf;":                            '\U0001D540',
    -	"Iota;":                            '\U00000399',
    -	"Iscr;":                            '\U00002110',
    -	"Itilde;":                          '\U00000128',
    -	"Iukcy;":                           '\U00000406',
    -	"Iuml;":                            '\U000000CF',
    -	"Jcirc;":                           '\U00000134',
    -	"Jcy;":                             '\U00000419',
    -	"Jfr;":                             '\U0001D50D',
    -	"Jopf;":                            '\U0001D541',
    -	"Jscr;":                            '\U0001D4A5',
    -	"Jsercy;":                          '\U00000408',
    -	"Jukcy;":                           '\U00000404',
    -	"KHcy;":                            '\U00000425',
    -	"KJcy;":                            '\U0000040C',
    -	"Kappa;":                           '\U0000039A',
    -	"Kcedil;":                          '\U00000136',
    -	"Kcy;":                             '\U0000041A',
    -	"Kfr;":                             '\U0001D50E',
    -	"Kopf;":                            '\U0001D542',
    -	"Kscr;":                            '\U0001D4A6',
    -	"LJcy;":                            '\U00000409',
    -	"LT;":                              '\U0000003C',
    -	"Lacute;":                          '\U00000139',
    -	"Lambda;":                          '\U0000039B',
    -	"Lang;":                            '\U000027EA',
    -	"Laplacetrf;":                      '\U00002112',
    -	"Larr;":                            '\U0000219E',
    -	"Lcaron;":                          '\U0000013D',
    -	"Lcedil;":                          '\U0000013B',
    -	"Lcy;":                             '\U0000041B',
    -	"LeftAngleBracket;":                '\U000027E8',
    -	"LeftArrow;":                       '\U00002190',
    -	"LeftArrowBar;":                    '\U000021E4',
    -	"LeftArrowRightArrow;":             '\U000021C6',
    -	"LeftCeiling;":                     '\U00002308',
    -	"LeftDoubleBracket;":               '\U000027E6',
    -	"LeftDownTeeVector;":               '\U00002961',
    -	"LeftDownVector;":                  '\U000021C3',
    -	"LeftDownVectorBar;":               '\U00002959',
    -	"LeftFloor;":                       '\U0000230A',
    -	"LeftRightArrow;":                  '\U00002194',
    -	"LeftRightVector;":                 '\U0000294E',
    -	"LeftTee;":                         '\U000022A3',
    -	"LeftTeeArrow;":                    '\U000021A4',
    -	"LeftTeeVector;":                   '\U0000295A',
    -	"LeftTriangle;":                    '\U000022B2',
    -	"LeftTriangleBar;":                 '\U000029CF',
    -	"LeftTriangleEqual;":               '\U000022B4',
    -	"LeftUpDownVector;":                '\U00002951',
    -	"LeftUpTeeVector;":                 '\U00002960',
    -	"LeftUpVector;":                    '\U000021BF',
    -	"LeftUpVectorBar;":                 '\U00002958',
    -	"LeftVector;":                      '\U000021BC',
    -	"LeftVectorBar;":                   '\U00002952',
    -	"Leftarrow;":                       '\U000021D0',
    -	"Leftrightarrow;":                  '\U000021D4',
    -	"LessEqualGreater;":                '\U000022DA',
    -	"LessFullEqual;":                   '\U00002266',
    -	"LessGreater;":                     '\U00002276',
    -	"LessLess;":                        '\U00002AA1',
    -	"LessSlantEqual;":                  '\U00002A7D',
    -	"LessTilde;":                       '\U00002272',
    -	"Lfr;":                             '\U0001D50F',
    -	"Ll;":                              '\U000022D8',
    -	"Lleftarrow;":                      '\U000021DA',
    -	"Lmidot;":                          '\U0000013F',
    -	"LongLeftArrow;":                   '\U000027F5',
    -	"LongLeftRightArrow;":              '\U000027F7',
    -	"LongRightArrow;":                  '\U000027F6',
    -	"Longleftarrow;":                   '\U000027F8',
    -	"Longleftrightarrow;":              '\U000027FA',
    -	"Longrightarrow;":                  '\U000027F9',
    -	"Lopf;":                            '\U0001D543',
    -	"LowerLeftArrow;":                  '\U00002199',
    -	"LowerRightArrow;":                 '\U00002198',
    -	"Lscr;":                            '\U00002112',
    -	"Lsh;":                             '\U000021B0',
    -	"Lstrok;":                          '\U00000141',
    -	"Lt;":                              '\U0000226A',
    -	"Map;":                             '\U00002905',
    -	"Mcy;":                             '\U0000041C',
    -	"MediumSpace;":                     '\U0000205F',
    -	"Mellintrf;":                       '\U00002133',
    -	"Mfr;":                             '\U0001D510',
    -	"MinusPlus;":                       '\U00002213',
    -	"Mopf;":                            '\U0001D544',
    -	"Mscr;":                            '\U00002133',
    -	"Mu;":                              '\U0000039C',
    -	"NJcy;":                            '\U0000040A',
    -	"Nacute;":                          '\U00000143',
    -	"Ncaron;":                          '\U00000147',
    -	"Ncedil;":                          '\U00000145',
    -	"Ncy;":                             '\U0000041D',
    -	"NegativeMediumSpace;":             '\U0000200B',
    -	"NegativeThickSpace;":              '\U0000200B',
    -	"NegativeThinSpace;":               '\U0000200B',
    -	"NegativeVeryThinSpace;":           '\U0000200B',
    -	"NestedGreaterGreater;":            '\U0000226B',
    -	"NestedLessLess;":                  '\U0000226A',
    -	"NewLine;":                         '\U0000000A',
    -	"Nfr;":                             '\U0001D511',
    -	"NoBreak;":                         '\U00002060',
    -	"NonBreakingSpace;":                '\U000000A0',
    -	"Nopf;":                            '\U00002115',
    -	"Not;":                             '\U00002AEC',
    -	"NotCongruent;":                    '\U00002262',
    -	"NotCupCap;":                       '\U0000226D',
    -	"NotDoubleVerticalBar;":            '\U00002226',
    -	"NotElement;":                      '\U00002209',
    -	"NotEqual;":                        '\U00002260',
    -	"NotExists;":                       '\U00002204',
    -	"NotGreater;":                      '\U0000226F',
    -	"NotGreaterEqual;":                 '\U00002271',
    -	"NotGreaterLess;":                  '\U00002279',
    -	"NotGreaterTilde;":                 '\U00002275',
    -	"NotLeftTriangle;":                 '\U000022EA',
    -	"NotLeftTriangleEqual;":            '\U000022EC',
    -	"NotLess;":                         '\U0000226E',
    -	"NotLessEqual;":                    '\U00002270',
    -	"NotLessGreater;":                  '\U00002278',
    -	"NotLessTilde;":                    '\U00002274',
    -	"NotPrecedes;":                     '\U00002280',
    -	"NotPrecedesSlantEqual;":           '\U000022E0',
    -	"NotReverseElement;":               '\U0000220C',
    -	"NotRightTriangle;":                '\U000022EB',
    -	"NotRightTriangleEqual;":           '\U000022ED',
    -	"NotSquareSubsetEqual;":            '\U000022E2',
    -	"NotSquareSupersetEqual;":          '\U000022E3',
    -	"NotSubsetEqual;":                  '\U00002288',
    -	"NotSucceeds;":                     '\U00002281',
    -	"NotSucceedsSlantEqual;":           '\U000022E1',
    -	"NotSupersetEqual;":                '\U00002289',
    -	"NotTilde;":                        '\U00002241',
    -	"NotTildeEqual;":                   '\U00002244',
    -	"NotTildeFullEqual;":               '\U00002247',
    -	"NotTildeTilde;":                   '\U00002249',
    -	"NotVerticalBar;":                  '\U00002224',
    -	"Nscr;":                            '\U0001D4A9',
    -	"Ntilde;":                          '\U000000D1',
    -	"Nu;":                              '\U0000039D',
    -	"OElig;":                           '\U00000152',
    -	"Oacute;":                          '\U000000D3',
    -	"Ocirc;":                           '\U000000D4',
    -	"Ocy;":                             '\U0000041E',
    -	"Odblac;":                          '\U00000150',
    -	"Ofr;":                             '\U0001D512',
    -	"Ograve;":                          '\U000000D2',
    -	"Omacr;":                           '\U0000014C',
    -	"Omega;":                           '\U000003A9',
    -	"Omicron;":                         '\U0000039F',
    -	"Oopf;":                            '\U0001D546',
    -	"OpenCurlyDoubleQuote;":            '\U0000201C',
    -	"OpenCurlyQuote;":                  '\U00002018',
    -	"Or;":                              '\U00002A54',
    -	"Oscr;":                            '\U0001D4AA',
    -	"Oslash;":                          '\U000000D8',
    -	"Otilde;":                          '\U000000D5',
    -	"Otimes;":                          '\U00002A37',
    -	"Ouml;":                            '\U000000D6',
    -	"OverBar;":                         '\U0000203E',
    -	"OverBrace;":                       '\U000023DE',
    -	"OverBracket;":                     '\U000023B4',
    -	"OverParenthesis;":                 '\U000023DC',
    -	"PartialD;":                        '\U00002202',
    -	"Pcy;":                             '\U0000041F',
    -	"Pfr;":                             '\U0001D513',
    -	"Phi;":                             '\U000003A6',
    -	"Pi;":                              '\U000003A0',
    -	"PlusMinus;":                       '\U000000B1',
    -	"Poincareplane;":                   '\U0000210C',
    -	"Popf;":                            '\U00002119',
    -	"Pr;":                              '\U00002ABB',
    -	"Precedes;":                        '\U0000227A',
    -	"PrecedesEqual;":                   '\U00002AAF',
    -	"PrecedesSlantEqual;":              '\U0000227C',
    -	"PrecedesTilde;":                   '\U0000227E',
    -	"Prime;":                           '\U00002033',
    -	"Product;":                         '\U0000220F',
    -	"Proportion;":                      '\U00002237',
    -	"Proportional;":                    '\U0000221D',
    -	"Pscr;":                            '\U0001D4AB',
    -	"Psi;":                             '\U000003A8',
    -	"QUOT;":                            '\U00000022',
    -	"Qfr;":                             '\U0001D514',
    -	"Qopf;":                            '\U0000211A',
    -	"Qscr;":                            '\U0001D4AC',
    -	"RBarr;":                           '\U00002910',
    -	"REG;":                             '\U000000AE',
    -	"Racute;":                          '\U00000154',
    -	"Rang;":                            '\U000027EB',
    -	"Rarr;":                            '\U000021A0',
    -	"Rarrtl;":                          '\U00002916',
    -	"Rcaron;":                          '\U00000158',
    -	"Rcedil;":                          '\U00000156',
    -	"Rcy;":                             '\U00000420',
    -	"Re;":                              '\U0000211C',
    -	"ReverseElement;":                  '\U0000220B',
    -	"ReverseEquilibrium;":              '\U000021CB',
    -	"ReverseUpEquilibrium;":            '\U0000296F',
    -	"Rfr;":                             '\U0000211C',
    -	"Rho;":                             '\U000003A1',
    -	"RightAngleBracket;":               '\U000027E9',
    -	"RightArrow;":                      '\U00002192',
    -	"RightArrowBar;":                   '\U000021E5',
    -	"RightArrowLeftArrow;":             '\U000021C4',
    -	"RightCeiling;":                    '\U00002309',
    -	"RightDoubleBracket;":              '\U000027E7',
    -	"RightDownTeeVector;":              '\U0000295D',
    -	"RightDownVector;":                 '\U000021C2',
    -	"RightDownVectorBar;":              '\U00002955',
    -	"RightFloor;":                      '\U0000230B',
    -	"RightTee;":                        '\U000022A2',
    -	"RightTeeArrow;":                   '\U000021A6',
    -	"RightTeeVector;":                  '\U0000295B',
    -	"RightTriangle;":                   '\U000022B3',
    -	"RightTriangleBar;":                '\U000029D0',
    -	"RightTriangleEqual;":              '\U000022B5',
    -	"RightUpDownVector;":               '\U0000294F',
    -	"RightUpTeeVector;":                '\U0000295C',
    -	"RightUpVector;":                   '\U000021BE',
    -	"RightUpVectorBar;":                '\U00002954',
    -	"RightVector;":                     '\U000021C0',
    -	"RightVectorBar;":                  '\U00002953',
    -	"Rightarrow;":                      '\U000021D2',
    -	"Ropf;":                            '\U0000211D',
    -	"RoundImplies;":                    '\U00002970',
    -	"Rrightarrow;":                     '\U000021DB',
    -	"Rscr;":                            '\U0000211B',
    -	"Rsh;":                             '\U000021B1',
    -	"RuleDelayed;":                     '\U000029F4',
    -	"SHCHcy;":                          '\U00000429',
    -	"SHcy;":                            '\U00000428',
    -	"SOFTcy;":                          '\U0000042C',
    -	"Sacute;":                          '\U0000015A',
    -	"Sc;":                              '\U00002ABC',
    -	"Scaron;":                          '\U00000160',
    -	"Scedil;":                          '\U0000015E',
    -	"Scirc;":                           '\U0000015C',
    -	"Scy;":                             '\U00000421',
    -	"Sfr;":                             '\U0001D516',
    -	"ShortDownArrow;":                  '\U00002193',
    -	"ShortLeftArrow;":                  '\U00002190',
    -	"ShortRightArrow;":                 '\U00002192',
    -	"ShortUpArrow;":                    '\U00002191',
    -	"Sigma;":                           '\U000003A3',
    -	"SmallCircle;":                     '\U00002218',
    -	"Sopf;":                            '\U0001D54A',
    -	"Sqrt;":                            '\U0000221A',
    -	"Square;":                          '\U000025A1',
    -	"SquareIntersection;":              '\U00002293',
    -	"SquareSubset;":                    '\U0000228F',
    -	"SquareSubsetEqual;":               '\U00002291',
    -	"SquareSuperset;":                  '\U00002290',
    -	"SquareSupersetEqual;":             '\U00002292',
    -	"SquareUnion;":                     '\U00002294',
    -	"Sscr;":                            '\U0001D4AE',
    -	"Star;":                            '\U000022C6',
    -	"Sub;":                             '\U000022D0',
    -	"Subset;":                          '\U000022D0',
    -	"SubsetEqual;":                     '\U00002286',
    -	"Succeeds;":                        '\U0000227B',
    -	"SucceedsEqual;":                   '\U00002AB0',
    -	"SucceedsSlantEqual;":              '\U0000227D',
    -	"SucceedsTilde;":                   '\U0000227F',
    -	"SuchThat;":                        '\U0000220B',
    -	"Sum;":                             '\U00002211',
    -	"Sup;":                             '\U000022D1',
    -	"Superset;":                        '\U00002283',
    -	"SupersetEqual;":                   '\U00002287',
    -	"Supset;":                          '\U000022D1',
    -	"THORN;":                           '\U000000DE',
    -	"TRADE;":                           '\U00002122',
    -	"TSHcy;":                           '\U0000040B',
    -	"TScy;":                            '\U00000426',
    -	"Tab;":                             '\U00000009',
    -	"Tau;":                             '\U000003A4',
    -	"Tcaron;":                          '\U00000164',
    -	"Tcedil;":                          '\U00000162',
    -	"Tcy;":                             '\U00000422',
    -	"Tfr;":                             '\U0001D517',
    -	"Therefore;":                       '\U00002234',
    -	"Theta;":                           '\U00000398',
    -	"ThinSpace;":                       '\U00002009',
    -	"Tilde;":                           '\U0000223C',
    -	"TildeEqual;":                      '\U00002243',
    -	"TildeFullEqual;":                  '\U00002245',
    -	"TildeTilde;":                      '\U00002248',
    -	"Topf;":                            '\U0001D54B',
    -	"TripleDot;":                       '\U000020DB',
    -	"Tscr;":                            '\U0001D4AF',
    -	"Tstrok;":                          '\U00000166',
    -	"Uacute;":                          '\U000000DA',
    -	"Uarr;":                            '\U0000219F',
    -	"Uarrocir;":                        '\U00002949',
    -	"Ubrcy;":                           '\U0000040E',
    -	"Ubreve;":                          '\U0000016C',
    -	"Ucirc;":                           '\U000000DB',
    -	"Ucy;":                             '\U00000423',
    -	"Udblac;":                          '\U00000170',
    -	"Ufr;":                             '\U0001D518',
    -	"Ugrave;":                          '\U000000D9',
    -	"Umacr;":                           '\U0000016A',
    -	"UnderBar;":                        '\U0000005F',
    -	"UnderBrace;":                      '\U000023DF',
    -	"UnderBracket;":                    '\U000023B5',
    -	"UnderParenthesis;":                '\U000023DD',
    -	"Union;":                           '\U000022C3',
    -	"UnionPlus;":                       '\U0000228E',
    -	"Uogon;":                           '\U00000172',
    -	"Uopf;":                            '\U0001D54C',
    -	"UpArrow;":                         '\U00002191',
    -	"UpArrowBar;":                      '\U00002912',
    -	"UpArrowDownArrow;":                '\U000021C5',
    -	"UpDownArrow;":                     '\U00002195',
    -	"UpEquilibrium;":                   '\U0000296E',
    -	"UpTee;":                           '\U000022A5',
    -	"UpTeeArrow;":                      '\U000021A5',
    -	"Uparrow;":                         '\U000021D1',
    -	"Updownarrow;":                     '\U000021D5',
    -	"UpperLeftArrow;":                  '\U00002196',
    -	"UpperRightArrow;":                 '\U00002197',
    -	"Upsi;":                            '\U000003D2',
    -	"Upsilon;":                         '\U000003A5',
    -	"Uring;":                           '\U0000016E',
    -	"Uscr;":                            '\U0001D4B0',
    -	"Utilde;":                          '\U00000168',
    -	"Uuml;":                            '\U000000DC',
    -	"VDash;":                           '\U000022AB',
    -	"Vbar;":                            '\U00002AEB',
    -	"Vcy;":                             '\U00000412',
    -	"Vdash;":                           '\U000022A9',
    -	"Vdashl;":                          '\U00002AE6',
    -	"Vee;":                             '\U000022C1',
    -	"Verbar;":                          '\U00002016',
    -	"Vert;":                            '\U00002016',
    -	"VerticalBar;":                     '\U00002223',
    -	"VerticalLine;":                    '\U0000007C',
    -	"VerticalSeparator;":               '\U00002758',
    -	"VerticalTilde;":                   '\U00002240',
    -	"VeryThinSpace;":                   '\U0000200A',
    -	"Vfr;":                             '\U0001D519',
    -	"Vopf;":                            '\U0001D54D',
    -	"Vscr;":                            '\U0001D4B1',
    -	"Vvdash;":                          '\U000022AA',
    -	"Wcirc;":                           '\U00000174',
    -	"Wedge;":                           '\U000022C0',
    -	"Wfr;":                             '\U0001D51A',
    -	"Wopf;":                            '\U0001D54E',
    -	"Wscr;":                            '\U0001D4B2',
    -	"Xfr;":                             '\U0001D51B',
    -	"Xi;":                              '\U0000039E',
    -	"Xopf;":                            '\U0001D54F',
    -	"Xscr;":                            '\U0001D4B3',
    -	"YAcy;":                            '\U0000042F',
    -	"YIcy;":                            '\U00000407',
    -	"YUcy;":                            '\U0000042E',
    -	"Yacute;":                          '\U000000DD',
    -	"Ycirc;":                           '\U00000176',
    -	"Ycy;":                             '\U0000042B',
    -	"Yfr;":                             '\U0001D51C',
    -	"Yopf;":                            '\U0001D550',
    -	"Yscr;":                            '\U0001D4B4',
    -	"Yuml;":                            '\U00000178',
    -	"ZHcy;":                            '\U00000416',
    -	"Zacute;":                          '\U00000179',
    -	"Zcaron;":                          '\U0000017D',
    -	"Zcy;":                             '\U00000417',
    -	"Zdot;":                            '\U0000017B',
    -	"ZeroWidthSpace;":                  '\U0000200B',
    -	"Zeta;":                            '\U00000396',
    -	"Zfr;":                             '\U00002128',
    -	"Zopf;":                            '\U00002124',
    -	"Zscr;":                            '\U0001D4B5',
    -	"aacute;":                          '\U000000E1',
    -	"abreve;":                          '\U00000103',
    -	"ac;":                              '\U0000223E',
    -	"acd;":                             '\U0000223F',
    -	"acirc;":                           '\U000000E2',
    -	"acute;":                           '\U000000B4',
    -	"acy;":                             '\U00000430',
    -	"aelig;":                           '\U000000E6',
    -	"af;":                              '\U00002061',
    -	"afr;":                             '\U0001D51E',
    -	"agrave;":                          '\U000000E0',
    -	"alefsym;":                         '\U00002135',
    -	"aleph;":                           '\U00002135',
    -	"alpha;":                           '\U000003B1',
    -	"amacr;":                           '\U00000101',
    -	"amalg;":                           '\U00002A3F',
    -	"amp;":                             '\U00000026',
    -	"and;":                             '\U00002227',
    -	"andand;":                          '\U00002A55',
    -	"andd;":                            '\U00002A5C',
    -	"andslope;":                        '\U00002A58',
    -	"andv;":                            '\U00002A5A',
    -	"ang;":                             '\U00002220',
    -	"ange;":                            '\U000029A4',
    -	"angle;":                           '\U00002220',
    -	"angmsd;":                          '\U00002221',
    -	"angmsdaa;":                        '\U000029A8',
    -	"angmsdab;":                        '\U000029A9',
    -	"angmsdac;":                        '\U000029AA',
    -	"angmsdad;":                        '\U000029AB',
    -	"angmsdae;":                        '\U000029AC',
    -	"angmsdaf;":                        '\U000029AD',
    -	"angmsdag;":                        '\U000029AE',
    -	"angmsdah;":                        '\U000029AF',
    -	"angrt;":                           '\U0000221F',
    -	"angrtvb;":                         '\U000022BE',
    -	"angrtvbd;":                        '\U0000299D',
    -	"angsph;":                          '\U00002222',
    -	"angst;":                           '\U000000C5',
    -	"angzarr;":                         '\U0000237C',
    -	"aogon;":                           '\U00000105',
    -	"aopf;":                            '\U0001D552',
    -	"ap;":                              '\U00002248',
    -	"apE;":                             '\U00002A70',
    -	"apacir;":                          '\U00002A6F',
    -	"ape;":                             '\U0000224A',
    -	"apid;":                            '\U0000224B',
    -	"apos;":                            '\U00000027',
    -	"approx;":                          '\U00002248',
    -	"approxeq;":                        '\U0000224A',
    -	"aring;":                           '\U000000E5',
    -	"ascr;":                            '\U0001D4B6',
    -	"ast;":                             '\U0000002A',
    -	"asymp;":                           '\U00002248',
    -	"asympeq;":                         '\U0000224D',
    -	"atilde;":                          '\U000000E3',
    -	"auml;":                            '\U000000E4',
    -	"awconint;":                        '\U00002233',
    -	"awint;":                           '\U00002A11',
    -	"bNot;":                            '\U00002AED',
    -	"backcong;":                        '\U0000224C',
    -	"backepsilon;":                     '\U000003F6',
    -	"backprime;":                       '\U00002035',
    -	"backsim;":                         '\U0000223D',
    -	"backsimeq;":                       '\U000022CD',
    -	"barvee;":                          '\U000022BD',
    -	"barwed;":                          '\U00002305',
    -	"barwedge;":                        '\U00002305',
    -	"bbrk;":                            '\U000023B5',
    -	"bbrktbrk;":                        '\U000023B6',
    -	"bcong;":                           '\U0000224C',
    -	"bcy;":                             '\U00000431',
    -	"bdquo;":                           '\U0000201E',
    -	"becaus;":                          '\U00002235',
    -	"because;":                         '\U00002235',
    -	"bemptyv;":                         '\U000029B0',
    -	"bepsi;":                           '\U000003F6',
    -	"bernou;":                          '\U0000212C',
    -	"beta;":                            '\U000003B2',
    -	"beth;":                            '\U00002136',
    -	"between;":                         '\U0000226C',
    -	"bfr;":                             '\U0001D51F',
    -	"bigcap;":                          '\U000022C2',
    -	"bigcirc;":                         '\U000025EF',
    -	"bigcup;":                          '\U000022C3',
    -	"bigodot;":                         '\U00002A00',
    -	"bigoplus;":                        '\U00002A01',
    -	"bigotimes;":                       '\U00002A02',
    -	"bigsqcup;":                        '\U00002A06',
    -	"bigstar;":                         '\U00002605',
    -	"bigtriangledown;":                 '\U000025BD',
    -	"bigtriangleup;":                   '\U000025B3',
    -	"biguplus;":                        '\U00002A04',
    -	"bigvee;":                          '\U000022C1',
    -	"bigwedge;":                        '\U000022C0',
    -	"bkarow;":                          '\U0000290D',
    -	"blacklozenge;":                    '\U000029EB',
    -	"blacksquare;":                     '\U000025AA',
    -	"blacktriangle;":                   '\U000025B4',
    -	"blacktriangledown;":               '\U000025BE',
    -	"blacktriangleleft;":               '\U000025C2',
    -	"blacktriangleright;":              '\U000025B8',
    -	"blank;":                           '\U00002423',
    -	"blk12;":                           '\U00002592',
    -	"blk14;":                           '\U00002591',
    -	"blk34;":                           '\U00002593',
    -	"block;":                           '\U00002588',
    -	"bnot;":                            '\U00002310',
    -	"bopf;":                            '\U0001D553',
    -	"bot;":                             '\U000022A5',
    -	"bottom;":                          '\U000022A5',
    -	"bowtie;":                          '\U000022C8',
    -	"boxDL;":                           '\U00002557',
    -	"boxDR;":                           '\U00002554',
    -	"boxDl;":                           '\U00002556',
    -	"boxDr;":                           '\U00002553',
    -	"boxH;":                            '\U00002550',
    -	"boxHD;":                           '\U00002566',
    -	"boxHU;":                           '\U00002569',
    -	"boxHd;":                           '\U00002564',
    -	"boxHu;":                           '\U00002567',
    -	"boxUL;":                           '\U0000255D',
    -	"boxUR;":                           '\U0000255A',
    -	"boxUl;":                           '\U0000255C',
    -	"boxUr;":                           '\U00002559',
    -	"boxV;":                            '\U00002551',
    -	"boxVH;":                           '\U0000256C',
    -	"boxVL;":                           '\U00002563',
    -	"boxVR;":                           '\U00002560',
    -	"boxVh;":                           '\U0000256B',
    -	"boxVl;":                           '\U00002562',
    -	"boxVr;":                           '\U0000255F',
    -	"boxbox;":                          '\U000029C9',
    -	"boxdL;":                           '\U00002555',
    -	"boxdR;":                           '\U00002552',
    -	"boxdl;":                           '\U00002510',
    -	"boxdr;":                           '\U0000250C',
    -	"boxh;":                            '\U00002500',
    -	"boxhD;":                           '\U00002565',
    -	"boxhU;":                           '\U00002568',
    -	"boxhd;":                           '\U0000252C',
    -	"boxhu;":                           '\U00002534',
    -	"boxminus;":                        '\U0000229F',
    -	"boxplus;":                         '\U0000229E',
    -	"boxtimes;":                        '\U000022A0',
    -	"boxuL;":                           '\U0000255B',
    -	"boxuR;":                           '\U00002558',
    -	"boxul;":                           '\U00002518',
    -	"boxur;":                           '\U00002514',
    -	"boxv;":                            '\U00002502',
    -	"boxvH;":                           '\U0000256A',
    -	"boxvL;":                           '\U00002561',
    -	"boxvR;":                           '\U0000255E',
    -	"boxvh;":                           '\U0000253C',
    -	"boxvl;":                           '\U00002524',
    -	"boxvr;":                           '\U0000251C',
    -	"bprime;":                          '\U00002035',
    -	"breve;":                           '\U000002D8',
    -	"brvbar;":                          '\U000000A6',
    -	"bscr;":                            '\U0001D4B7',
    -	"bsemi;":                           '\U0000204F',
    -	"bsim;":                            '\U0000223D',
    -	"bsime;":                           '\U000022CD',
    -	"bsol;":                            '\U0000005C',
    -	"bsolb;":                           '\U000029C5',
    -	"bsolhsub;":                        '\U000027C8',
    -	"bull;":                            '\U00002022',
    -	"bullet;":                          '\U00002022',
    -	"bump;":                            '\U0000224E',
    -	"bumpE;":                           '\U00002AAE',
    -	"bumpe;":                           '\U0000224F',
    -	"bumpeq;":                          '\U0000224F',
    -	"cacute;":                          '\U00000107',
    -	"cap;":                             '\U00002229',
    -	"capand;":                          '\U00002A44',
    -	"capbrcup;":                        '\U00002A49',
    -	"capcap;":                          '\U00002A4B',
    -	"capcup;":                          '\U00002A47',
    -	"capdot;":                          '\U00002A40',
    -	"caret;":                           '\U00002041',
    -	"caron;":                           '\U000002C7',
    -	"ccaps;":                           '\U00002A4D',
    -	"ccaron;":                          '\U0000010D',
    -	"ccedil;":                          '\U000000E7',
    -	"ccirc;":                           '\U00000109',
    -	"ccups;":                           '\U00002A4C',
    -	"ccupssm;":                         '\U00002A50',
    -	"cdot;":                            '\U0000010B',
    -	"cedil;":                           '\U000000B8',
    -	"cemptyv;":                         '\U000029B2',
    -	"cent;":                            '\U000000A2',
    -	"centerdot;":                       '\U000000B7',
    -	"cfr;":                             '\U0001D520',
    -	"chcy;":                            '\U00000447',
    -	"check;":                           '\U00002713',
    -	"checkmark;":                       '\U00002713',
    -	"chi;":                             '\U000003C7',
    -	"cir;":                             '\U000025CB',
    -	"cirE;":                            '\U000029C3',
    -	"circ;":                            '\U000002C6',
    -	"circeq;":                          '\U00002257',
    -	"circlearrowleft;":                 '\U000021BA',
    -	"circlearrowright;":                '\U000021BB',
    -	"circledR;":                        '\U000000AE',
    -	"circledS;":                        '\U000024C8',
    -	"circledast;":                      '\U0000229B',
    -	"circledcirc;":                     '\U0000229A',
    -	"circleddash;":                     '\U0000229D',
    -	"cire;":                            '\U00002257',
    -	"cirfnint;":                        '\U00002A10',
    -	"cirmid;":                          '\U00002AEF',
    -	"cirscir;":                         '\U000029C2',
    -	"clubs;":                           '\U00002663',
    -	"clubsuit;":                        '\U00002663',
    -	"colon;":                           '\U0000003A',
    -	"colone;":                          '\U00002254',
    -	"coloneq;":                         '\U00002254',
    -	"comma;":                           '\U0000002C',
    -	"commat;":                          '\U00000040',
    -	"comp;":                            '\U00002201',
    -	"compfn;":                          '\U00002218',
    -	"complement;":                      '\U00002201',
    -	"complexes;":                       '\U00002102',
    -	"cong;":                            '\U00002245',
    -	"congdot;":                         '\U00002A6D',
    -	"conint;":                          '\U0000222E',
    -	"copf;":                            '\U0001D554',
    -	"coprod;":                          '\U00002210',
    -	"copy;":                            '\U000000A9',
    -	"copysr;":                          '\U00002117',
    -	"crarr;":                           '\U000021B5',
    -	"cross;":                           '\U00002717',
    -	"cscr;":                            '\U0001D4B8',
    -	"csub;":                            '\U00002ACF',
    -	"csube;":                           '\U00002AD1',
    -	"csup;":                            '\U00002AD0',
    -	"csupe;":                           '\U00002AD2',
    -	"ctdot;":                           '\U000022EF',
    -	"cudarrl;":                         '\U00002938',
    -	"cudarrr;":                         '\U00002935',
    -	"cuepr;":                           '\U000022DE',
    -	"cuesc;":                           '\U000022DF',
    -	"cularr;":                          '\U000021B6',
    -	"cularrp;":                         '\U0000293D',
    -	"cup;":                             '\U0000222A',
    -	"cupbrcap;":                        '\U00002A48',
    -	"cupcap;":                          '\U00002A46',
    -	"cupcup;":                          '\U00002A4A',
    -	"cupdot;":                          '\U0000228D',
    -	"cupor;":                           '\U00002A45',
    -	"curarr;":                          '\U000021B7',
    -	"curarrm;":                         '\U0000293C',
    -	"curlyeqprec;":                     '\U000022DE',
    -	"curlyeqsucc;":                     '\U000022DF',
    -	"curlyvee;":                        '\U000022CE',
    -	"curlywedge;":                      '\U000022CF',
    -	"curren;":                          '\U000000A4',
    -	"curvearrowleft;":                  '\U000021B6',
    -	"curvearrowright;":                 '\U000021B7',
    -	"cuvee;":                           '\U000022CE',
    -	"cuwed;":                           '\U000022CF',
    -	"cwconint;":                        '\U00002232',
    -	"cwint;":                           '\U00002231',
    -	"cylcty;":                          '\U0000232D',
    -	"dArr;":                            '\U000021D3',
    -	"dHar;":                            '\U00002965',
    -	"dagger;":                          '\U00002020',
    -	"daleth;":                          '\U00002138',
    -	"darr;":                            '\U00002193',
    -	"dash;":                            '\U00002010',
    -	"dashv;":                           '\U000022A3',
    -	"dbkarow;":                         '\U0000290F',
    -	"dblac;":                           '\U000002DD',
    -	"dcaron;":                          '\U0000010F',
    -	"dcy;":                             '\U00000434',
    -	"dd;":                              '\U00002146',
    -	"ddagger;":                         '\U00002021',
    -	"ddarr;":                           '\U000021CA',
    -	"ddotseq;":                         '\U00002A77',
    -	"deg;":                             '\U000000B0',
    -	"delta;":                           '\U000003B4',
    -	"demptyv;":                         '\U000029B1',
    -	"dfisht;":                          '\U0000297F',
    -	"dfr;":                             '\U0001D521',
    -	"dharl;":                           '\U000021C3',
    -	"dharr;":                           '\U000021C2',
    -	"diam;":                            '\U000022C4',
    -	"diamond;":                         '\U000022C4',
    -	"diamondsuit;":                     '\U00002666',
    -	"diams;":                           '\U00002666',
    -	"die;":                             '\U000000A8',
    -	"digamma;":                         '\U000003DD',
    -	"disin;":                           '\U000022F2',
    -	"div;":                             '\U000000F7',
    -	"divide;":                          '\U000000F7',
    -	"divideontimes;":                   '\U000022C7',
    -	"divonx;":                          '\U000022C7',
    -	"djcy;":                            '\U00000452',
    -	"dlcorn;":                          '\U0000231E',
    -	"dlcrop;":                          '\U0000230D',
    -	"dollar;":                          '\U00000024',
    -	"dopf;":                            '\U0001D555',
    -	"dot;":                             '\U000002D9',
    -	"doteq;":                           '\U00002250',
    -	"doteqdot;":                        '\U00002251',
    -	"dotminus;":                        '\U00002238',
    -	"dotplus;":                         '\U00002214',
    -	"dotsquare;":                       '\U000022A1',
    -	"doublebarwedge;":                  '\U00002306',
    -	"downarrow;":                       '\U00002193',
    -	"downdownarrows;":                  '\U000021CA',
    -	"downharpoonleft;":                 '\U000021C3',
    -	"downharpoonright;":                '\U000021C2',
    -	"drbkarow;":                        '\U00002910',
    -	"drcorn;":                          '\U0000231F',
    -	"drcrop;":                          '\U0000230C',
    -	"dscr;":                            '\U0001D4B9',
    -	"dscy;":                            '\U00000455',
    -	"dsol;":                            '\U000029F6',
    -	"dstrok;":                          '\U00000111',
    -	"dtdot;":                           '\U000022F1',
    -	"dtri;":                            '\U000025BF',
    -	"dtrif;":                           '\U000025BE',
    -	"duarr;":                           '\U000021F5',
    -	"duhar;":                           '\U0000296F',
    -	"dwangle;":                         '\U000029A6',
    -	"dzcy;":                            '\U0000045F',
    -	"dzigrarr;":                        '\U000027FF',
    -	"eDDot;":                           '\U00002A77',
    -	"eDot;":                            '\U00002251',
    -	"eacute;":                          '\U000000E9',
    -	"easter;":                          '\U00002A6E',
    -	"ecaron;":                          '\U0000011B',
    -	"ecir;":                            '\U00002256',
    -	"ecirc;":                           '\U000000EA',
    -	"ecolon;":                          '\U00002255',
    -	"ecy;":                             '\U0000044D',
    -	"edot;":                            '\U00000117',
    -	"ee;":                              '\U00002147',
    -	"efDot;":                           '\U00002252',
    -	"efr;":                             '\U0001D522',
    -	"eg;":                              '\U00002A9A',
    -	"egrave;":                          '\U000000E8',
    -	"egs;":                             '\U00002A96',
    -	"egsdot;":                          '\U00002A98',
    -	"el;":                              '\U00002A99',
    -	"elinters;":                        '\U000023E7',
    -	"ell;":                             '\U00002113',
    -	"els;":                             '\U00002A95',
    -	"elsdot;":                          '\U00002A97',
    -	"emacr;":                           '\U00000113',
    -	"empty;":                           '\U00002205',
    -	"emptyset;":                        '\U00002205',
    -	"emptyv;":                          '\U00002205',
    -	"emsp;":                            '\U00002003',
    -	"emsp13;":                          '\U00002004',
    -	"emsp14;":                          '\U00002005',
    -	"eng;":                             '\U0000014B',
    -	"ensp;":                            '\U00002002',
    -	"eogon;":                           '\U00000119',
    -	"eopf;":                            '\U0001D556',
    -	"epar;":                            '\U000022D5',
    -	"eparsl;":                          '\U000029E3',
    -	"eplus;":                           '\U00002A71',
    -	"epsi;":                            '\U000003B5',
    -	"epsilon;":                         '\U000003B5',
    -	"epsiv;":                           '\U000003F5',
    -	"eqcirc;":                          '\U00002256',
    -	"eqcolon;":                         '\U00002255',
    -	"eqsim;":                           '\U00002242',
    -	"eqslantgtr;":                      '\U00002A96',
    -	"eqslantless;":                     '\U00002A95',
    -	"equals;":                          '\U0000003D',
    -	"equest;":                          '\U0000225F',
    -	"equiv;":                           '\U00002261',
    -	"equivDD;":                         '\U00002A78',
    -	"eqvparsl;":                        '\U000029E5',
    -	"erDot;":                           '\U00002253',
    -	"erarr;":                           '\U00002971',
    -	"escr;":                            '\U0000212F',
    -	"esdot;":                           '\U00002250',
    -	"esim;":                            '\U00002242',
    -	"eta;":                             '\U000003B7',
    -	"eth;":                             '\U000000F0',
    -	"euml;":                            '\U000000EB',
    -	"euro;":                            '\U000020AC',
    -	"excl;":                            '\U00000021',
    -	"exist;":                           '\U00002203',
    -	"expectation;":                     '\U00002130',
    -	"exponentiale;":                    '\U00002147',
    -	"fallingdotseq;":                   '\U00002252',
    -	"fcy;":                             '\U00000444',
    -	"female;":                          '\U00002640',
    -	"ffilig;":                          '\U0000FB03',
    -	"fflig;":                           '\U0000FB00',
    -	"ffllig;":                          '\U0000FB04',
    -	"ffr;":                             '\U0001D523',
    -	"filig;":                           '\U0000FB01',
    -	"flat;":                            '\U0000266D',
    -	"fllig;":                           '\U0000FB02',
    -	"fltns;":                           '\U000025B1',
    -	"fnof;":                            '\U00000192',
    -	"fopf;":                            '\U0001D557',
    -	"forall;":                          '\U00002200',
    -	"fork;":                            '\U000022D4',
    -	"forkv;":                           '\U00002AD9',
    -	"fpartint;":                        '\U00002A0D',
    -	"frac12;":                          '\U000000BD',
    -	"frac13;":                          '\U00002153',
    -	"frac14;":                          '\U000000BC',
    -	"frac15;":                          '\U00002155',
    -	"frac16;":                          '\U00002159',
    -	"frac18;":                          '\U0000215B',
    -	"frac23;":                          '\U00002154',
    -	"frac25;":                          '\U00002156',
    -	"frac34;":                          '\U000000BE',
    -	"frac35;":                          '\U00002157',
    -	"frac38;":                          '\U0000215C',
    -	"frac45;":                          '\U00002158',
    -	"frac56;":                          '\U0000215A',
    -	"frac58;":                          '\U0000215D',
    -	"frac78;":                          '\U0000215E',
    -	"frasl;":                           '\U00002044',
    -	"frown;":                           '\U00002322',
    -	"fscr;":                            '\U0001D4BB',
    -	"gE;":                              '\U00002267',
    -	"gEl;":                             '\U00002A8C',
    -	"gacute;":                          '\U000001F5',
    -	"gamma;":                           '\U000003B3',
    -	"gammad;":                          '\U000003DD',
    -	"gap;":                             '\U00002A86',
    -	"gbreve;":                          '\U0000011F',
    -	"gcirc;":                           '\U0000011D',
    -	"gcy;":                             '\U00000433',
    -	"gdot;":                            '\U00000121',
    -	"ge;":                              '\U00002265',
    -	"gel;":                             '\U000022DB',
    -	"geq;":                             '\U00002265',
    -	"geqq;":                            '\U00002267',
    -	"geqslant;":                        '\U00002A7E',
    -	"ges;":                             '\U00002A7E',
    -	"gescc;":                           '\U00002AA9',
    -	"gesdot;":                          '\U00002A80',
    -	"gesdoto;":                         '\U00002A82',
    -	"gesdotol;":                        '\U00002A84',
    -	"gesles;":                          '\U00002A94',
    -	"gfr;":                             '\U0001D524',
    -	"gg;":                              '\U0000226B',
    -	"ggg;":                             '\U000022D9',
    -	"gimel;":                           '\U00002137',
    -	"gjcy;":                            '\U00000453',
    -	"gl;":                              '\U00002277',
    -	"glE;":                             '\U00002A92',
    -	"gla;":                             '\U00002AA5',
    -	"glj;":                             '\U00002AA4',
    -	"gnE;":                             '\U00002269',
    -	"gnap;":                            '\U00002A8A',
    -	"gnapprox;":                        '\U00002A8A',
    -	"gne;":                             '\U00002A88',
    -	"gneq;":                            '\U00002A88',
    -	"gneqq;":                           '\U00002269',
    -	"gnsim;":                           '\U000022E7',
    -	"gopf;":                            '\U0001D558',
    -	"grave;":                           '\U00000060',
    -	"gscr;":                            '\U0000210A',
    -	"gsim;":                            '\U00002273',
    -	"gsime;":                           '\U00002A8E',
    -	"gsiml;":                           '\U00002A90',
    -	"gt;":                              '\U0000003E',
    -	"gtcc;":                            '\U00002AA7',
    -	"gtcir;":                           '\U00002A7A',
    -	"gtdot;":                           '\U000022D7',
    -	"gtlPar;":                          '\U00002995',
    -	"gtquest;":                         '\U00002A7C',
    -	"gtrapprox;":                       '\U00002A86',
    -	"gtrarr;":                          '\U00002978',
    -	"gtrdot;":                          '\U000022D7',
    -	"gtreqless;":                       '\U000022DB',
    -	"gtreqqless;":                      '\U00002A8C',
    -	"gtrless;":                         '\U00002277',
    -	"gtrsim;":                          '\U00002273',
    -	"hArr;":                            '\U000021D4',
    -	"hairsp;":                          '\U0000200A',
    -	"half;":                            '\U000000BD',
    -	"hamilt;":                          '\U0000210B',
    -	"hardcy;":                          '\U0000044A',
    -	"harr;":                            '\U00002194',
    -	"harrcir;":                         '\U00002948',
    -	"harrw;":                           '\U000021AD',
    -	"hbar;":                            '\U0000210F',
    -	"hcirc;":                           '\U00000125',
    -	"hearts;":                          '\U00002665',
    -	"heartsuit;":                       '\U00002665',
    -	"hellip;":                          '\U00002026',
    -	"hercon;":                          '\U000022B9',
    -	"hfr;":                             '\U0001D525',
    -	"hksearow;":                        '\U00002925',
    -	"hkswarow;":                        '\U00002926',
    -	"hoarr;":                           '\U000021FF',
    -	"homtht;":                          '\U0000223B',
    -	"hookleftarrow;":                   '\U000021A9',
    -	"hookrightarrow;":                  '\U000021AA',
    -	"hopf;":                            '\U0001D559',
    -	"horbar;":                          '\U00002015',
    -	"hscr;":                            '\U0001D4BD',
    -	"hslash;":                          '\U0000210F',
    -	"hstrok;":                          '\U00000127',
    -	"hybull;":                          '\U00002043',
    -	"hyphen;":                          '\U00002010',
    -	"iacute;":                          '\U000000ED',
    -	"ic;":                              '\U00002063',
    -	"icirc;":                           '\U000000EE',
    -	"icy;":                             '\U00000438',
    -	"iecy;":                            '\U00000435',
    -	"iexcl;":                           '\U000000A1',
    -	"iff;":                             '\U000021D4',
    -	"ifr;":                             '\U0001D526',
    -	"igrave;":                          '\U000000EC',
    -	"ii;":                              '\U00002148',
    -	"iiiint;":                          '\U00002A0C',
    -	"iiint;":                           '\U0000222D',
    -	"iinfin;":                          '\U000029DC',
    -	"iiota;":                           '\U00002129',
    -	"ijlig;":                           '\U00000133',
    -	"imacr;":                           '\U0000012B',
    -	"image;":                           '\U00002111',
    -	"imagline;":                        '\U00002110',
    -	"imagpart;":                        '\U00002111',
    -	"imath;":                           '\U00000131',
    -	"imof;":                            '\U000022B7',
    -	"imped;":                           '\U000001B5',
    -	"in;":                              '\U00002208',
    -	"incare;":                          '\U00002105',
    -	"infin;":                           '\U0000221E',
    -	"infintie;":                        '\U000029DD',
    -	"inodot;":                          '\U00000131',
    -	"int;":                             '\U0000222B',
    -	"intcal;":                          '\U000022BA',
    -	"integers;":                        '\U00002124',
    -	"intercal;":                        '\U000022BA',
    -	"intlarhk;":                        '\U00002A17',
    -	"intprod;":                         '\U00002A3C',
    -	"iocy;":                            '\U00000451',
    -	"iogon;":                           '\U0000012F',
    -	"iopf;":                            '\U0001D55A',
    -	"iota;":                            '\U000003B9',
    -	"iprod;":                           '\U00002A3C',
    -	"iquest;":                          '\U000000BF',
    -	"iscr;":                            '\U0001D4BE',
    -	"isin;":                            '\U00002208',
    -	"isinE;":                           '\U000022F9',
    -	"isindot;":                         '\U000022F5',
    -	"isins;":                           '\U000022F4',
    -	"isinsv;":                          '\U000022F3',
    -	"isinv;":                           '\U00002208',
    -	"it;":                              '\U00002062',
    -	"itilde;":                          '\U00000129',
    -	"iukcy;":                           '\U00000456',
    -	"iuml;":                            '\U000000EF',
    -	"jcirc;":                           '\U00000135',
    -	"jcy;":                             '\U00000439',
    -	"jfr;":                             '\U0001D527',
    -	"jmath;":                           '\U00000237',
    -	"jopf;":                            '\U0001D55B',
    -	"jscr;":                            '\U0001D4BF',
    -	"jsercy;":                          '\U00000458',
    -	"jukcy;":                           '\U00000454',
    -	"kappa;":                           '\U000003BA',
    -	"kappav;":                          '\U000003F0',
    -	"kcedil;":                          '\U00000137',
    -	"kcy;":                             '\U0000043A',
    -	"kfr;":                             '\U0001D528',
    -	"kgreen;":                          '\U00000138',
    -	"khcy;":                            '\U00000445',
    -	"kjcy;":                            '\U0000045C',
    -	"kopf;":                            '\U0001D55C',
    -	"kscr;":                            '\U0001D4C0',
    -	"lAarr;":                           '\U000021DA',
    -	"lArr;":                            '\U000021D0',
    -	"lAtail;":                          '\U0000291B',
    -	"lBarr;":                           '\U0000290E',
    -	"lE;":                              '\U00002266',
    -	"lEg;":                             '\U00002A8B',
    -	"lHar;":                            '\U00002962',
    -	"lacute;":                          '\U0000013A',
    -	"laemptyv;":                        '\U000029B4',
    -	"lagran;":                          '\U00002112',
    -	"lambda;":                          '\U000003BB',
    -	"lang;":                            '\U000027E8',
    -	"langd;":                           '\U00002991',
    -	"langle;":                          '\U000027E8',
    -	"lap;":                             '\U00002A85',
    -	"laquo;":                           '\U000000AB',
    -	"larr;":                            '\U00002190',
    -	"larrb;":                           '\U000021E4',
    -	"larrbfs;":                         '\U0000291F',
    -	"larrfs;":                          '\U0000291D',
    -	"larrhk;":                          '\U000021A9',
    -	"larrlp;":                          '\U000021AB',
    -	"larrpl;":                          '\U00002939',
    -	"larrsim;":                         '\U00002973',
    -	"larrtl;":                          '\U000021A2',
    -	"lat;":                             '\U00002AAB',
    -	"latail;":                          '\U00002919',
    -	"late;":                            '\U00002AAD',
    -	"lbarr;":                           '\U0000290C',
    -	"lbbrk;":                           '\U00002772',
    -	"lbrace;":                          '\U0000007B',
    -	"lbrack;":                          '\U0000005B',
    -	"lbrke;":                           '\U0000298B',
    -	"lbrksld;":                         '\U0000298F',
    -	"lbrkslu;":                         '\U0000298D',
    -	"lcaron;":                          '\U0000013E',
    -	"lcedil;":                          '\U0000013C',
    -	"lceil;":                           '\U00002308',
    -	"lcub;":                            '\U0000007B',
    -	"lcy;":                             '\U0000043B',
    -	"ldca;":                            '\U00002936',
    -	"ldquo;":                           '\U0000201C',
    -	"ldquor;":                          '\U0000201E',
    -	"ldrdhar;":                         '\U00002967',
    -	"ldrushar;":                        '\U0000294B',
    -	"ldsh;":                            '\U000021B2',
    -	"le;":                              '\U00002264',
    -	"leftarrow;":                       '\U00002190',
    -	"leftarrowtail;":                   '\U000021A2',
    -	"leftharpoondown;":                 '\U000021BD',
    -	"leftharpoonup;":                   '\U000021BC',
    -	"leftleftarrows;":                  '\U000021C7',
    -	"leftrightarrow;":                  '\U00002194',
    -	"leftrightarrows;":                 '\U000021C6',
    -	"leftrightharpoons;":               '\U000021CB',
    -	"leftrightsquigarrow;":             '\U000021AD',
    -	"leftthreetimes;":                  '\U000022CB',
    -	"leg;":                             '\U000022DA',
    -	"leq;":                             '\U00002264',
    -	"leqq;":                            '\U00002266',
    -	"leqslant;":                        '\U00002A7D',
    -	"les;":                             '\U00002A7D',
    -	"lescc;":                           '\U00002AA8',
    -	"lesdot;":                          '\U00002A7F',
    -	"lesdoto;":                         '\U00002A81',
    -	"lesdotor;":                        '\U00002A83',
    -	"lesges;":                          '\U00002A93',
    -	"lessapprox;":                      '\U00002A85',
    -	"lessdot;":                         '\U000022D6',
    -	"lesseqgtr;":                       '\U000022DA',
    -	"lesseqqgtr;":                      '\U00002A8B',
    -	"lessgtr;":                         '\U00002276',
    -	"lesssim;":                         '\U00002272',
    -	"lfisht;":                          '\U0000297C',
    -	"lfloor;":                          '\U0000230A',
    -	"lfr;":                             '\U0001D529',
    -	"lg;":                              '\U00002276',
    -	"lgE;":                             '\U00002A91',
    -	"lhard;":                           '\U000021BD',
    -	"lharu;":                           '\U000021BC',
    -	"lharul;":                          '\U0000296A',
    -	"lhblk;":                           '\U00002584',
    -	"ljcy;":                            '\U00000459',
    -	"ll;":                              '\U0000226A',
    -	"llarr;":                           '\U000021C7',
    -	"llcorner;":                        '\U0000231E',
    -	"llhard;":                          '\U0000296B',
    -	"lltri;":                           '\U000025FA',
    -	"lmidot;":                          '\U00000140',
    -	"lmoust;":                          '\U000023B0',
    -	"lmoustache;":                      '\U000023B0',
    -	"lnE;":                             '\U00002268',
    -	"lnap;":                            '\U00002A89',
    -	"lnapprox;":                        '\U00002A89',
    -	"lne;":                             '\U00002A87',
    -	"lneq;":                            '\U00002A87',
    -	"lneqq;":                           '\U00002268',
    -	"lnsim;":                           '\U000022E6',
    -	"loang;":                           '\U000027EC',
    -	"loarr;":                           '\U000021FD',
    -	"lobrk;":                           '\U000027E6',
    -	"longleftarrow;":                   '\U000027F5',
    -	"longleftrightarrow;":              '\U000027F7',
    -	"longmapsto;":                      '\U000027FC',
    -	"longrightarrow;":                  '\U000027F6',
    -	"looparrowleft;":                   '\U000021AB',
    -	"looparrowright;":                  '\U000021AC',
    -	"lopar;":                           '\U00002985',
    -	"lopf;":                            '\U0001D55D',
    -	"loplus;":                          '\U00002A2D',
    -	"lotimes;":                         '\U00002A34',
    -	"lowast;":                          '\U00002217',
    -	"lowbar;":                          '\U0000005F',
    -	"loz;":                             '\U000025CA',
    -	"lozenge;":                         '\U000025CA',
    -	"lozf;":                            '\U000029EB',
    -	"lpar;":                            '\U00000028',
    -	"lparlt;":                          '\U00002993',
    -	"lrarr;":                           '\U000021C6',
    -	"lrcorner;":                        '\U0000231F',
    -	"lrhar;":                           '\U000021CB',
    -	"lrhard;":                          '\U0000296D',
    -	"lrm;":                             '\U0000200E',
    -	"lrtri;":                           '\U000022BF',
    -	"lsaquo;":                          '\U00002039',
    -	"lscr;":                            '\U0001D4C1',
    -	"lsh;":                             '\U000021B0',
    -	"lsim;":                            '\U00002272',
    -	"lsime;":                           '\U00002A8D',
    -	"lsimg;":                           '\U00002A8F',
    -	"lsqb;":                            '\U0000005B',
    -	"lsquo;":                           '\U00002018',
    -	"lsquor;":                          '\U0000201A',
    -	"lstrok;":                          '\U00000142',
    -	"lt;":                              '\U0000003C',
    -	"ltcc;":                            '\U00002AA6',
    -	"ltcir;":                           '\U00002A79',
    -	"ltdot;":                           '\U000022D6',
    -	"lthree;":                          '\U000022CB',
    -	"ltimes;":                          '\U000022C9',
    -	"ltlarr;":                          '\U00002976',
    -	"ltquest;":                         '\U00002A7B',
    -	"ltrPar;":                          '\U00002996',
    -	"ltri;":                            '\U000025C3',
    -	"ltrie;":                           '\U000022B4',
    -	"ltrif;":                           '\U000025C2',
    -	"lurdshar;":                        '\U0000294A',
    -	"luruhar;":                         '\U00002966',
    -	"mDDot;":                           '\U0000223A',
    -	"macr;":                            '\U000000AF',
    -	"male;":                            '\U00002642',
    -	"malt;":                            '\U00002720',
    -	"maltese;":                         '\U00002720',
    -	"map;":                             '\U000021A6',
    -	"mapsto;":                          '\U000021A6',
    -	"mapstodown;":                      '\U000021A7',
    -	"mapstoleft;":                      '\U000021A4',
    -	"mapstoup;":                        '\U000021A5',
    -	"marker;":                          '\U000025AE',
    -	"mcomma;":                          '\U00002A29',
    -	"mcy;":                             '\U0000043C',
    -	"mdash;":                           '\U00002014',
    -	"measuredangle;":                   '\U00002221',
    -	"mfr;":                             '\U0001D52A',
    -	"mho;":                             '\U00002127',
    -	"micro;":                           '\U000000B5',
    -	"mid;":                             '\U00002223',
    -	"midast;":                          '\U0000002A',
    -	"midcir;":                          '\U00002AF0',
    -	"middot;":                          '\U000000B7',
    -	"minus;":                           '\U00002212',
    -	"minusb;":                          '\U0000229F',
    -	"minusd;":                          '\U00002238',
    -	"minusdu;":                         '\U00002A2A',
    -	"mlcp;":                            '\U00002ADB',
    -	"mldr;":                            '\U00002026',
    -	"mnplus;":                          '\U00002213',
    -	"models;":                          '\U000022A7',
    -	"mopf;":                            '\U0001D55E',
    -	"mp;":                              '\U00002213',
    -	"mscr;":                            '\U0001D4C2',
    -	"mstpos;":                          '\U0000223E',
    -	"mu;":                              '\U000003BC',
    -	"multimap;":                        '\U000022B8',
    -	"mumap;":                           '\U000022B8',
    -	"nLeftarrow;":                      '\U000021CD',
    -	"nLeftrightarrow;":                 '\U000021CE',
    -	"nRightarrow;":                     '\U000021CF',
    -	"nVDash;":                          '\U000022AF',
    -	"nVdash;":                          '\U000022AE',
    -	"nabla;":                           '\U00002207',
    -	"nacute;":                          '\U00000144',
    -	"nap;":                             '\U00002249',
    -	"napos;":                           '\U00000149',
    -	"napprox;":                         '\U00002249',
    -	"natur;":                           '\U0000266E',
    -	"natural;":                         '\U0000266E',
    -	"naturals;":                        '\U00002115',
    -	"nbsp;":                            '\U000000A0',
    -	"ncap;":                            '\U00002A43',
    -	"ncaron;":                          '\U00000148',
    -	"ncedil;":                          '\U00000146',
    -	"ncong;":                           '\U00002247',
    -	"ncup;":                            '\U00002A42',
    -	"ncy;":                             '\U0000043D',
    -	"ndash;":                           '\U00002013',
    -	"ne;":                              '\U00002260',
    -	"neArr;":                           '\U000021D7',
    -	"nearhk;":                          '\U00002924',
    -	"nearr;":                           '\U00002197',
    -	"nearrow;":                         '\U00002197',
    -	"nequiv;":                          '\U00002262',
    -	"nesear;":                          '\U00002928',
    -	"nexist;":                          '\U00002204',
    -	"nexists;":                         '\U00002204',
    -	"nfr;":                             '\U0001D52B',
    -	"nge;":                             '\U00002271',
    -	"ngeq;":                            '\U00002271',
    -	"ngsim;":                           '\U00002275',
    -	"ngt;":                             '\U0000226F',
    -	"ngtr;":                            '\U0000226F',
    -	"nhArr;":                           '\U000021CE',
    -	"nharr;":                           '\U000021AE',
    -	"nhpar;":                           '\U00002AF2',
    -	"ni;":                              '\U0000220B',
    -	"nis;":                             '\U000022FC',
    -	"nisd;":                            '\U000022FA',
    -	"niv;":                             '\U0000220B',
    -	"njcy;":                            '\U0000045A',
    -	"nlArr;":                           '\U000021CD',
    -	"nlarr;":                           '\U0000219A',
    -	"nldr;":                            '\U00002025',
    -	"nle;":                             '\U00002270',
    -	"nleftarrow;":                      '\U0000219A',
    -	"nleftrightarrow;":                 '\U000021AE',
    -	"nleq;":                            '\U00002270',
    -	"nless;":                           '\U0000226E',
    -	"nlsim;":                           '\U00002274',
    -	"nlt;":                             '\U0000226E',
    -	"nltri;":                           '\U000022EA',
    -	"nltrie;":                          '\U000022EC',
    -	"nmid;":                            '\U00002224',
    -	"nopf;":                            '\U0001D55F',
    -	"not;":                             '\U000000AC',
    -	"notin;":                           '\U00002209',
    -	"notinva;":                         '\U00002209',
    -	"notinvb;":                         '\U000022F7',
    -	"notinvc;":                         '\U000022F6',
    -	"notni;":                           '\U0000220C',
    -	"notniva;":                         '\U0000220C',
    -	"notnivb;":                         '\U000022FE',
    -	"notnivc;":                         '\U000022FD',
    -	"npar;":                            '\U00002226',
    -	"nparallel;":                       '\U00002226',
    -	"npolint;":                         '\U00002A14',
    -	"npr;":                             '\U00002280',
    -	"nprcue;":                          '\U000022E0',
    -	"nprec;":                           '\U00002280',
    -	"nrArr;":                           '\U000021CF',
    -	"nrarr;":                           '\U0000219B',
    -	"nrightarrow;":                     '\U0000219B',
    -	"nrtri;":                           '\U000022EB',
    -	"nrtrie;":                          '\U000022ED',
    -	"nsc;":                             '\U00002281',
    -	"nsccue;":                          '\U000022E1',
    -	"nscr;":                            '\U0001D4C3',
    -	"nshortmid;":                       '\U00002224',
    -	"nshortparallel;":                  '\U00002226',
    -	"nsim;":                            '\U00002241',
    -	"nsime;":                           '\U00002244',
    -	"nsimeq;":                          '\U00002244',
    -	"nsmid;":                           '\U00002224',
    -	"nspar;":                           '\U00002226',
    -	"nsqsube;":                         '\U000022E2',
    -	"nsqsupe;":                         '\U000022E3',
    -	"nsub;":                            '\U00002284',
    -	"nsube;":                           '\U00002288',
    -	"nsubseteq;":                       '\U00002288',
    -	"nsucc;":                           '\U00002281',
    -	"nsup;":                            '\U00002285',
    -	"nsupe;":                           '\U00002289',
    -	"nsupseteq;":                       '\U00002289',
    -	"ntgl;":                            '\U00002279',
    -	"ntilde;":                          '\U000000F1',
    -	"ntlg;":                            '\U00002278',
    -	"ntriangleleft;":                   '\U000022EA',
    -	"ntrianglelefteq;":                 '\U000022EC',
    -	"ntriangleright;":                  '\U000022EB',
    -	"ntrianglerighteq;":                '\U000022ED',
    -	"nu;":                              '\U000003BD',
    -	"num;":                             '\U00000023',
    -	"numero;":                          '\U00002116',
    -	"numsp;":                           '\U00002007',
    -	"nvDash;":                          '\U000022AD',
    -	"nvHarr;":                          '\U00002904',
    -	"nvdash;":                          '\U000022AC',
    -	"nvinfin;":                         '\U000029DE',
    -	"nvlArr;":                          '\U00002902',
    -	"nvrArr;":                          '\U00002903',
    -	"nwArr;":                           '\U000021D6',
    -	"nwarhk;":                          '\U00002923',
    -	"nwarr;":                           '\U00002196',
    -	"nwarrow;":                         '\U00002196',
    -	"nwnear;":                          '\U00002927',
    -	"oS;":                              '\U000024C8',
    -	"oacute;":                          '\U000000F3',
    -	"oast;":                            '\U0000229B',
    -	"ocir;":                            '\U0000229A',
    -	"ocirc;":                           '\U000000F4',
    -	"ocy;":                             '\U0000043E',
    -	"odash;":                           '\U0000229D',
    -	"odblac;":                          '\U00000151',
    -	"odiv;":                            '\U00002A38',
    -	"odot;":                            '\U00002299',
    -	"odsold;":                          '\U000029BC',
    -	"oelig;":                           '\U00000153',
    -	"ofcir;":                           '\U000029BF',
    -	"ofr;":                             '\U0001D52C',
    -	"ogon;":                            '\U000002DB',
    -	"ograve;":                          '\U000000F2',
    -	"ogt;":                             '\U000029C1',
    -	"ohbar;":                           '\U000029B5',
    -	"ohm;":                             '\U000003A9',
    -	"oint;":                            '\U0000222E',
    -	"olarr;":                           '\U000021BA',
    -	"olcir;":                           '\U000029BE',
    -	"olcross;":                         '\U000029BB',
    -	"oline;":                           '\U0000203E',
    -	"olt;":                             '\U000029C0',
    -	"omacr;":                           '\U0000014D',
    -	"omega;":                           '\U000003C9',
    -	"omicron;":                         '\U000003BF',
    -	"omid;":                            '\U000029B6',
    -	"ominus;":                          '\U00002296',
    -	"oopf;":                            '\U0001D560',
    -	"opar;":                            '\U000029B7',
    -	"operp;":                           '\U000029B9',
    -	"oplus;":                           '\U00002295',
    -	"or;":                              '\U00002228',
    -	"orarr;":                           '\U000021BB',
    -	"ord;":                             '\U00002A5D',
    -	"order;":                           '\U00002134',
    -	"orderof;":                         '\U00002134',
    -	"ordf;":                            '\U000000AA',
    -	"ordm;":                            '\U000000BA',
    -	"origof;":                          '\U000022B6',
    -	"oror;":                            '\U00002A56',
    -	"orslope;":                         '\U00002A57',
    -	"orv;":                             '\U00002A5B',
    -	"oscr;":                            '\U00002134',
    -	"oslash;":                          '\U000000F8',
    -	"osol;":                            '\U00002298',
    -	"otilde;":                          '\U000000F5',
    -	"otimes;":                          '\U00002297',
    -	"otimesas;":                        '\U00002A36',
    -	"ouml;":                            '\U000000F6',
    -	"ovbar;":                           '\U0000233D',
    -	"par;":                             '\U00002225',
    -	"para;":                            '\U000000B6',
    -	"parallel;":                        '\U00002225',
    -	"parsim;":                          '\U00002AF3',
    -	"parsl;":                           '\U00002AFD',
    -	"part;":                            '\U00002202',
    -	"pcy;":                             '\U0000043F',
    -	"percnt;":                          '\U00000025',
    -	"period;":                          '\U0000002E',
    -	"permil;":                          '\U00002030',
    -	"perp;":                            '\U000022A5',
    -	"pertenk;":                         '\U00002031',
    -	"pfr;":                             '\U0001D52D',
    -	"phi;":                             '\U000003C6',
    -	"phiv;":                            '\U000003D5',
    -	"phmmat;":                          '\U00002133',
    -	"phone;":                           '\U0000260E',
    -	"pi;":                              '\U000003C0',
    -	"pitchfork;":                       '\U000022D4',
    -	"piv;":                             '\U000003D6',
    -	"planck;":                          '\U0000210F',
    -	"planckh;":                         '\U0000210E',
    -	"plankv;":                          '\U0000210F',
    -	"plus;":                            '\U0000002B',
    -	"plusacir;":                        '\U00002A23',
    -	"plusb;":                           '\U0000229E',
    -	"pluscir;":                         '\U00002A22',
    -	"plusdo;":                          '\U00002214',
    -	"plusdu;":                          '\U00002A25',
    -	"pluse;":                           '\U00002A72',
    -	"plusmn;":                          '\U000000B1',
    -	"plussim;":                         '\U00002A26',
    -	"plustwo;":                         '\U00002A27',
    -	"pm;":                              '\U000000B1',
    -	"pointint;":                        '\U00002A15',
    -	"popf;":                            '\U0001D561',
    -	"pound;":                           '\U000000A3',
    -	"pr;":                              '\U0000227A',
    -	"prE;":                             '\U00002AB3',
    -	"prap;":                            '\U00002AB7',
    -	"prcue;":                           '\U0000227C',
    -	"pre;":                             '\U00002AAF',
    -	"prec;":                            '\U0000227A',
    -	"precapprox;":                      '\U00002AB7',
    -	"preccurlyeq;":                     '\U0000227C',
    -	"preceq;":                          '\U00002AAF',
    -	"precnapprox;":                     '\U00002AB9',
    -	"precneqq;":                        '\U00002AB5',
    -	"precnsim;":                        '\U000022E8',
    -	"precsim;":                         '\U0000227E',
    -	"prime;":                           '\U00002032',
    -	"primes;":                          '\U00002119',
    -	"prnE;":                            '\U00002AB5',
    -	"prnap;":                           '\U00002AB9',
    -	"prnsim;":                          '\U000022E8',
    -	"prod;":                            '\U0000220F',
    -	"profalar;":                        '\U0000232E',
    -	"profline;":                        '\U00002312',
    -	"profsurf;":                        '\U00002313',
    -	"prop;":                            '\U0000221D',
    -	"propto;":                          '\U0000221D',
    -	"prsim;":                           '\U0000227E',
    -	"prurel;":                          '\U000022B0',
    -	"pscr;":                            '\U0001D4C5',
    -	"psi;":                             '\U000003C8',
    -	"puncsp;":                          '\U00002008',
    -	"qfr;":                             '\U0001D52E',
    -	"qint;":                            '\U00002A0C',
    -	"qopf;":                            '\U0001D562',
    -	"qprime;":                          '\U00002057',
    -	"qscr;":                            '\U0001D4C6',
    -	"quaternions;":                     '\U0000210D',
    -	"quatint;":                         '\U00002A16',
    -	"quest;":                           '\U0000003F',
    -	"questeq;":                         '\U0000225F',
    -	"quot;":                            '\U00000022',
    -	"rAarr;":                           '\U000021DB',
    -	"rArr;":                            '\U000021D2',
    -	"rAtail;":                          '\U0000291C',
    -	"rBarr;":                           '\U0000290F',
    -	"rHar;":                            '\U00002964',
    -	"racute;":                          '\U00000155',
    -	"radic;":                           '\U0000221A',
    -	"raemptyv;":                        '\U000029B3',
    -	"rang;":                            '\U000027E9',
    -	"rangd;":                           '\U00002992',
    -	"range;":                           '\U000029A5',
    -	"rangle;":                          '\U000027E9',
    -	"raquo;":                           '\U000000BB',
    -	"rarr;":                            '\U00002192',
    -	"rarrap;":                          '\U00002975',
    -	"rarrb;":                           '\U000021E5',
    -	"rarrbfs;":                         '\U00002920',
    -	"rarrc;":                           '\U00002933',
    -	"rarrfs;":                          '\U0000291E',
    -	"rarrhk;":                          '\U000021AA',
    -	"rarrlp;":                          '\U000021AC',
    -	"rarrpl;":                          '\U00002945',
    -	"rarrsim;":                         '\U00002974',
    -	"rarrtl;":                          '\U000021A3',
    -	"rarrw;":                           '\U0000219D',
    -	"ratail;":                          '\U0000291A',
    -	"ratio;":                           '\U00002236',
    -	"rationals;":                       '\U0000211A',
    -	"rbarr;":                           '\U0000290D',
    -	"rbbrk;":                           '\U00002773',
    -	"rbrace;":                          '\U0000007D',
    -	"rbrack;":                          '\U0000005D',
    -	"rbrke;":                           '\U0000298C',
    -	"rbrksld;":                         '\U0000298E',
    -	"rbrkslu;":                         '\U00002990',
    -	"rcaron;":                          '\U00000159',
    -	"rcedil;":                          '\U00000157',
    -	"rceil;":                           '\U00002309',
    -	"rcub;":                            '\U0000007D',
    -	"rcy;":                             '\U00000440',
    -	"rdca;":                            '\U00002937',
    -	"rdldhar;":                         '\U00002969',
    -	"rdquo;":                           '\U0000201D',
    -	"rdquor;":                          '\U0000201D',
    -	"rdsh;":                            '\U000021B3',
    -	"real;":                            '\U0000211C',
    -	"realine;":                         '\U0000211B',
    -	"realpart;":                        '\U0000211C',
    -	"reals;":                           '\U0000211D',
    -	"rect;":                            '\U000025AD',
    -	"reg;":                             '\U000000AE',
    -	"rfisht;":                          '\U0000297D',
    -	"rfloor;":                          '\U0000230B',
    -	"rfr;":                             '\U0001D52F',
    -	"rhard;":                           '\U000021C1',
    -	"rharu;":                           '\U000021C0',
    -	"rharul;":                          '\U0000296C',
    -	"rho;":                             '\U000003C1',
    -	"rhov;":                            '\U000003F1',
    -	"rightarrow;":                      '\U00002192',
    -	"rightarrowtail;":                  '\U000021A3',
    -	"rightharpoondown;":                '\U000021C1',
    -	"rightharpoonup;":                  '\U000021C0',
    -	"rightleftarrows;":                 '\U000021C4',
    -	"rightleftharpoons;":               '\U000021CC',
    -	"rightrightarrows;":                '\U000021C9',
    -	"rightsquigarrow;":                 '\U0000219D',
    -	"rightthreetimes;":                 '\U000022CC',
    -	"ring;":                            '\U000002DA',
    -	"risingdotseq;":                    '\U00002253',
    -	"rlarr;":                           '\U000021C4',
    -	"rlhar;":                           '\U000021CC',
    -	"rlm;":                             '\U0000200F',
    -	"rmoust;":                          '\U000023B1',
    -	"rmoustache;":                      '\U000023B1',
    -	"rnmid;":                           '\U00002AEE',
    -	"roang;":                           '\U000027ED',
    -	"roarr;":                           '\U000021FE',
    -	"robrk;":                           '\U000027E7',
    -	"ropar;":                           '\U00002986',
    -	"ropf;":                            '\U0001D563',
    -	"roplus;":                          '\U00002A2E',
    -	"rotimes;":                         '\U00002A35',
    -	"rpar;":                            '\U00000029',
    -	"rpargt;":                          '\U00002994',
    -	"rppolint;":                        '\U00002A12',
    -	"rrarr;":                           '\U000021C9',
    -	"rsaquo;":                          '\U0000203A',
    -	"rscr;":                            '\U0001D4C7',
    -	"rsh;":                             '\U000021B1',
    -	"rsqb;":                            '\U0000005D',
    -	"rsquo;":                           '\U00002019',
    -	"rsquor;":                          '\U00002019',
    -	"rthree;":                          '\U000022CC',
    -	"rtimes;":                          '\U000022CA',
    -	"rtri;":                            '\U000025B9',
    -	"rtrie;":                           '\U000022B5',
    -	"rtrif;":                           '\U000025B8',
    -	"rtriltri;":                        '\U000029CE',
    -	"ruluhar;":                         '\U00002968',
    -	"rx;":                              '\U0000211E',
    -	"sacute;":                          '\U0000015B',
    -	"sbquo;":                           '\U0000201A',
    -	"sc;":                              '\U0000227B',
    -	"scE;":                             '\U00002AB4',
    -	"scap;":                            '\U00002AB8',
    -	"scaron;":                          '\U00000161',
    -	"sccue;":                           '\U0000227D',
    -	"sce;":                             '\U00002AB0',
    -	"scedil;":                          '\U0000015F',
    -	"scirc;":                           '\U0000015D',
    -	"scnE;":                            '\U00002AB6',
    -	"scnap;":                           '\U00002ABA',
    -	"scnsim;":                          '\U000022E9',
    -	"scpolint;":                        '\U00002A13',
    -	"scsim;":                           '\U0000227F',
    -	"scy;":                             '\U00000441',
    -	"sdot;":                            '\U000022C5',
    -	"sdotb;":                           '\U000022A1',
    -	"sdote;":                           '\U00002A66',
    -	"seArr;":                           '\U000021D8',
    -	"searhk;":                          '\U00002925',
    -	"searr;":                           '\U00002198',
    -	"searrow;":                         '\U00002198',
    -	"sect;":                            '\U000000A7',
    -	"semi;":                            '\U0000003B',
    -	"seswar;":                          '\U00002929',
    -	"setminus;":                        '\U00002216',
    -	"setmn;":                           '\U00002216',
    -	"sext;":                            '\U00002736',
    -	"sfr;":                             '\U0001D530',
    -	"sfrown;":                          '\U00002322',
    -	"sharp;":                           '\U0000266F',
    -	"shchcy;":                          '\U00000449',
    -	"shcy;":                            '\U00000448',
    -	"shortmid;":                        '\U00002223',
    -	"shortparallel;":                   '\U00002225',
    -	"shy;":                             '\U000000AD',
    -	"sigma;":                           '\U000003C3',
    -	"sigmaf;":                          '\U000003C2',
    -	"sigmav;":                          '\U000003C2',
    -	"sim;":                             '\U0000223C',
    -	"simdot;":                          '\U00002A6A',
    -	"sime;":                            '\U00002243',
    -	"simeq;":                           '\U00002243',
    -	"simg;":                            '\U00002A9E',
    -	"simgE;":                           '\U00002AA0',
    -	"siml;":                            '\U00002A9D',
    -	"simlE;":                           '\U00002A9F',
    -	"simne;":                           '\U00002246',
    -	"simplus;":                         '\U00002A24',
    -	"simrarr;":                         '\U00002972',
    -	"slarr;":                           '\U00002190',
    -	"smallsetminus;":                   '\U00002216',
    -	"smashp;":                          '\U00002A33',
    -	"smeparsl;":                        '\U000029E4',
    -	"smid;":                            '\U00002223',
    -	"smile;":                           '\U00002323',
    -	"smt;":                             '\U00002AAA',
    -	"smte;":                            '\U00002AAC',
    -	"softcy;":                          '\U0000044C',
    -	"sol;":                             '\U0000002F',
    -	"solb;":                            '\U000029C4',
    -	"solbar;":                          '\U0000233F',
    -	"sopf;":                            '\U0001D564',
    -	"spades;":                          '\U00002660',
    -	"spadesuit;":                       '\U00002660',
    -	"spar;":                            '\U00002225',
    -	"sqcap;":                           '\U00002293',
    -	"sqcup;":                           '\U00002294',
    -	"sqsub;":                           '\U0000228F',
    -	"sqsube;":                          '\U00002291',
    -	"sqsubset;":                        '\U0000228F',
    -	"sqsubseteq;":                      '\U00002291',
    -	"sqsup;":                           '\U00002290',
    -	"sqsupe;":                          '\U00002292',
    -	"sqsupset;":                        '\U00002290',
    -	"sqsupseteq;":                      '\U00002292',
    -	"squ;":                             '\U000025A1',
    -	"square;":                          '\U000025A1',
    -	"squarf;":                          '\U000025AA',
    -	"squf;":                            '\U000025AA',
    -	"srarr;":                           '\U00002192',
    -	"sscr;":                            '\U0001D4C8',
    -	"ssetmn;":                          '\U00002216',
    -	"ssmile;":                          '\U00002323',
    -	"sstarf;":                          '\U000022C6',
    -	"star;":                            '\U00002606',
    -	"starf;":                           '\U00002605',
    -	"straightepsilon;":                 '\U000003F5',
    -	"straightphi;":                     '\U000003D5',
    -	"strns;":                           '\U000000AF',
    -	"sub;":                             '\U00002282',
    -	"subE;":                            '\U00002AC5',
    -	"subdot;":                          '\U00002ABD',
    -	"sube;":                            '\U00002286',
    -	"subedot;":                         '\U00002AC3',
    -	"submult;":                         '\U00002AC1',
    -	"subnE;":                           '\U00002ACB',
    -	"subne;":                           '\U0000228A',
    -	"subplus;":                         '\U00002ABF',
    -	"subrarr;":                         '\U00002979',
    -	"subset;":                          '\U00002282',
    -	"subseteq;":                        '\U00002286',
    -	"subseteqq;":                       '\U00002AC5',
    -	"subsetneq;":                       '\U0000228A',
    -	"subsetneqq;":                      '\U00002ACB',
    -	"subsim;":                          '\U00002AC7',
    -	"subsub;":                          '\U00002AD5',
    -	"subsup;":                          '\U00002AD3',
    -	"succ;":                            '\U0000227B',
    -	"succapprox;":                      '\U00002AB8',
    -	"succcurlyeq;":                     '\U0000227D',
    -	"succeq;":                          '\U00002AB0',
    -	"succnapprox;":                     '\U00002ABA',
    -	"succneqq;":                        '\U00002AB6',
    -	"succnsim;":                        '\U000022E9',
    -	"succsim;":                         '\U0000227F',
    -	"sum;":                             '\U00002211',
    -	"sung;":                            '\U0000266A',
    -	"sup;":                             '\U00002283',
    -	"sup1;":                            '\U000000B9',
    -	"sup2;":                            '\U000000B2',
    -	"sup3;":                            '\U000000B3',
    -	"supE;":                            '\U00002AC6',
    -	"supdot;":                          '\U00002ABE',
    -	"supdsub;":                         '\U00002AD8',
    -	"supe;":                            '\U00002287',
    -	"supedot;":                         '\U00002AC4',
    -	"suphsol;":                         '\U000027C9',
    -	"suphsub;":                         '\U00002AD7',
    -	"suplarr;":                         '\U0000297B',
    -	"supmult;":                         '\U00002AC2',
    -	"supnE;":                           '\U00002ACC',
    -	"supne;":                           '\U0000228B',
    -	"supplus;":                         '\U00002AC0',
    -	"supset;":                          '\U00002283',
    -	"supseteq;":                        '\U00002287',
    -	"supseteqq;":                       '\U00002AC6',
    -	"supsetneq;":                       '\U0000228B',
    -	"supsetneqq;":                      '\U00002ACC',
    -	"supsim;":                          '\U00002AC8',
    -	"supsub;":                          '\U00002AD4',
    -	"supsup;":                          '\U00002AD6',
    -	"swArr;":                           '\U000021D9',
    -	"swarhk;":                          '\U00002926',
    -	"swarr;":                           '\U00002199',
    -	"swarrow;":                         '\U00002199',
    -	"swnwar;":                          '\U0000292A',
    -	"szlig;":                           '\U000000DF',
    -	"target;":                          '\U00002316',
    -	"tau;":                             '\U000003C4',
    -	"tbrk;":                            '\U000023B4',
    -	"tcaron;":                          '\U00000165',
    -	"tcedil;":                          '\U00000163',
    -	"tcy;":                             '\U00000442',
    -	"tdot;":                            '\U000020DB',
    -	"telrec;":                          '\U00002315',
    -	"tfr;":                             '\U0001D531',
    -	"there4;":                          '\U00002234',
    -	"therefore;":                       '\U00002234',
    -	"theta;":                           '\U000003B8',
    -	"thetasym;":                        '\U000003D1',
    -	"thetav;":                          '\U000003D1',
    -	"thickapprox;":                     '\U00002248',
    -	"thicksim;":                        '\U0000223C',
    -	"thinsp;":                          '\U00002009',
    -	"thkap;":                           '\U00002248',
    -	"thksim;":                          '\U0000223C',
    -	"thorn;":                           '\U000000FE',
    -	"tilde;":                           '\U000002DC',
    -	"times;":                           '\U000000D7',
    -	"timesb;":                          '\U000022A0',
    -	"timesbar;":                        '\U00002A31',
    -	"timesd;":                          '\U00002A30',
    -	"tint;":                            '\U0000222D',
    -	"toea;":                            '\U00002928',
    -	"top;":                             '\U000022A4',
    -	"topbot;":                          '\U00002336',
    -	"topcir;":                          '\U00002AF1',
    -	"topf;":                            '\U0001D565',
    -	"topfork;":                         '\U00002ADA',
    -	"tosa;":                            '\U00002929',
    -	"tprime;":                          '\U00002034',
    -	"trade;":                           '\U00002122',
    -	"triangle;":                        '\U000025B5',
    -	"triangledown;":                    '\U000025BF',
    -	"triangleleft;":                    '\U000025C3',
    -	"trianglelefteq;":                  '\U000022B4',
    -	"triangleq;":                       '\U0000225C',
    -	"triangleright;":                   '\U000025B9',
    -	"trianglerighteq;":                 '\U000022B5',
    -	"tridot;":                          '\U000025EC',
    -	"trie;":                            '\U0000225C',
    -	"triminus;":                        '\U00002A3A',
    -	"triplus;":                         '\U00002A39',
    -	"trisb;":                           '\U000029CD',
    -	"tritime;":                         '\U00002A3B',
    -	"trpezium;":                        '\U000023E2',
    -	"tscr;":                            '\U0001D4C9',
    -	"tscy;":                            '\U00000446',
    -	"tshcy;":                           '\U0000045B',
    -	"tstrok;":                          '\U00000167',
    -	"twixt;":                           '\U0000226C',
    -	"twoheadleftarrow;":                '\U0000219E',
    -	"twoheadrightarrow;":               '\U000021A0',
    -	"uArr;":                            '\U000021D1',
    -	"uHar;":                            '\U00002963',
    -	"uacute;":                          '\U000000FA',
    -	"uarr;":                            '\U00002191',
    -	"ubrcy;":                           '\U0000045E',
    -	"ubreve;":                          '\U0000016D',
    -	"ucirc;":                           '\U000000FB',
    -	"ucy;":                             '\U00000443',
    -	"udarr;":                           '\U000021C5',
    -	"udblac;":                          '\U00000171',
    -	"udhar;":                           '\U0000296E',
    -	"ufisht;":                          '\U0000297E',
    -	"ufr;":                             '\U0001D532',
    -	"ugrave;":                          '\U000000F9',
    -	"uharl;":                           '\U000021BF',
    -	"uharr;":                           '\U000021BE',
    -	"uhblk;":                           '\U00002580',
    -	"ulcorn;":                          '\U0000231C',
    -	"ulcorner;":                        '\U0000231C',
    -	"ulcrop;":                          '\U0000230F',
    -	"ultri;":                           '\U000025F8',
    -	"umacr;":                           '\U0000016B',
    -	"uml;":                             '\U000000A8',
    -	"uogon;":                           '\U00000173',
    -	"uopf;":                            '\U0001D566',
    -	"uparrow;":                         '\U00002191',
    -	"updownarrow;":                     '\U00002195',
    -	"upharpoonleft;":                   '\U000021BF',
    -	"upharpoonright;":                  '\U000021BE',
    -	"uplus;":                           '\U0000228E',
    -	"upsi;":                            '\U000003C5',
    -	"upsih;":                           '\U000003D2',
    -	"upsilon;":                         '\U000003C5',
    -	"upuparrows;":                      '\U000021C8',
    -	"urcorn;":                          '\U0000231D',
    -	"urcorner;":                        '\U0000231D',
    -	"urcrop;":                          '\U0000230E',
    -	"uring;":                           '\U0000016F',
    -	"urtri;":                           '\U000025F9',
    -	"uscr;":                            '\U0001D4CA',
    -	"utdot;":                           '\U000022F0',
    -	"utilde;":                          '\U00000169',
    -	"utri;":                            '\U000025B5',
    -	"utrif;":                           '\U000025B4',
    -	"uuarr;":                           '\U000021C8',
    -	"uuml;":                            '\U000000FC',
    -	"uwangle;":                         '\U000029A7',
    -	"vArr;":                            '\U000021D5',
    -	"vBar;":                            '\U00002AE8',
    -	"vBarv;":                           '\U00002AE9',
    -	"vDash;":                           '\U000022A8',
    -	"vangrt;":                          '\U0000299C',
    -	"varepsilon;":                      '\U000003F5',
    -	"varkappa;":                        '\U000003F0',
    -	"varnothing;":                      '\U00002205',
    -	"varphi;":                          '\U000003D5',
    -	"varpi;":                           '\U000003D6',
    -	"varpropto;":                       '\U0000221D',
    -	"varr;":                            '\U00002195',
    -	"varrho;":                          '\U000003F1',
    -	"varsigma;":                        '\U000003C2',
    -	"vartheta;":                        '\U000003D1',
    -	"vartriangleleft;":                 '\U000022B2',
    -	"vartriangleright;":                '\U000022B3',
    -	"vcy;":                             '\U00000432',
    -	"vdash;":                           '\U000022A2',
    -	"vee;":                             '\U00002228',
    -	"veebar;":                          '\U000022BB',
    -	"veeeq;":                           '\U0000225A',
    -	"vellip;":                          '\U000022EE',
    -	"verbar;":                          '\U0000007C',
    -	"vert;":                            '\U0000007C',
    -	"vfr;":                             '\U0001D533',
    -	"vltri;":                           '\U000022B2',
    -	"vopf;":                            '\U0001D567',
    -	"vprop;":                           '\U0000221D',
    -	"vrtri;":                           '\U000022B3',
    -	"vscr;":                            '\U0001D4CB',
    -	"vzigzag;":                         '\U0000299A',
    -	"wcirc;":                           '\U00000175',
    -	"wedbar;":                          '\U00002A5F',
    -	"wedge;":                           '\U00002227',
    -	"wedgeq;":                          '\U00002259',
    -	"weierp;":                          '\U00002118',
    -	"wfr;":                             '\U0001D534',
    -	"wopf;":                            '\U0001D568',
    -	"wp;":                              '\U00002118',
    -	"wr;":                              '\U00002240',
    -	"wreath;":                          '\U00002240',
    -	"wscr;":                            '\U0001D4CC',
    -	"xcap;":                            '\U000022C2',
    -	"xcirc;":                           '\U000025EF',
    -	"xcup;":                            '\U000022C3',
    -	"xdtri;":                           '\U000025BD',
    -	"xfr;":                             '\U0001D535',
    -	"xhArr;":                           '\U000027FA',
    -	"xharr;":                           '\U000027F7',
    -	"xi;":                              '\U000003BE',
    -	"xlArr;":                           '\U000027F8',
    -	"xlarr;":                           '\U000027F5',
    -	"xmap;":                            '\U000027FC',
    -	"xnis;":                            '\U000022FB',
    -	"xodot;":                           '\U00002A00',
    -	"xopf;":                            '\U0001D569',
    -	"xoplus;":                          '\U00002A01',
    -	"xotime;":                          '\U00002A02',
    -	"xrArr;":                           '\U000027F9',
    -	"xrarr;":                           '\U000027F6',
    -	"xscr;":                            '\U0001D4CD',
    -	"xsqcup;":                          '\U00002A06',
    -	"xuplus;":                          '\U00002A04',
    -	"xutri;":                           '\U000025B3',
    -	"xvee;":                            '\U000022C1',
    -	"xwedge;":                          '\U000022C0',
    -	"yacute;":                          '\U000000FD',
    -	"yacy;":                            '\U0000044F',
    -	"ycirc;":                           '\U00000177',
    -	"ycy;":                             '\U0000044B',
    -	"yen;":                             '\U000000A5',
    -	"yfr;":                             '\U0001D536',
    -	"yicy;":                            '\U00000457',
    -	"yopf;":                            '\U0001D56A',
    -	"yscr;":                            '\U0001D4CE',
    -	"yucy;":                            '\U0000044E',
    -	"yuml;":                            '\U000000FF',
    -	"zacute;":                          '\U0000017A',
    -	"zcaron;":                          '\U0000017E',
    -	"zcy;":                             '\U00000437',
    -	"zdot;":                            '\U0000017C',
    -	"zeetrf;":                          '\U00002128',
    -	"zeta;":                            '\U000003B6',
    -	"zfr;":                             '\U0001D537',
    -	"zhcy;":                            '\U00000436',
    -	"zigrarr;":                         '\U000021DD',
    -	"zopf;":                            '\U0001D56B',
    -	"zscr;":                            '\U0001D4CF',
    -	"zwj;":                             '\U0000200D',
    -	"zwnj;":                            '\U0000200C',
    -	"AElig":                            '\U000000C6',
    -	"AMP":                              '\U00000026',
    -	"Aacute":                           '\U000000C1',
    -	"Acirc":                            '\U000000C2',
    -	"Agrave":                           '\U000000C0',
    -	"Aring":                            '\U000000C5',
    -	"Atilde":                           '\U000000C3',
    -	"Auml":                             '\U000000C4',
    -	"COPY":                             '\U000000A9',
    -	"Ccedil":                           '\U000000C7',
    -	"ETH":                              '\U000000D0',
    -	"Eacute":                           '\U000000C9',
    -	"Ecirc":                            '\U000000CA',
    -	"Egrave":                           '\U000000C8',
    -	"Euml":                             '\U000000CB',
    -	"GT":                               '\U0000003E',
    -	"Iacute":                           '\U000000CD',
    -	"Icirc":                            '\U000000CE',
    -	"Igrave":                           '\U000000CC',
    -	"Iuml":                             '\U000000CF',
    -	"LT":                               '\U0000003C',
    -	"Ntilde":                           '\U000000D1',
    -	"Oacute":                           '\U000000D3',
    -	"Ocirc":                            '\U000000D4',
    -	"Ograve":                           '\U000000D2',
    -	"Oslash":                           '\U000000D8',
    -	"Otilde":                           '\U000000D5',
    -	"Ouml":                             '\U000000D6',
    -	"QUOT":                             '\U00000022',
    -	"REG":                              '\U000000AE',
    -	"THORN":                            '\U000000DE',
    -	"Uacute":                           '\U000000DA',
    -	"Ucirc":                            '\U000000DB',
    -	"Ugrave":                           '\U000000D9',
    -	"Uuml":                             '\U000000DC',
    -	"Yacute":                           '\U000000DD',
    -	"aacute":                           '\U000000E1',
    -	"acirc":                            '\U000000E2',
    -	"acute":                            '\U000000B4',
    -	"aelig":                            '\U000000E6',
    -	"agrave":                           '\U000000E0',
    -	"amp":                              '\U00000026',
    -	"aring":                            '\U000000E5',
    -	"atilde":                           '\U000000E3',
    -	"auml":                             '\U000000E4',
    -	"brvbar":                           '\U000000A6',
    -	"ccedil":                           '\U000000E7',
    -	"cedil":                            '\U000000B8',
    -	"cent":                             '\U000000A2',
    -	"copy":                             '\U000000A9',
    -	"curren":                           '\U000000A4',
    -	"deg":                              '\U000000B0',
    -	"divide":                           '\U000000F7',
    -	"eacute":                           '\U000000E9',
    -	"ecirc":                            '\U000000EA',
    -	"egrave":                           '\U000000E8',
    -	"eth":                              '\U000000F0',
    -	"euml":                             '\U000000EB',
    -	"frac12":                           '\U000000BD',
    -	"frac14":                           '\U000000BC',
    -	"frac34":                           '\U000000BE',
    -	"gt":                               '\U0000003E',
    -	"iacute":                           '\U000000ED',
    -	"icirc":                            '\U000000EE',
    -	"iexcl":                            '\U000000A1',
    -	"igrave":                           '\U000000EC',
    -	"iquest":                           '\U000000BF',
    -	"iuml":                             '\U000000EF',
    -	"laquo":                            '\U000000AB',
    -	"lt":                               '\U0000003C',
    -	"macr":                             '\U000000AF',
    -	"micro":                            '\U000000B5',
    -	"middot":                           '\U000000B7',
    -	"nbsp":                             '\U000000A0',
    -	"not":                              '\U000000AC',
    -	"ntilde":                           '\U000000F1',
    -	"oacute":                           '\U000000F3',
    -	"ocirc":                            '\U000000F4',
    -	"ograve":                           '\U000000F2',
    -	"ordf":                             '\U000000AA',
    -	"ordm":                             '\U000000BA',
    -	"oslash":                           '\U000000F8',
    -	"otilde":                           '\U000000F5',
    -	"ouml":                             '\U000000F6',
    -	"para":                             '\U000000B6',
    -	"plusmn":                           '\U000000B1',
    -	"pound":                            '\U000000A3',
    -	"quot":                             '\U00000022',
    -	"raquo":                            '\U000000BB',
    -	"reg":                              '\U000000AE',
    -	"sect":                             '\U000000A7',
    -	"shy":                              '\U000000AD',
    -	"sup1":                             '\U000000B9',
    -	"sup2":                             '\U000000B2',
    -	"sup3":                             '\U000000B3',
    -	"szlig":                            '\U000000DF',
    -	"thorn":                            '\U000000FE',
    -	"times":                            '\U000000D7',
    -	"uacute":                           '\U000000FA',
    -	"ucirc":                            '\U000000FB',
    -	"ugrave":                           '\U000000F9',
    -	"uml":                              '\U000000A8',
    -	"uuml":                             '\U000000FC',
    -	"yacute":                           '\U000000FD',
    -	"yen":                              '\U000000A5',
    -	"yuml":                             '\U000000FF',
    -}
    +var entity map[string]rune
     
     // HTML entities that are two unicode codepoints.
    -var entity2 = map[string][2]rune{
    -	// TODO(nigeltao): Handle replacements that are wider than their names.
    -	// "nLt;":                     {'\u226A', '\u20D2'},
    -	// "nGt;":                     {'\u226B', '\u20D2'},
    -	"NotEqualTilde;":           {'\u2242', '\u0338'},
    -	"NotGreaterFullEqual;":     {'\u2267', '\u0338'},
    -	"NotGreaterGreater;":       {'\u226B', '\u0338'},
    -	"NotGreaterSlantEqual;":    {'\u2A7E', '\u0338'},
    -	"NotHumpDownHump;":         {'\u224E', '\u0338'},
    -	"NotHumpEqual;":            {'\u224F', '\u0338'},
    -	"NotLeftTriangleBar;":      {'\u29CF', '\u0338'},
    -	"NotLessLess;":             {'\u226A', '\u0338'},
    -	"NotLessSlantEqual;":       {'\u2A7D', '\u0338'},
    -	"NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
    -	"NotNestedLessLess;":       {'\u2AA1', '\u0338'},
    -	"NotPrecedesEqual;":        {'\u2AAF', '\u0338'},
    -	"NotRightTriangleBar;":     {'\u29D0', '\u0338'},
    -	"NotSquareSubset;":         {'\u228F', '\u0338'},
    -	"NotSquareSuperset;":       {'\u2290', '\u0338'},
    -	"NotSubset;":               {'\u2282', '\u20D2'},
    -	"NotSucceedsEqual;":        {'\u2AB0', '\u0338'},
    -	"NotSucceedsTilde;":        {'\u227F', '\u0338'},
    -	"NotSuperset;":             {'\u2283', '\u20D2'},
    -	"ThickSpace;":              {'\u205F', '\u200A'},
    -	"acE;":                     {'\u223E', '\u0333'},
    -	"bne;":                     {'\u003D', '\u20E5'},
    -	"bnequiv;":                 {'\u2261', '\u20E5'},
    -	"caps;":                    {'\u2229', '\uFE00'},
    -	"cups;":                    {'\u222A', '\uFE00'},
    -	"fjlig;":                   {'\u0066', '\u006A'},
    -	"gesl;":                    {'\u22DB', '\uFE00'},
    -	"gvertneqq;":               {'\u2269', '\uFE00'},
    -	"gvnE;":                    {'\u2269', '\uFE00'},
    -	"lates;":                   {'\u2AAD', '\uFE00'},
    -	"lesg;":                    {'\u22DA', '\uFE00'},
    -	"lvertneqq;":               {'\u2268', '\uFE00'},
    -	"lvnE;":                    {'\u2268', '\uFE00'},
    -	"nGg;":                     {'\u22D9', '\u0338'},
    -	"nGtv;":                    {'\u226B', '\u0338'},
    -	"nLl;":                     {'\u22D8', '\u0338'},
    -	"nLtv;":                    {'\u226A', '\u0338'},
    -	"nang;":                    {'\u2220', '\u20D2'},
    -	"napE;":                    {'\u2A70', '\u0338'},
    -	"napid;":                   {'\u224B', '\u0338'},
    -	"nbump;":                   {'\u224E', '\u0338'},
    -	"nbumpe;":                  {'\u224F', '\u0338'},
    -	"ncongdot;":                {'\u2A6D', '\u0338'},
    -	"nedot;":                   {'\u2250', '\u0338'},
    -	"nesim;":                   {'\u2242', '\u0338'},
    -	"ngE;":                     {'\u2267', '\u0338'},
    -	"ngeqq;":                   {'\u2267', '\u0338'},
    -	"ngeqslant;":               {'\u2A7E', '\u0338'},
    -	"nges;":                    {'\u2A7E', '\u0338'},
    -	"nlE;":                     {'\u2266', '\u0338'},
    -	"nleqq;":                   {'\u2266', '\u0338'},
    -	"nleqslant;":               {'\u2A7D', '\u0338'},
    -	"nles;":                    {'\u2A7D', '\u0338'},
    -	"notinE;":                  {'\u22F9', '\u0338'},
    -	"notindot;":                {'\u22F5', '\u0338'},
    -	"nparsl;":                  {'\u2AFD', '\u20E5'},
    -	"npart;":                   {'\u2202', '\u0338'},
    -	"npre;":                    {'\u2AAF', '\u0338'},
    -	"npreceq;":                 {'\u2AAF', '\u0338'},
    -	"nrarrc;":                  {'\u2933', '\u0338'},
    -	"nrarrw;":                  {'\u219D', '\u0338'},
    -	"nsce;":                    {'\u2AB0', '\u0338'},
    -	"nsubE;":                   {'\u2AC5', '\u0338'},
    -	"nsubset;":                 {'\u2282', '\u20D2'},
    -	"nsubseteqq;":              {'\u2AC5', '\u0338'},
    -	"nsucceq;":                 {'\u2AB0', '\u0338'},
    -	"nsupE;":                   {'\u2AC6', '\u0338'},
    -	"nsupset;":                 {'\u2283', '\u20D2'},
    -	"nsupseteqq;":              {'\u2AC6', '\u0338'},
    -	"nvap;":                    {'\u224D', '\u20D2'},
    -	"nvge;":                    {'\u2265', '\u20D2'},
    -	"nvgt;":                    {'\u003E', '\u20D2'},
    -	"nvle;":                    {'\u2264', '\u20D2'},
    -	"nvlt;":                    {'\u003C', '\u20D2'},
    -	"nvltrie;":                 {'\u22B4', '\u20D2'},
    -	"nvrtrie;":                 {'\u22B5', '\u20D2'},
    -	"nvsim;":                   {'\u223C', '\u20D2'},
    -	"race;":                    {'\u223D', '\u0331'},
    -	"smtes;":                   {'\u2AAC', '\uFE00'},
    -	"sqcaps;":                  {'\u2293', '\uFE00'},
    -	"sqcups;":                  {'\u2294', '\uFE00'},
    -	"varsubsetneq;":            {'\u228A', '\uFE00'},
    -	"varsubsetneqq;":           {'\u2ACB', '\uFE00'},
    -	"varsupsetneq;":            {'\u228B', '\uFE00'},
    -	"varsupsetneqq;":           {'\u2ACC', '\uFE00'},
    -	"vnsub;":                   {'\u2282', '\u20D2'},
    -	"vnsup;":                   {'\u2283', '\u20D2'},
    -	"vsubnE;":                  {'\u2ACB', '\uFE00'},
    -	"vsubne;":                  {'\u228A', '\uFE00'},
    -	"vsupnE;":                  {'\u2ACC', '\uFE00'},
    -	"vsupne;":                  {'\u228B', '\uFE00'},
    +var entity2 map[string][2]rune
    +
    +// populateMapsOnce guards calling populateMaps.
    +var populateMapsOnce sync.Once
    +
    +// populateMaps populates entity and entity2.
    +func populateMaps() {
    +	entity = map[string]rune{
    +		"AElig;":                           '\U000000C6',
    +		"AMP;":                             '\U00000026',
    +		"Aacute;":                          '\U000000C1',
    +		"Abreve;":                          '\U00000102',
    +		"Acirc;":                           '\U000000C2',
    +		"Acy;":                             '\U00000410',
    +		"Afr;":                             '\U0001D504',
    +		"Agrave;":                          '\U000000C0',
    +		"Alpha;":                           '\U00000391',
    +		"Amacr;":                           '\U00000100',
    +		"And;":                             '\U00002A53',
    +		"Aogon;":                           '\U00000104',
    +		"Aopf;":                            '\U0001D538',
    +		"ApplyFunction;":                   '\U00002061',
    +		"Aring;":                           '\U000000C5',
    +		"Ascr;":                            '\U0001D49C',
    +		"Assign;":                          '\U00002254',
    +		"Atilde;":                          '\U000000C3',
    +		"Auml;":                            '\U000000C4',
    +		"Backslash;":                       '\U00002216',
    +		"Barv;":                            '\U00002AE7',
    +		"Barwed;":                          '\U00002306',
    +		"Bcy;":                             '\U00000411',
    +		"Because;":                         '\U00002235',
    +		"Bernoullis;":                      '\U0000212C',
    +		"Beta;":                            '\U00000392',
    +		"Bfr;":                             '\U0001D505',
    +		"Bopf;":                            '\U0001D539',
    +		"Breve;":                           '\U000002D8',
    +		"Bscr;":                            '\U0000212C',
    +		"Bumpeq;":                          '\U0000224E',
    +		"CHcy;":                            '\U00000427',
    +		"COPY;":                            '\U000000A9',
    +		"Cacute;":                          '\U00000106',
    +		"Cap;":                             '\U000022D2',
    +		"CapitalDifferentialD;":            '\U00002145',
    +		"Cayleys;":                         '\U0000212D',
    +		"Ccaron;":                          '\U0000010C',
    +		"Ccedil;":                          '\U000000C7',
    +		"Ccirc;":                           '\U00000108',
    +		"Cconint;":                         '\U00002230',
    +		"Cdot;":                            '\U0000010A',
    +		"Cedilla;":                         '\U000000B8',
    +		"CenterDot;":                       '\U000000B7',
    +		"Cfr;":                             '\U0000212D',
    +		"Chi;":                             '\U000003A7',
    +		"CircleDot;":                       '\U00002299',
    +		"CircleMinus;":                     '\U00002296',
    +		"CirclePlus;":                      '\U00002295',
    +		"CircleTimes;":                     '\U00002297',
    +		"ClockwiseContourIntegral;":        '\U00002232',
    +		"CloseCurlyDoubleQuote;":           '\U0000201D',
    +		"CloseCurlyQuote;":                 '\U00002019',
    +		"Colon;":                           '\U00002237',
    +		"Colone;":                          '\U00002A74',
    +		"Congruent;":                       '\U00002261',
    +		"Conint;":                          '\U0000222F',
    +		"ContourIntegral;":                 '\U0000222E',
    +		"Copf;":                            '\U00002102',
    +		"Coproduct;":                       '\U00002210',
    +		"CounterClockwiseContourIntegral;": '\U00002233',
    +		"Cross;":                           '\U00002A2F',
    +		"Cscr;":                            '\U0001D49E',
    +		"Cup;":                             '\U000022D3',
    +		"CupCap;":                          '\U0000224D',
    +		"DD;":                              '\U00002145',
    +		"DDotrahd;":                        '\U00002911',
    +		"DJcy;":                            '\U00000402',
    +		"DScy;":                            '\U00000405',
    +		"DZcy;":                            '\U0000040F',
    +		"Dagger;":                          '\U00002021',
    +		"Darr;":                            '\U000021A1',
    +		"Dashv;":                           '\U00002AE4',
    +		"Dcaron;":                          '\U0000010E',
    +		"Dcy;":                             '\U00000414',
    +		"Del;":                             '\U00002207',
    +		"Delta;":                           '\U00000394',
    +		"Dfr;":                             '\U0001D507',
    +		"DiacriticalAcute;":                '\U000000B4',
    +		"DiacriticalDot;":                  '\U000002D9',
    +		"DiacriticalDoubleAcute;":          '\U000002DD',
    +		"DiacriticalGrave;":                '\U00000060',
    +		"DiacriticalTilde;":                '\U000002DC',
    +		"Diamond;":                         '\U000022C4',
    +		"DifferentialD;":                   '\U00002146',
    +		"Dopf;":                            '\U0001D53B',
    +		"Dot;":                             '\U000000A8',
    +		"DotDot;":                          '\U000020DC',
    +		"DotEqual;":                        '\U00002250',
    +		"DoubleContourIntegral;":           '\U0000222F',
    +		"DoubleDot;":                       '\U000000A8',
    +		"DoubleDownArrow;":                 '\U000021D3',
    +		"DoubleLeftArrow;":                 '\U000021D0',
    +		"DoubleLeftRightArrow;":            '\U000021D4',
    +		"DoubleLeftTee;":                   '\U00002AE4',
    +		"DoubleLongLeftArrow;":             '\U000027F8',
    +		"DoubleLongLeftRightArrow;":        '\U000027FA',
    +		"DoubleLongRightArrow;":            '\U000027F9',
    +		"DoubleRightArrow;":                '\U000021D2',
    +		"DoubleRightTee;":                  '\U000022A8',
    +		"DoubleUpArrow;":                   '\U000021D1',
    +		"DoubleUpDownArrow;":               '\U000021D5',
    +		"DoubleVerticalBar;":               '\U00002225',
    +		"DownArrow;":                       '\U00002193',
    +		"DownArrowBar;":                    '\U00002913',
    +		"DownArrowUpArrow;":                '\U000021F5',
    +		"DownBreve;":                       '\U00000311',
    +		"DownLeftRightVector;":             '\U00002950',
    +		"DownLeftTeeVector;":               '\U0000295E',
    +		"DownLeftVector;":                  '\U000021BD',
    +		"DownLeftVectorBar;":               '\U00002956',
    +		"DownRightTeeVector;":              '\U0000295F',
    +		"DownRightVector;":                 '\U000021C1',
    +		"DownRightVectorBar;":              '\U00002957',
    +		"DownTee;":                         '\U000022A4',
    +		"DownTeeArrow;":                    '\U000021A7',
    +		"Downarrow;":                       '\U000021D3',
    +		"Dscr;":                            '\U0001D49F',
    +		"Dstrok;":                          '\U00000110',
    +		"ENG;":                             '\U0000014A',
    +		"ETH;":                             '\U000000D0',
    +		"Eacute;":                          '\U000000C9',
    +		"Ecaron;":                          '\U0000011A',
    +		"Ecirc;":                           '\U000000CA',
    +		"Ecy;":                             '\U0000042D',
    +		"Edot;":                            '\U00000116',
    +		"Efr;":                             '\U0001D508',
    +		"Egrave;":                          '\U000000C8',
    +		"Element;":                         '\U00002208',
    +		"Emacr;":                           '\U00000112',
    +		"EmptySmallSquare;":                '\U000025FB',
    +		"EmptyVerySmallSquare;":            '\U000025AB',
    +		"Eogon;":                           '\U00000118',
    +		"Eopf;":                            '\U0001D53C',
    +		"Epsilon;":                         '\U00000395',
    +		"Equal;":                           '\U00002A75',
    +		"EqualTilde;":                      '\U00002242',
    +		"Equilibrium;":                     '\U000021CC',
    +		"Escr;":                            '\U00002130',
    +		"Esim;":                            '\U00002A73',
    +		"Eta;":                             '\U00000397',
    +		"Euml;":                            '\U000000CB',
    +		"Exists;":                          '\U00002203',
    +		"ExponentialE;":                    '\U00002147',
    +		"Fcy;":                             '\U00000424',
    +		"Ffr;":                             '\U0001D509',
    +		"FilledSmallSquare;":               '\U000025FC',
    +		"FilledVerySmallSquare;":           '\U000025AA',
    +		"Fopf;":                            '\U0001D53D',
    +		"ForAll;":                          '\U00002200',
    +		"Fouriertrf;":                      '\U00002131',
    +		"Fscr;":                            '\U00002131',
    +		"GJcy;":                            '\U00000403',
    +		"GT;":                              '\U0000003E',
    +		"Gamma;":                           '\U00000393',
    +		"Gammad;":                          '\U000003DC',
    +		"Gbreve;":                          '\U0000011E',
    +		"Gcedil;":                          '\U00000122',
    +		"Gcirc;":                           '\U0000011C',
    +		"Gcy;":                             '\U00000413',
    +		"Gdot;":                            '\U00000120',
    +		"Gfr;":                             '\U0001D50A',
    +		"Gg;":                              '\U000022D9',
    +		"Gopf;":                            '\U0001D53E',
    +		"GreaterEqual;":                    '\U00002265',
    +		"GreaterEqualLess;":                '\U000022DB',
    +		"GreaterFullEqual;":                '\U00002267',
    +		"GreaterGreater;":                  '\U00002AA2',
    +		"GreaterLess;":                     '\U00002277',
    +		"GreaterSlantEqual;":               '\U00002A7E',
    +		"GreaterTilde;":                    '\U00002273',
    +		"Gscr;":                            '\U0001D4A2',
    +		"Gt;":                              '\U0000226B',
    +		"HARDcy;":                          '\U0000042A',
    +		"Hacek;":                           '\U000002C7',
    +		"Hat;":                             '\U0000005E',
    +		"Hcirc;":                           '\U00000124',
    +		"Hfr;":                             '\U0000210C',
    +		"HilbertSpace;":                    '\U0000210B',
    +		"Hopf;":                            '\U0000210D',
    +		"HorizontalLine;":                  '\U00002500',
    +		"Hscr;":                            '\U0000210B',
    +		"Hstrok;":                          '\U00000126',
    +		"HumpDownHump;":                    '\U0000224E',
    +		"HumpEqual;":                       '\U0000224F',
    +		"IEcy;":                            '\U00000415',
    +		"IJlig;":                           '\U00000132',
    +		"IOcy;":                            '\U00000401',
    +		"Iacute;":                          '\U000000CD',
    +		"Icirc;":                           '\U000000CE',
    +		"Icy;":                             '\U00000418',
    +		"Idot;":                            '\U00000130',
    +		"Ifr;":                             '\U00002111',
    +		"Igrave;":                          '\U000000CC',
    +		"Im;":                              '\U00002111',
    +		"Imacr;":                           '\U0000012A',
    +		"ImaginaryI;":                      '\U00002148',
    +		"Implies;":                         '\U000021D2',
    +		"Int;":                             '\U0000222C',
    +		"Integral;":                        '\U0000222B',
    +		"Intersection;":                    '\U000022C2',
    +		"InvisibleComma;":                  '\U00002063',
    +		"InvisibleTimes;":                  '\U00002062',
    +		"Iogon;":                           '\U0000012E',
    +		"Iopf;":                            '\U0001D540',
    +		"Iota;":                            '\U00000399',
    +		"Iscr;":                            '\U00002110',
    +		"Itilde;":                          '\U00000128',
    +		"Iukcy;":                           '\U00000406',
    +		"Iuml;":                            '\U000000CF',
    +		"Jcirc;":                           '\U00000134',
    +		"Jcy;":                             '\U00000419',
    +		"Jfr;":                             '\U0001D50D',
    +		"Jopf;":                            '\U0001D541',
    +		"Jscr;":                            '\U0001D4A5',
    +		"Jsercy;":                          '\U00000408',
    +		"Jukcy;":                           '\U00000404',
    +		"KHcy;":                            '\U00000425',
    +		"KJcy;":                            '\U0000040C',
    +		"Kappa;":                           '\U0000039A',
    +		"Kcedil;":                          '\U00000136',
    +		"Kcy;":                             '\U0000041A',
    +		"Kfr;":                             '\U0001D50E',
    +		"Kopf;":                            '\U0001D542',
    +		"Kscr;":                            '\U0001D4A6',
    +		"LJcy;":                            '\U00000409',
    +		"LT;":                              '\U0000003C',
    +		"Lacute;":                          '\U00000139',
    +		"Lambda;":                          '\U0000039B',
    +		"Lang;":                            '\U000027EA',
    +		"Laplacetrf;":                      '\U00002112',
    +		"Larr;":                            '\U0000219E',
    +		"Lcaron;":                          '\U0000013D',
    +		"Lcedil;":                          '\U0000013B',
    +		"Lcy;":                             '\U0000041B',
    +		"LeftAngleBracket;":                '\U000027E8',
    +		"LeftArrow;":                       '\U00002190',
    +		"LeftArrowBar;":                    '\U000021E4',
    +		"LeftArrowRightArrow;":             '\U000021C6',
    +		"LeftCeiling;":                     '\U00002308',
    +		"LeftDoubleBracket;":               '\U000027E6',
    +		"LeftDownTeeVector;":               '\U00002961',
    +		"LeftDownVector;":                  '\U000021C3',
    +		"LeftDownVectorBar;":               '\U00002959',
    +		"LeftFloor;":                       '\U0000230A',
    +		"LeftRightArrow;":                  '\U00002194',
    +		"LeftRightVector;":                 '\U0000294E',
    +		"LeftTee;":                         '\U000022A3',
    +		"LeftTeeArrow;":                    '\U000021A4',
    +		"LeftTeeVector;":                   '\U0000295A',
    +		"LeftTriangle;":                    '\U000022B2',
    +		"LeftTriangleBar;":                 '\U000029CF',
    +		"LeftTriangleEqual;":               '\U000022B4',
    +		"LeftUpDownVector;":                '\U00002951',
    +		"LeftUpTeeVector;":                 '\U00002960',
    +		"LeftUpVector;":                    '\U000021BF',
    +		"LeftUpVectorBar;":                 '\U00002958',
    +		"LeftVector;":                      '\U000021BC',
    +		"LeftVectorBar;":                   '\U00002952',
    +		"Leftarrow;":                       '\U000021D0',
    +		"Leftrightarrow;":                  '\U000021D4',
    +		"LessEqualGreater;":                '\U000022DA',
    +		"LessFullEqual;":                   '\U00002266',
    +		"LessGreater;":                     '\U00002276',
    +		"LessLess;":                        '\U00002AA1',
    +		"LessSlantEqual;":                  '\U00002A7D',
    +		"LessTilde;":                       '\U00002272',
    +		"Lfr;":                             '\U0001D50F',
    +		"Ll;":                              '\U000022D8',
    +		"Lleftarrow;":                      '\U000021DA',
    +		"Lmidot;":                          '\U0000013F',
    +		"LongLeftArrow;":                   '\U000027F5',
    +		"LongLeftRightArrow;":              '\U000027F7',
    +		"LongRightArrow;":                  '\U000027F6',
    +		"Longleftarrow;":                   '\U000027F8',
    +		"Longleftrightarrow;":              '\U000027FA',
    +		"Longrightarrow;":                  '\U000027F9',
    +		"Lopf;":                            '\U0001D543',
    +		"LowerLeftArrow;":                  '\U00002199',
    +		"LowerRightArrow;":                 '\U00002198',
    +		"Lscr;":                            '\U00002112',
    +		"Lsh;":                             '\U000021B0',
    +		"Lstrok;":                          '\U00000141',
    +		"Lt;":                              '\U0000226A',
    +		"Map;":                             '\U00002905',
    +		"Mcy;":                             '\U0000041C',
    +		"MediumSpace;":                     '\U0000205F',
    +		"Mellintrf;":                       '\U00002133',
    +		"Mfr;":                             '\U0001D510',
    +		"MinusPlus;":                       '\U00002213',
    +		"Mopf;":                            '\U0001D544',
    +		"Mscr;":                            '\U00002133',
    +		"Mu;":                              '\U0000039C',
    +		"NJcy;":                            '\U0000040A',
    +		"Nacute;":                          '\U00000143',
    +		"Ncaron;":                          '\U00000147',
    +		"Ncedil;":                          '\U00000145',
    +		"Ncy;":                             '\U0000041D',
    +		"NegativeMediumSpace;":             '\U0000200B',
    +		"NegativeThickSpace;":              '\U0000200B',
    +		"NegativeThinSpace;":               '\U0000200B',
    +		"NegativeVeryThinSpace;":           '\U0000200B',
    +		"NestedGreaterGreater;":            '\U0000226B',
    +		"NestedLessLess;":                  '\U0000226A',
    +		"NewLine;":                         '\U0000000A',
    +		"Nfr;":                             '\U0001D511',
    +		"NoBreak;":                         '\U00002060',
    +		"NonBreakingSpace;":                '\U000000A0',
    +		"Nopf;":                            '\U00002115',
    +		"Not;":                             '\U00002AEC',
    +		"NotCongruent;":                    '\U00002262',
    +		"NotCupCap;":                       '\U0000226D',
    +		"NotDoubleVerticalBar;":            '\U00002226',
    +		"NotElement;":                      '\U00002209',
    +		"NotEqual;":                        '\U00002260',
    +		"NotExists;":                       '\U00002204',
    +		"NotGreater;":                      '\U0000226F',
    +		"NotGreaterEqual;":                 '\U00002271',
    +		"NotGreaterLess;":                  '\U00002279',
    +		"NotGreaterTilde;":                 '\U00002275',
    +		"NotLeftTriangle;":                 '\U000022EA',
    +		"NotLeftTriangleEqual;":            '\U000022EC',
    +		"NotLess;":                         '\U0000226E',
    +		"NotLessEqual;":                    '\U00002270',
    +		"NotLessGreater;":                  '\U00002278',
    +		"NotLessTilde;":                    '\U00002274',
    +		"NotPrecedes;":                     '\U00002280',
    +		"NotPrecedesSlantEqual;":           '\U000022E0',
    +		"NotReverseElement;":               '\U0000220C',
    +		"NotRightTriangle;":                '\U000022EB',
    +		"NotRightTriangleEqual;":           '\U000022ED',
    +		"NotSquareSubsetEqual;":            '\U000022E2',
    +		"NotSquareSupersetEqual;":          '\U000022E3',
    +		"NotSubsetEqual;":                  '\U00002288',
    +		"NotSucceeds;":                     '\U00002281',
    +		"NotSucceedsSlantEqual;":           '\U000022E1',
    +		"NotSupersetEqual;":                '\U00002289',
    +		"NotTilde;":                        '\U00002241',
    +		"NotTildeEqual;":                   '\U00002244',
    +		"NotTildeFullEqual;":               '\U00002247',
    +		"NotTildeTilde;":                   '\U00002249',
    +		"NotVerticalBar;":                  '\U00002224',
    +		"Nscr;":                            '\U0001D4A9',
    +		"Ntilde;":                          '\U000000D1',
    +		"Nu;":                              '\U0000039D',
    +		"OElig;":                           '\U00000152',
    +		"Oacute;":                          '\U000000D3',
    +		"Ocirc;":                           '\U000000D4',
    +		"Ocy;":                             '\U0000041E',
    +		"Odblac;":                          '\U00000150',
    +		"Ofr;":                             '\U0001D512',
    +		"Ograve;":                          '\U000000D2',
    +		"Omacr;":                           '\U0000014C',
    +		"Omega;":                           '\U000003A9',
    +		"Omicron;":                         '\U0000039F',
    +		"Oopf;":                            '\U0001D546',
    +		"OpenCurlyDoubleQuote;":            '\U0000201C',
    +		"OpenCurlyQuote;":                  '\U00002018',
    +		"Or;":                              '\U00002A54',
    +		"Oscr;":                            '\U0001D4AA',
    +		"Oslash;":                          '\U000000D8',
    +		"Otilde;":                          '\U000000D5',
    +		"Otimes;":                          '\U00002A37',
    +		"Ouml;":                            '\U000000D6',
    +		"OverBar;":                         '\U0000203E',
    +		"OverBrace;":                       '\U000023DE',
    +		"OverBracket;":                     '\U000023B4',
    +		"OverParenthesis;":                 '\U000023DC',
    +		"PartialD;":                        '\U00002202',
    +		"Pcy;":                             '\U0000041F',
    +		"Pfr;":                             '\U0001D513',
    +		"Phi;":                             '\U000003A6',
    +		"Pi;":                              '\U000003A0',
    +		"PlusMinus;":                       '\U000000B1',
    +		"Poincareplane;":                   '\U0000210C',
    +		"Popf;":                            '\U00002119',
    +		"Pr;":                              '\U00002ABB',
    +		"Precedes;":                        '\U0000227A',
    +		"PrecedesEqual;":                   '\U00002AAF',
    +		"PrecedesSlantEqual;":              '\U0000227C',
    +		"PrecedesTilde;":                   '\U0000227E',
    +		"Prime;":                           '\U00002033',
    +		"Product;":                         '\U0000220F',
    +		"Proportion;":                      '\U00002237',
    +		"Proportional;":                    '\U0000221D',
    +		"Pscr;":                            '\U0001D4AB',
    +		"Psi;":                             '\U000003A8',
    +		"QUOT;":                            '\U00000022',
    +		"Qfr;":                             '\U0001D514',
    +		"Qopf;":                            '\U0000211A',
    +		"Qscr;":                            '\U0001D4AC',
    +		"RBarr;":                           '\U00002910',
    +		"REG;":                             '\U000000AE',
    +		"Racute;":                          '\U00000154',
    +		"Rang;":                            '\U000027EB',
    +		"Rarr;":                            '\U000021A0',
    +		"Rarrtl;":                          '\U00002916',
    +		"Rcaron;":                          '\U00000158',
    +		"Rcedil;":                          '\U00000156',
    +		"Rcy;":                             '\U00000420',
    +		"Re;":                              '\U0000211C',
    +		"ReverseElement;":                  '\U0000220B',
    +		"ReverseEquilibrium;":              '\U000021CB',
    +		"ReverseUpEquilibrium;":            '\U0000296F',
    +		"Rfr;":                             '\U0000211C',
    +		"Rho;":                             '\U000003A1',
    +		"RightAngleBracket;":               '\U000027E9',
    +		"RightArrow;":                      '\U00002192',
    +		"RightArrowBar;":                   '\U000021E5',
    +		"RightArrowLeftArrow;":             '\U000021C4',
    +		"RightCeiling;":                    '\U00002309',
    +		"RightDoubleBracket;":              '\U000027E7',
    +		"RightDownTeeVector;":              '\U0000295D',
    +		"RightDownVector;":                 '\U000021C2',
    +		"RightDownVectorBar;":              '\U00002955',
    +		"RightFloor;":                      '\U0000230B',
    +		"RightTee;":                        '\U000022A2',
    +		"RightTeeArrow;":                   '\U000021A6',
    +		"RightTeeVector;":                  '\U0000295B',
    +		"RightTriangle;":                   '\U000022B3',
    +		"RightTriangleBar;":                '\U000029D0',
    +		"RightTriangleEqual;":              '\U000022B5',
    +		"RightUpDownVector;":               '\U0000294F',
    +		"RightUpTeeVector;":                '\U0000295C',
    +		"RightUpVector;":                   '\U000021BE',
    +		"RightUpVectorBar;":                '\U00002954',
    +		"RightVector;":                     '\U000021C0',
    +		"RightVectorBar;":                  '\U00002953',
    +		"Rightarrow;":                      '\U000021D2',
    +		"Ropf;":                            '\U0000211D',
    +		"RoundImplies;":                    '\U00002970',
    +		"Rrightarrow;":                     '\U000021DB',
    +		"Rscr;":                            '\U0000211B',
    +		"Rsh;":                             '\U000021B1',
    +		"RuleDelayed;":                     '\U000029F4',
    +		"SHCHcy;":                          '\U00000429',
    +		"SHcy;":                            '\U00000428',
    +		"SOFTcy;":                          '\U0000042C',
    +		"Sacute;":                          '\U0000015A',
    +		"Sc;":                              '\U00002ABC',
    +		"Scaron;":                          '\U00000160',
    +		"Scedil;":                          '\U0000015E',
    +		"Scirc;":                           '\U0000015C',
    +		"Scy;":                             '\U00000421',
    +		"Sfr;":                             '\U0001D516',
    +		"ShortDownArrow;":                  '\U00002193',
    +		"ShortLeftArrow;":                  '\U00002190',
    +		"ShortRightArrow;":                 '\U00002192',
    +		"ShortUpArrow;":                    '\U00002191',
    +		"Sigma;":                           '\U000003A3',
    +		"SmallCircle;":                     '\U00002218',
    +		"Sopf;":                            '\U0001D54A',
    +		"Sqrt;":                            '\U0000221A',
    +		"Square;":                          '\U000025A1',
    +		"SquareIntersection;":              '\U00002293',
    +		"SquareSubset;":                    '\U0000228F',
    +		"SquareSubsetEqual;":               '\U00002291',
    +		"SquareSuperset;":                  '\U00002290',
    +		"SquareSupersetEqual;":             '\U00002292',
    +		"SquareUnion;":                     '\U00002294',
    +		"Sscr;":                            '\U0001D4AE',
    +		"Star;":                            '\U000022C6',
    +		"Sub;":                             '\U000022D0',
    +		"Subset;":                          '\U000022D0',
    +		"SubsetEqual;":                     '\U00002286',
    +		"Succeeds;":                        '\U0000227B',
    +		"SucceedsEqual;":                   '\U00002AB0',
    +		"SucceedsSlantEqual;":              '\U0000227D',
    +		"SucceedsTilde;":                   '\U0000227F',
    +		"SuchThat;":                        '\U0000220B',
    +		"Sum;":                             '\U00002211',
    +		"Sup;":                             '\U000022D1',
    +		"Superset;":                        '\U00002283',
    +		"SupersetEqual;":                   '\U00002287',
    +		"Supset;":                          '\U000022D1',
    +		"THORN;":                           '\U000000DE',
    +		"TRADE;":                           '\U00002122',
    +		"TSHcy;":                           '\U0000040B',
    +		"TScy;":                            '\U00000426',
    +		"Tab;":                             '\U00000009',
    +		"Tau;":                             '\U000003A4',
    +		"Tcaron;":                          '\U00000164',
    +		"Tcedil;":                          '\U00000162',
    +		"Tcy;":                             '\U00000422',
    +		"Tfr;":                             '\U0001D517',
    +		"Therefore;":                       '\U00002234',
    +		"Theta;":                           '\U00000398',
    +		"ThinSpace;":                       '\U00002009',
    +		"Tilde;":                           '\U0000223C',
    +		"TildeEqual;":                      '\U00002243',
    +		"TildeFullEqual;":                  '\U00002245',
    +		"TildeTilde;":                      '\U00002248',
    +		"Topf;":                            '\U0001D54B',
    +		"TripleDot;":                       '\U000020DB',
    +		"Tscr;":                            '\U0001D4AF',
    +		"Tstrok;":                          '\U00000166',
    +		"Uacute;":                          '\U000000DA',
    +		"Uarr;":                            '\U0000219F',
    +		"Uarrocir;":                        '\U00002949',
    +		"Ubrcy;":                           '\U0000040E',
    +		"Ubreve;":                          '\U0000016C',
    +		"Ucirc;":                           '\U000000DB',
    +		"Ucy;":                             '\U00000423',
    +		"Udblac;":                          '\U00000170',
    +		"Ufr;":                             '\U0001D518',
    +		"Ugrave;":                          '\U000000D9',
    +		"Umacr;":                           '\U0000016A',
    +		"UnderBar;":                        '\U0000005F',
    +		"UnderBrace;":                      '\U000023DF',
    +		"UnderBracket;":                    '\U000023B5',
    +		"UnderParenthesis;":                '\U000023DD',
    +		"Union;":                           '\U000022C3',
    +		"UnionPlus;":                       '\U0000228E',
    +		"Uogon;":                           '\U00000172',
    +		"Uopf;":                            '\U0001D54C',
    +		"UpArrow;":                         '\U00002191',
    +		"UpArrowBar;":                      '\U00002912',
    +		"UpArrowDownArrow;":                '\U000021C5',
    +		"UpDownArrow;":                     '\U00002195',
    +		"UpEquilibrium;":                   '\U0000296E',
    +		"UpTee;":                           '\U000022A5',
    +		"UpTeeArrow;":                      '\U000021A5',
    +		"Uparrow;":                         '\U000021D1',
    +		"Updownarrow;":                     '\U000021D5',
    +		"UpperLeftArrow;":                  '\U00002196',
    +		"UpperRightArrow;":                 '\U00002197',
    +		"Upsi;":                            '\U000003D2',
    +		"Upsilon;":                         '\U000003A5',
    +		"Uring;":                           '\U0000016E',
    +		"Uscr;":                            '\U0001D4B0',
    +		"Utilde;":                          '\U00000168',
    +		"Uuml;":                            '\U000000DC',
    +		"VDash;":                           '\U000022AB',
    +		"Vbar;":                            '\U00002AEB',
    +		"Vcy;":                             '\U00000412',
    +		"Vdash;":                           '\U000022A9',
    +		"Vdashl;":                          '\U00002AE6',
    +		"Vee;":                             '\U000022C1',
    +		"Verbar;":                          '\U00002016',
    +		"Vert;":                            '\U00002016',
    +		"VerticalBar;":                     '\U00002223',
    +		"VerticalLine;":                    '\U0000007C',
    +		"VerticalSeparator;":               '\U00002758',
    +		"VerticalTilde;":                   '\U00002240',
    +		"VeryThinSpace;":                   '\U0000200A',
    +		"Vfr;":                             '\U0001D519',
    +		"Vopf;":                            '\U0001D54D',
    +		"Vscr;":                            '\U0001D4B1',
    +		"Vvdash;":                          '\U000022AA',
    +		"Wcirc;":                           '\U00000174',
    +		"Wedge;":                           '\U000022C0',
    +		"Wfr;":                             '\U0001D51A',
    +		"Wopf;":                            '\U0001D54E',
    +		"Wscr;":                            '\U0001D4B2',
    +		"Xfr;":                             '\U0001D51B',
    +		"Xi;":                              '\U0000039E',
    +		"Xopf;":                            '\U0001D54F',
    +		"Xscr;":                            '\U0001D4B3',
    +		"YAcy;":                            '\U0000042F',
    +		"YIcy;":                            '\U00000407',
    +		"YUcy;":                            '\U0000042E',
    +		"Yacute;":                          '\U000000DD',
    +		"Ycirc;":                           '\U00000176',
    +		"Ycy;":                             '\U0000042B',
    +		"Yfr;":                             '\U0001D51C',
    +		"Yopf;":                            '\U0001D550',
    +		"Yscr;":                            '\U0001D4B4',
    +		"Yuml;":                            '\U00000178',
    +		"ZHcy;":                            '\U00000416',
    +		"Zacute;":                          '\U00000179',
    +		"Zcaron;":                          '\U0000017D',
    +		"Zcy;":                             '\U00000417',
    +		"Zdot;":                            '\U0000017B',
    +		"ZeroWidthSpace;":                  '\U0000200B',
    +		"Zeta;":                            '\U00000396',
    +		"Zfr;":                             '\U00002128',
    +		"Zopf;":                            '\U00002124',
    +		"Zscr;":                            '\U0001D4B5',
    +		"aacute;":                          '\U000000E1',
    +		"abreve;":                          '\U00000103',
    +		"ac;":                              '\U0000223E',
    +		"acd;":                             '\U0000223F',
    +		"acirc;":                           '\U000000E2',
    +		"acute;":                           '\U000000B4',
    +		"acy;":                             '\U00000430',
    +		"aelig;":                           '\U000000E6',
    +		"af;":                              '\U00002061',
    +		"afr;":                             '\U0001D51E',
    +		"agrave;":                          '\U000000E0',
    +		"alefsym;":                         '\U00002135',
    +		"aleph;":                           '\U00002135',
    +		"alpha;":                           '\U000003B1',
    +		"amacr;":                           '\U00000101',
    +		"amalg;":                           '\U00002A3F',
    +		"amp;":                             '\U00000026',
    +		"and;":                             '\U00002227',
    +		"andand;":                          '\U00002A55',
    +		"andd;":                            '\U00002A5C',
    +		"andslope;":                        '\U00002A58',
    +		"andv;":                            '\U00002A5A',
    +		"ang;":                             '\U00002220',
    +		"ange;":                            '\U000029A4',
    +		"angle;":                           '\U00002220',
    +		"angmsd;":                          '\U00002221',
    +		"angmsdaa;":                        '\U000029A8',
    +		"angmsdab;":                        '\U000029A9',
    +		"angmsdac;":                        '\U000029AA',
    +		"angmsdad;":                        '\U000029AB',
    +		"angmsdae;":                        '\U000029AC',
    +		"angmsdaf;":                        '\U000029AD',
    +		"angmsdag;":                        '\U000029AE',
    +		"angmsdah;":                        '\U000029AF',
    +		"angrt;":                           '\U0000221F',
    +		"angrtvb;":                         '\U000022BE',
    +		"angrtvbd;":                        '\U0000299D',
    +		"angsph;":                          '\U00002222',
    +		"angst;":                           '\U000000C5',
    +		"angzarr;":                         '\U0000237C',
    +		"aogon;":                           '\U00000105',
    +		"aopf;":                            '\U0001D552',
    +		"ap;":                              '\U00002248',
    +		"apE;":                             '\U00002A70',
    +		"apacir;":                          '\U00002A6F',
    +		"ape;":                             '\U0000224A',
    +		"apid;":                            '\U0000224B',
    +		"apos;":                            '\U00000027',
    +		"approx;":                          '\U00002248',
    +		"approxeq;":                        '\U0000224A',
    +		"aring;":                           '\U000000E5',
    +		"ascr;":                            '\U0001D4B6',
    +		"ast;":                             '\U0000002A',
    +		"asymp;":                           '\U00002248',
    +		"asympeq;":                         '\U0000224D',
    +		"atilde;":                          '\U000000E3',
    +		"auml;":                            '\U000000E4',
    +		"awconint;":                        '\U00002233',
    +		"awint;":                           '\U00002A11',
    +		"bNot;":                            '\U00002AED',
    +		"backcong;":                        '\U0000224C',
    +		"backepsilon;":                     '\U000003F6',
    +		"backprime;":                       '\U00002035',
    +		"backsim;":                         '\U0000223D',
    +		"backsimeq;":                       '\U000022CD',
    +		"barvee;":                          '\U000022BD',
    +		"barwed;":                          '\U00002305',
    +		"barwedge;":                        '\U00002305',
    +		"bbrk;":                            '\U000023B5',
    +		"bbrktbrk;":                        '\U000023B6',
    +		"bcong;":                           '\U0000224C',
    +		"bcy;":                             '\U00000431',
    +		"bdquo;":                           '\U0000201E',
    +		"becaus;":                          '\U00002235',
    +		"because;":                         '\U00002235',
    +		"bemptyv;":                         '\U000029B0',
    +		"bepsi;":                           '\U000003F6',
    +		"bernou;":                          '\U0000212C',
    +		"beta;":                            '\U000003B2',
    +		"beth;":                            '\U00002136',
    +		"between;":                         '\U0000226C',
    +		"bfr;":                             '\U0001D51F',
    +		"bigcap;":                          '\U000022C2',
    +		"bigcirc;":                         '\U000025EF',
    +		"bigcup;":                          '\U000022C3',
    +		"bigodot;":                         '\U00002A00',
    +		"bigoplus;":                        '\U00002A01',
    +		"bigotimes;":                       '\U00002A02',
    +		"bigsqcup;":                        '\U00002A06',
    +		"bigstar;":                         '\U00002605',
    +		"bigtriangledown;":                 '\U000025BD',
    +		"bigtriangleup;":                   '\U000025B3',
    +		"biguplus;":                        '\U00002A04',
    +		"bigvee;":                          '\U000022C1',
    +		"bigwedge;":                        '\U000022C0',
    +		"bkarow;":                          '\U0000290D',
    +		"blacklozenge;":                    '\U000029EB',
    +		"blacksquare;":                     '\U000025AA',
    +		"blacktriangle;":                   '\U000025B4',
    +		"blacktriangledown;":               '\U000025BE',
    +		"blacktriangleleft;":               '\U000025C2',
    +		"blacktriangleright;":              '\U000025B8',
    +		"blank;":                           '\U00002423',
    +		"blk12;":                           '\U00002592',
    +		"blk14;":                           '\U00002591',
    +		"blk34;":                           '\U00002593',
    +		"block;":                           '\U00002588',
    +		"bnot;":                            '\U00002310',
    +		"bopf;":                            '\U0001D553',
    +		"bot;":                             '\U000022A5',
    +		"bottom;":                          '\U000022A5',
    +		"bowtie;":                          '\U000022C8',
    +		"boxDL;":                           '\U00002557',
    +		"boxDR;":                           '\U00002554',
    +		"boxDl;":                           '\U00002556',
    +		"boxDr;":                           '\U00002553',
    +		"boxH;":                            '\U00002550',
    +		"boxHD;":                           '\U00002566',
    +		"boxHU;":                           '\U00002569',
    +		"boxHd;":                           '\U00002564',
    +		"boxHu;":                           '\U00002567',
    +		"boxUL;":                           '\U0000255D',
    +		"boxUR;":                           '\U0000255A',
    +		"boxUl;":                           '\U0000255C',
    +		"boxUr;":                           '\U00002559',
    +		"boxV;":                            '\U00002551',
    +		"boxVH;":                           '\U0000256C',
    +		"boxVL;":                           '\U00002563',
    +		"boxVR;":                           '\U00002560',
    +		"boxVh;":                           '\U0000256B',
    +		"boxVl;":                           '\U00002562',
    +		"boxVr;":                           '\U0000255F',
    +		"boxbox;":                          '\U000029C9',
    +		"boxdL;":                           '\U00002555',
    +		"boxdR;":                           '\U00002552',
    +		"boxdl;":                           '\U00002510',
    +		"boxdr;":                           '\U0000250C',
    +		"boxh;":                            '\U00002500',
    +		"boxhD;":                           '\U00002565',
    +		"boxhU;":                           '\U00002568',
    +		"boxhd;":                           '\U0000252C',
    +		"boxhu;":                           '\U00002534',
    +		"boxminus;":                        '\U0000229F',
    +		"boxplus;":                         '\U0000229E',
    +		"boxtimes;":                        '\U000022A0',
    +		"boxuL;":                           '\U0000255B',
    +		"boxuR;":                           '\U00002558',
    +		"boxul;":                           '\U00002518',
    +		"boxur;":                           '\U00002514',
    +		"boxv;":                            '\U00002502',
    +		"boxvH;":                           '\U0000256A',
    +		"boxvL;":                           '\U00002561',
    +		"boxvR;":                           '\U0000255E',
    +		"boxvh;":                           '\U0000253C',
    +		"boxvl;":                           '\U00002524',
    +		"boxvr;":                           '\U0000251C',
    +		"bprime;":                          '\U00002035',
    +		"breve;":                           '\U000002D8',
    +		"brvbar;":                          '\U000000A6',
    +		"bscr;":                            '\U0001D4B7',
    +		"bsemi;":                           '\U0000204F',
    +		"bsim;":                            '\U0000223D',
    +		"bsime;":                           '\U000022CD',
    +		"bsol;":                            '\U0000005C',
    +		"bsolb;":                           '\U000029C5',
    +		"bsolhsub;":                        '\U000027C8',
    +		"bull;":                            '\U00002022',
    +		"bullet;":                          '\U00002022',
    +		"bump;":                            '\U0000224E',
    +		"bumpE;":                           '\U00002AAE',
    +		"bumpe;":                           '\U0000224F',
    +		"bumpeq;":                          '\U0000224F',
    +		"cacute;":                          '\U00000107',
    +		"cap;":                             '\U00002229',
    +		"capand;":                          '\U00002A44',
    +		"capbrcup;":                        '\U00002A49',
    +		"capcap;":                          '\U00002A4B',
    +		"capcup;":                          '\U00002A47',
    +		"capdot;":                          '\U00002A40',
    +		"caret;":                           '\U00002041',
    +		"caron;":                           '\U000002C7',
    +		"ccaps;":                           '\U00002A4D',
    +		"ccaron;":                          '\U0000010D',
    +		"ccedil;":                          '\U000000E7',
    +		"ccirc;":                           '\U00000109',
    +		"ccups;":                           '\U00002A4C',
    +		"ccupssm;":                         '\U00002A50',
    +		"cdot;":                            '\U0000010B',
    +		"cedil;":                           '\U000000B8',
    +		"cemptyv;":                         '\U000029B2',
    +		"cent;":                            '\U000000A2',
    +		"centerdot;":                       '\U000000B7',
    +		"cfr;":                             '\U0001D520',
    +		"chcy;":                            '\U00000447',
    +		"check;":                           '\U00002713',
    +		"checkmark;":                       '\U00002713',
    +		"chi;":                             '\U000003C7',
    +		"cir;":                             '\U000025CB',
    +		"cirE;":                            '\U000029C3',
    +		"circ;":                            '\U000002C6',
    +		"circeq;":                          '\U00002257',
    +		"circlearrowleft;":                 '\U000021BA',
    +		"circlearrowright;":                '\U000021BB',
    +		"circledR;":                        '\U000000AE',
    +		"circledS;":                        '\U000024C8',
    +		"circledast;":                      '\U0000229B',
    +		"circledcirc;":                     '\U0000229A',
    +		"circleddash;":                     '\U0000229D',
    +		"cire;":                            '\U00002257',
    +		"cirfnint;":                        '\U00002A10',
    +		"cirmid;":                          '\U00002AEF',
    +		"cirscir;":                         '\U000029C2',
    +		"clubs;":                           '\U00002663',
    +		"clubsuit;":                        '\U00002663',
    +		"colon;":                           '\U0000003A',
    +		"colone;":                          '\U00002254',
    +		"coloneq;":                         '\U00002254',
    +		"comma;":                           '\U0000002C',
    +		"commat;":                          '\U00000040',
    +		"comp;":                            '\U00002201',
    +		"compfn;":                          '\U00002218',
    +		"complement;":                      '\U00002201',
    +		"complexes;":                       '\U00002102',
    +		"cong;":                            '\U00002245',
    +		"congdot;":                         '\U00002A6D',
    +		"conint;":                          '\U0000222E',
    +		"copf;":                            '\U0001D554',
    +		"coprod;":                          '\U00002210',
    +		"copy;":                            '\U000000A9',
    +		"copysr;":                          '\U00002117',
    +		"crarr;":                           '\U000021B5',
    +		"cross;":                           '\U00002717',
    +		"cscr;":                            '\U0001D4B8',
    +		"csub;":                            '\U00002ACF',
    +		"csube;":                           '\U00002AD1',
    +		"csup;":                            '\U00002AD0',
    +		"csupe;":                           '\U00002AD2',
    +		"ctdot;":                           '\U000022EF',
    +		"cudarrl;":                         '\U00002938',
    +		"cudarrr;":                         '\U00002935',
    +		"cuepr;":                           '\U000022DE',
    +		"cuesc;":                           '\U000022DF',
    +		"cularr;":                          '\U000021B6',
    +		"cularrp;":                         '\U0000293D',
    +		"cup;":                             '\U0000222A',
    +		"cupbrcap;":                        '\U00002A48',
    +		"cupcap;":                          '\U00002A46',
    +		"cupcup;":                          '\U00002A4A',
    +		"cupdot;":                          '\U0000228D',
    +		"cupor;":                           '\U00002A45',
    +		"curarr;":                          '\U000021B7',
    +		"curarrm;":                         '\U0000293C',
    +		"curlyeqprec;":                     '\U000022DE',
    +		"curlyeqsucc;":                     '\U000022DF',
    +		"curlyvee;":                        '\U000022CE',
    +		"curlywedge;":                      '\U000022CF',
    +		"curren;":                          '\U000000A4',
    +		"curvearrowleft;":                  '\U000021B6',
    +		"curvearrowright;":                 '\U000021B7',
    +		"cuvee;":                           '\U000022CE',
    +		"cuwed;":                           '\U000022CF',
    +		"cwconint;":                        '\U00002232',
    +		"cwint;":                           '\U00002231',
    +		"cylcty;":                          '\U0000232D',
    +		"dArr;":                            '\U000021D3',
    +		"dHar;":                            '\U00002965',
    +		"dagger;":                          '\U00002020',
    +		"daleth;":                          '\U00002138',
    +		"darr;":                            '\U00002193',
    +		"dash;":                            '\U00002010',
    +		"dashv;":                           '\U000022A3',
    +		"dbkarow;":                         '\U0000290F',
    +		"dblac;":                           '\U000002DD',
    +		"dcaron;":                          '\U0000010F',
    +		"dcy;":                             '\U00000434',
    +		"dd;":                              '\U00002146',
    +		"ddagger;":                         '\U00002021',
    +		"ddarr;":                           '\U000021CA',
    +		"ddotseq;":                         '\U00002A77',
    +		"deg;":                             '\U000000B0',
    +		"delta;":                           '\U000003B4',
    +		"demptyv;":                         '\U000029B1',
    +		"dfisht;":                          '\U0000297F',
    +		"dfr;":                             '\U0001D521',
    +		"dharl;":                           '\U000021C3',
    +		"dharr;":                           '\U000021C2',
    +		"diam;":                            '\U000022C4',
    +		"diamond;":                         '\U000022C4',
    +		"diamondsuit;":                     '\U00002666',
    +		"diams;":                           '\U00002666',
    +		"die;":                             '\U000000A8',
    +		"digamma;":                         '\U000003DD',
    +		"disin;":                           '\U000022F2',
    +		"div;":                             '\U000000F7',
    +		"divide;":                          '\U000000F7',
    +		"divideontimes;":                   '\U000022C7',
    +		"divonx;":                          '\U000022C7',
    +		"djcy;":                            '\U00000452',
    +		"dlcorn;":                          '\U0000231E',
    +		"dlcrop;":                          '\U0000230D',
    +		"dollar;":                          '\U00000024',
    +		"dopf;":                            '\U0001D555',
    +		"dot;":                             '\U000002D9',
    +		"doteq;":                           '\U00002250',
    +		"doteqdot;":                        '\U00002251',
    +		"dotminus;":                        '\U00002238',
    +		"dotplus;":                         '\U00002214',
    +		"dotsquare;":                       '\U000022A1',
    +		"doublebarwedge;":                  '\U00002306',
    +		"downarrow;":                       '\U00002193',
    +		"downdownarrows;":                  '\U000021CA',
    +		"downharpoonleft;":                 '\U000021C3',
    +		"downharpoonright;":                '\U000021C2',
    +		"drbkarow;":                        '\U00002910',
    +		"drcorn;":                          '\U0000231F',
    +		"drcrop;":                          '\U0000230C',
    +		"dscr;":                            '\U0001D4B9',
    +		"dscy;":                            '\U00000455',
    +		"dsol;":                            '\U000029F6',
    +		"dstrok;":                          '\U00000111',
    +		"dtdot;":                           '\U000022F1',
    +		"dtri;":                            '\U000025BF',
    +		"dtrif;":                           '\U000025BE',
    +		"duarr;":                           '\U000021F5',
    +		"duhar;":                           '\U0000296F',
    +		"dwangle;":                         '\U000029A6',
    +		"dzcy;":                            '\U0000045F',
    +		"dzigrarr;":                        '\U000027FF',
    +		"eDDot;":                           '\U00002A77',
    +		"eDot;":                            '\U00002251',
    +		"eacute;":                          '\U000000E9',
    +		"easter;":                          '\U00002A6E',
    +		"ecaron;":                          '\U0000011B',
    +		"ecir;":                            '\U00002256',
    +		"ecirc;":                           '\U000000EA',
    +		"ecolon;":                          '\U00002255',
    +		"ecy;":                             '\U0000044D',
    +		"edot;":                            '\U00000117',
    +		"ee;":                              '\U00002147',
    +		"efDot;":                           '\U00002252',
    +		"efr;":                             '\U0001D522',
    +		"eg;":                              '\U00002A9A',
    +		"egrave;":                          '\U000000E8',
    +		"egs;":                             '\U00002A96',
    +		"egsdot;":                          '\U00002A98',
    +		"el;":                              '\U00002A99',
    +		"elinters;":                        '\U000023E7',
    +		"ell;":                             '\U00002113',
    +		"els;":                             '\U00002A95',
    +		"elsdot;":                          '\U00002A97',
    +		"emacr;":                           '\U00000113',
    +		"empty;":                           '\U00002205',
    +		"emptyset;":                        '\U00002205',
    +		"emptyv;":                          '\U00002205',
    +		"emsp;":                            '\U00002003',
    +		"emsp13;":                          '\U00002004',
    +		"emsp14;":                          '\U00002005',
    +		"eng;":                             '\U0000014B',
    +		"ensp;":                            '\U00002002',
    +		"eogon;":                           '\U00000119',
    +		"eopf;":                            '\U0001D556',
    +		"epar;":                            '\U000022D5',
    +		"eparsl;":                          '\U000029E3',
    +		"eplus;":                           '\U00002A71',
    +		"epsi;":                            '\U000003B5',
    +		"epsilon;":                         '\U000003B5',
    +		"epsiv;":                           '\U000003F5',
    +		"eqcirc;":                          '\U00002256',
    +		"eqcolon;":                         '\U00002255',
    +		"eqsim;":                           '\U00002242',
    +		"eqslantgtr;":                      '\U00002A96',
    +		"eqslantless;":                     '\U00002A95',
    +		"equals;":                          '\U0000003D',
    +		"equest;":                          '\U0000225F',
    +		"equiv;":                           '\U00002261',
    +		"equivDD;":                         '\U00002A78',
    +		"eqvparsl;":                        '\U000029E5',
    +		"erDot;":                           '\U00002253',
    +		"erarr;":                           '\U00002971',
    +		"escr;":                            '\U0000212F',
    +		"esdot;":                           '\U00002250',
    +		"esim;":                            '\U00002242',
    +		"eta;":                             '\U000003B7',
    +		"eth;":                             '\U000000F0',
    +		"euml;":                            '\U000000EB',
    +		"euro;":                            '\U000020AC',
    +		"excl;":                            '\U00000021',
    +		"exist;":                           '\U00002203',
    +		"expectation;":                     '\U00002130',
    +		"exponentiale;":                    '\U00002147',
    +		"fallingdotseq;":                   '\U00002252',
    +		"fcy;":                             '\U00000444',
    +		"female;":                          '\U00002640',
    +		"ffilig;":                          '\U0000FB03',
    +		"fflig;":                           '\U0000FB00',
    +		"ffllig;":                          '\U0000FB04',
    +		"ffr;":                             '\U0001D523',
    +		"filig;":                           '\U0000FB01',
    +		"flat;":                            '\U0000266D',
    +		"fllig;":                           '\U0000FB02',
    +		"fltns;":                           '\U000025B1',
    +		"fnof;":                            '\U00000192',
    +		"fopf;":                            '\U0001D557',
    +		"forall;":                          '\U00002200',
    +		"fork;":                            '\U000022D4',
    +		"forkv;":                           '\U00002AD9',
    +		"fpartint;":                        '\U00002A0D',
    +		"frac12;":                          '\U000000BD',
    +		"frac13;":                          '\U00002153',
    +		"frac14;":                          '\U000000BC',
    +		"frac15;":                          '\U00002155',
    +		"frac16;":                          '\U00002159',
    +		"frac18;":                          '\U0000215B',
    +		"frac23;":                          '\U00002154',
    +		"frac25;":                          '\U00002156',
    +		"frac34;":                          '\U000000BE',
    +		"frac35;":                          '\U00002157',
    +		"frac38;":                          '\U0000215C',
    +		"frac45;":                          '\U00002158',
    +		"frac56;":                          '\U0000215A',
    +		"frac58;":                          '\U0000215D',
    +		"frac78;":                          '\U0000215E',
    +		"frasl;":                           '\U00002044',
    +		"frown;":                           '\U00002322',
    +		"fscr;":                            '\U0001D4BB',
    +		"gE;":                              '\U00002267',
    +		"gEl;":                             '\U00002A8C',
    +		"gacute;":                          '\U000001F5',
    +		"gamma;":                           '\U000003B3',
    +		"gammad;":                          '\U000003DD',
    +		"gap;":                             '\U00002A86',
    +		"gbreve;":                          '\U0000011F',
    +		"gcirc;":                           '\U0000011D',
    +		"gcy;":                             '\U00000433',
    +		"gdot;":                            '\U00000121',
    +		"ge;":                              '\U00002265',
    +		"gel;":                             '\U000022DB',
    +		"geq;":                             '\U00002265',
    +		"geqq;":                            '\U00002267',
    +		"geqslant;":                        '\U00002A7E',
    +		"ges;":                             '\U00002A7E',
    +		"gescc;":                           '\U00002AA9',
    +		"gesdot;":                          '\U00002A80',
    +		"gesdoto;":                         '\U00002A82',
    +		"gesdotol;":                        '\U00002A84',
    +		"gesles;":                          '\U00002A94',
    +		"gfr;":                             '\U0001D524',
    +		"gg;":                              '\U0000226B',
    +		"ggg;":                             '\U000022D9',
    +		"gimel;":                           '\U00002137',
    +		"gjcy;":                            '\U00000453',
    +		"gl;":                              '\U00002277',
    +		"glE;":                             '\U00002A92',
    +		"gla;":                             '\U00002AA5',
    +		"glj;":                             '\U00002AA4',
    +		"gnE;":                             '\U00002269',
    +		"gnap;":                            '\U00002A8A',
    +		"gnapprox;":                        '\U00002A8A',
    +		"gne;":                             '\U00002A88',
    +		"gneq;":                            '\U00002A88',
    +		"gneqq;":                           '\U00002269',
    +		"gnsim;":                           '\U000022E7',
    +		"gopf;":                            '\U0001D558',
    +		"grave;":                           '\U00000060',
    +		"gscr;":                            '\U0000210A',
    +		"gsim;":                            '\U00002273',
    +		"gsime;":                           '\U00002A8E',
    +		"gsiml;":                           '\U00002A90',
    +		"gt;":                              '\U0000003E',
    +		"gtcc;":                            '\U00002AA7',
    +		"gtcir;":                           '\U00002A7A',
    +		"gtdot;":                           '\U000022D7',
    +		"gtlPar;":                          '\U00002995',
    +		"gtquest;":                         '\U00002A7C',
    +		"gtrapprox;":                       '\U00002A86',
    +		"gtrarr;":                          '\U00002978',
    +		"gtrdot;":                          '\U000022D7',
    +		"gtreqless;":                       '\U000022DB',
    +		"gtreqqless;":                      '\U00002A8C',
    +		"gtrless;":                         '\U00002277',
    +		"gtrsim;":                          '\U00002273',
    +		"hArr;":                            '\U000021D4',
    +		"hairsp;":                          '\U0000200A',
    +		"half;":                            '\U000000BD',
    +		"hamilt;":                          '\U0000210B',
    +		"hardcy;":                          '\U0000044A',
    +		"harr;":                            '\U00002194',
    +		"harrcir;":                         '\U00002948',
    +		"harrw;":                           '\U000021AD',
    +		"hbar;":                            '\U0000210F',
    +		"hcirc;":                           '\U00000125',
    +		"hearts;":                          '\U00002665',
    +		"heartsuit;":                       '\U00002665',
    +		"hellip;":                          '\U00002026',
    +		"hercon;":                          '\U000022B9',
    +		"hfr;":                             '\U0001D525',
    +		"hksearow;":                        '\U00002925',
    +		"hkswarow;":                        '\U00002926',
    +		"hoarr;":                           '\U000021FF',
    +		"homtht;":                          '\U0000223B',
    +		"hookleftarrow;":                   '\U000021A9',
    +		"hookrightarrow;":                  '\U000021AA',
    +		"hopf;":                            '\U0001D559',
    +		"horbar;":                          '\U00002015',
    +		"hscr;":                            '\U0001D4BD',
    +		"hslash;":                          '\U0000210F',
    +		"hstrok;":                          '\U00000127',
    +		"hybull;":                          '\U00002043',
    +		"hyphen;":                          '\U00002010',
    +		"iacute;":                          '\U000000ED',
    +		"ic;":                              '\U00002063',
    +		"icirc;":                           '\U000000EE',
    +		"icy;":                             '\U00000438',
    +		"iecy;":                            '\U00000435',
    +		"iexcl;":                           '\U000000A1',
    +		"iff;":                             '\U000021D4',
    +		"ifr;":                             '\U0001D526',
    +		"igrave;":                          '\U000000EC',
    +		"ii;":                              '\U00002148',
    +		"iiiint;":                          '\U00002A0C',
    +		"iiint;":                           '\U0000222D',
    +		"iinfin;":                          '\U000029DC',
    +		"iiota;":                           '\U00002129',
    +		"ijlig;":                           '\U00000133',
    +		"imacr;":                           '\U0000012B',
    +		"image;":                           '\U00002111',
    +		"imagline;":                        '\U00002110',
    +		"imagpart;":                        '\U00002111',
    +		"imath;":                           '\U00000131',
    +		"imof;":                            '\U000022B7',
    +		"imped;":                           '\U000001B5',
    +		"in;":                              '\U00002208',
    +		"incare;":                          '\U00002105',
    +		"infin;":                           '\U0000221E',
    +		"infintie;":                        '\U000029DD',
    +		"inodot;":                          '\U00000131',
    +		"int;":                             '\U0000222B',
    +		"intcal;":                          '\U000022BA',
    +		"integers;":                        '\U00002124',
    +		"intercal;":                        '\U000022BA',
    +		"intlarhk;":                        '\U00002A17',
    +		"intprod;":                         '\U00002A3C',
    +		"iocy;":                            '\U00000451',
    +		"iogon;":                           '\U0000012F',
    +		"iopf;":                            '\U0001D55A',
    +		"iota;":                            '\U000003B9',
    +		"iprod;":                           '\U00002A3C',
    +		"iquest;":                          '\U000000BF',
    +		"iscr;":                            '\U0001D4BE',
    +		"isin;":                            '\U00002208',
    +		"isinE;":                           '\U000022F9',
    +		"isindot;":                         '\U000022F5',
    +		"isins;":                           '\U000022F4',
    +		"isinsv;":                          '\U000022F3',
    +		"isinv;":                           '\U00002208',
    +		"it;":                              '\U00002062',
    +		"itilde;":                          '\U00000129',
    +		"iukcy;":                           '\U00000456',
    +		"iuml;":                            '\U000000EF',
    +		"jcirc;":                           '\U00000135',
    +		"jcy;":                             '\U00000439',
    +		"jfr;":                             '\U0001D527',
    +		"jmath;":                           '\U00000237',
    +		"jopf;":                            '\U0001D55B',
    +		"jscr;":                            '\U0001D4BF',
    +		"jsercy;":                          '\U00000458',
    +		"jukcy;":                           '\U00000454',
    +		"kappa;":                           '\U000003BA',
    +		"kappav;":                          '\U000003F0',
    +		"kcedil;":                          '\U00000137',
    +		"kcy;":                             '\U0000043A',
    +		"kfr;":                             '\U0001D528',
    +		"kgreen;":                          '\U00000138',
    +		"khcy;":                            '\U00000445',
    +		"kjcy;":                            '\U0000045C',
    +		"kopf;":                            '\U0001D55C',
    +		"kscr;":                            '\U0001D4C0',
    +		"lAarr;":                           '\U000021DA',
    +		"lArr;":                            '\U000021D0',
    +		"lAtail;":                          '\U0000291B',
    +		"lBarr;":                           '\U0000290E',
    +		"lE;":                              '\U00002266',
    +		"lEg;":                             '\U00002A8B',
    +		"lHar;":                            '\U00002962',
    +		"lacute;":                          '\U0000013A',
    +		"laemptyv;":                        '\U000029B4',
    +		"lagran;":                          '\U00002112',
    +		"lambda;":                          '\U000003BB',
    +		"lang;":                            '\U000027E8',
    +		"langd;":                           '\U00002991',
    +		"langle;":                          '\U000027E8',
    +		"lap;":                             '\U00002A85',
    +		"laquo;":                           '\U000000AB',
    +		"larr;":                            '\U00002190',
    +		"larrb;":                           '\U000021E4',
    +		"larrbfs;":                         '\U0000291F',
    +		"larrfs;":                          '\U0000291D',
    +		"larrhk;":                          '\U000021A9',
    +		"larrlp;":                          '\U000021AB',
    +		"larrpl;":                          '\U00002939',
    +		"larrsim;":                         '\U00002973',
    +		"larrtl;":                          '\U000021A2',
    +		"lat;":                             '\U00002AAB',
    +		"latail;":                          '\U00002919',
    +		"late;":                            '\U00002AAD',
    +		"lbarr;":                           '\U0000290C',
    +		"lbbrk;":                           '\U00002772',
    +		"lbrace;":                          '\U0000007B',
    +		"lbrack;":                          '\U0000005B',
    +		"lbrke;":                           '\U0000298B',
    +		"lbrksld;":                         '\U0000298F',
    +		"lbrkslu;":                         '\U0000298D',
    +		"lcaron;":                          '\U0000013E',
    +		"lcedil;":                          '\U0000013C',
    +		"lceil;":                           '\U00002308',
    +		"lcub;":                            '\U0000007B',
    +		"lcy;":                             '\U0000043B',
    +		"ldca;":                            '\U00002936',
    +		"ldquo;":                           '\U0000201C',
    +		"ldquor;":                          '\U0000201E',
    +		"ldrdhar;":                         '\U00002967',
    +		"ldrushar;":                        '\U0000294B',
    +		"ldsh;":                            '\U000021B2',
    +		"le;":                              '\U00002264',
    +		"leftarrow;":                       '\U00002190',
    +		"leftarrowtail;":                   '\U000021A2',
    +		"leftharpoondown;":                 '\U000021BD',
    +		"leftharpoonup;":                   '\U000021BC',
    +		"leftleftarrows;":                  '\U000021C7',
    +		"leftrightarrow;":                  '\U00002194',
    +		"leftrightarrows;":                 '\U000021C6',
    +		"leftrightharpoons;":               '\U000021CB',
    +		"leftrightsquigarrow;":             '\U000021AD',
    +		"leftthreetimes;":                  '\U000022CB',
    +		"leg;":                             '\U000022DA',
    +		"leq;":                             '\U00002264',
    +		"leqq;":                            '\U00002266',
    +		"leqslant;":                        '\U00002A7D',
    +		"les;":                             '\U00002A7D',
    +		"lescc;":                           '\U00002AA8',
    +		"lesdot;":                          '\U00002A7F',
    +		"lesdoto;":                         '\U00002A81',
    +		"lesdotor;":                        '\U00002A83',
    +		"lesges;":                          '\U00002A93',
    +		"lessapprox;":                      '\U00002A85',
    +		"lessdot;":                         '\U000022D6',
    +		"lesseqgtr;":                       '\U000022DA',
    +		"lesseqqgtr;":                      '\U00002A8B',
    +		"lessgtr;":                         '\U00002276',
    +		"lesssim;":                         '\U00002272',
    +		"lfisht;":                          '\U0000297C',
    +		"lfloor;":                          '\U0000230A',
    +		"lfr;":                             '\U0001D529',
    +		"lg;":                              '\U00002276',
    +		"lgE;":                             '\U00002A91',
    +		"lhard;":                           '\U000021BD',
    +		"lharu;":                           '\U000021BC',
    +		"lharul;":                          '\U0000296A',
    +		"lhblk;":                           '\U00002584',
    +		"ljcy;":                            '\U00000459',
    +		"ll;":                              '\U0000226A',
    +		"llarr;":                           '\U000021C7',
    +		"llcorner;":                        '\U0000231E',
    +		"llhard;":                          '\U0000296B',
    +		"lltri;":                           '\U000025FA',
    +		"lmidot;":                          '\U00000140',
    +		"lmoust;":                          '\U000023B0',
    +		"lmoustache;":                      '\U000023B0',
    +		"lnE;":                             '\U00002268',
    +		"lnap;":                            '\U00002A89',
    +		"lnapprox;":                        '\U00002A89',
    +		"lne;":                             '\U00002A87',
    +		"lneq;":                            '\U00002A87',
    +		"lneqq;":                           '\U00002268',
    +		"lnsim;":                           '\U000022E6',
    +		"loang;":                           '\U000027EC',
    +		"loarr;":                           '\U000021FD',
    +		"lobrk;":                           '\U000027E6',
    +		"longleftarrow;":                   '\U000027F5',
    +		"longleftrightarrow;":              '\U000027F7',
    +		"longmapsto;":                      '\U000027FC',
    +		"longrightarrow;":                  '\U000027F6',
    +		"looparrowleft;":                   '\U000021AB',
    +		"looparrowright;":                  '\U000021AC',
    +		"lopar;":                           '\U00002985',
    +		"lopf;":                            '\U0001D55D',
    +		"loplus;":                          '\U00002A2D',
    +		"lotimes;":                         '\U00002A34',
    +		"lowast;":                          '\U00002217',
    +		"lowbar;":                          '\U0000005F',
    +		"loz;":                             '\U000025CA',
    +		"lozenge;":                         '\U000025CA',
    +		"lozf;":                            '\U000029EB',
    +		"lpar;":                            '\U00000028',
    +		"lparlt;":                          '\U00002993',
    +		"lrarr;":                           '\U000021C6',
    +		"lrcorner;":                        '\U0000231F',
    +		"lrhar;":                           '\U000021CB',
    +		"lrhard;":                          '\U0000296D',
    +		"lrm;":                             '\U0000200E',
    +		"lrtri;":                           '\U000022BF',
    +		"lsaquo;":                          '\U00002039',
    +		"lscr;":                            '\U0001D4C1',
    +		"lsh;":                             '\U000021B0',
    +		"lsim;":                            '\U00002272',
    +		"lsime;":                           '\U00002A8D',
    +		"lsimg;":                           '\U00002A8F',
    +		"lsqb;":                            '\U0000005B',
    +		"lsquo;":                           '\U00002018',
    +		"lsquor;":                          '\U0000201A',
    +		"lstrok;":                          '\U00000142',
    +		"lt;":                              '\U0000003C',
    +		"ltcc;":                            '\U00002AA6',
    +		"ltcir;":                           '\U00002A79',
    +		"ltdot;":                           '\U000022D6',
    +		"lthree;":                          '\U000022CB',
    +		"ltimes;":                          '\U000022C9',
    +		"ltlarr;":                          '\U00002976',
    +		"ltquest;":                         '\U00002A7B',
    +		"ltrPar;":                          '\U00002996',
    +		"ltri;":                            '\U000025C3',
    +		"ltrie;":                           '\U000022B4',
    +		"ltrif;":                           '\U000025C2',
    +		"lurdshar;":                        '\U0000294A',
    +		"luruhar;":                         '\U00002966',
    +		"mDDot;":                           '\U0000223A',
    +		"macr;":                            '\U000000AF',
    +		"male;":                            '\U00002642',
    +		"malt;":                            '\U00002720',
    +		"maltese;":                         '\U00002720',
    +		"map;":                             '\U000021A6',
    +		"mapsto;":                          '\U000021A6',
    +		"mapstodown;":                      '\U000021A7',
    +		"mapstoleft;":                      '\U000021A4',
    +		"mapstoup;":                        '\U000021A5',
    +		"marker;":                          '\U000025AE',
    +		"mcomma;":                          '\U00002A29',
    +		"mcy;":                             '\U0000043C',
    +		"mdash;":                           '\U00002014',
    +		"measuredangle;":                   '\U00002221',
    +		"mfr;":                             '\U0001D52A',
    +		"mho;":                             '\U00002127',
    +		"micro;":                           '\U000000B5',
    +		"mid;":                             '\U00002223',
    +		"midast;":                          '\U0000002A',
    +		"midcir;":                          '\U00002AF0',
    +		"middot;":                          '\U000000B7',
    +		"minus;":                           '\U00002212',
    +		"minusb;":                          '\U0000229F',
    +		"minusd;":                          '\U00002238',
    +		"minusdu;":                         '\U00002A2A',
    +		"mlcp;":                            '\U00002ADB',
    +		"mldr;":                            '\U00002026',
    +		"mnplus;":                          '\U00002213',
    +		"models;":                          '\U000022A7',
    +		"mopf;":                            '\U0001D55E',
    +		"mp;":                              '\U00002213',
    +		"mscr;":                            '\U0001D4C2',
    +		"mstpos;":                          '\U0000223E',
    +		"mu;":                              '\U000003BC',
    +		"multimap;":                        '\U000022B8',
    +		"mumap;":                           '\U000022B8',
    +		"nLeftarrow;":                      '\U000021CD',
    +		"nLeftrightarrow;":                 '\U000021CE',
    +		"nRightarrow;":                     '\U000021CF',
    +		"nVDash;":                          '\U000022AF',
    +		"nVdash;":                          '\U000022AE',
    +		"nabla;":                           '\U00002207',
    +		"nacute;":                          '\U00000144',
    +		"nap;":                             '\U00002249',
    +		"napos;":                           '\U00000149',
    +		"napprox;":                         '\U00002249',
    +		"natur;":                           '\U0000266E',
    +		"natural;":                         '\U0000266E',
    +		"naturals;":                        '\U00002115',
    +		"nbsp;":                            '\U000000A0',
    +		"ncap;":                            '\U00002A43',
    +		"ncaron;":                          '\U00000148',
    +		"ncedil;":                          '\U00000146',
    +		"ncong;":                           '\U00002247',
    +		"ncup;":                            '\U00002A42',
    +		"ncy;":                             '\U0000043D',
    +		"ndash;":                           '\U00002013',
    +		"ne;":                              '\U00002260',
    +		"neArr;":                           '\U000021D7',
    +		"nearhk;":                          '\U00002924',
    +		"nearr;":                           '\U00002197',
    +		"nearrow;":                         '\U00002197',
    +		"nequiv;":                          '\U00002262',
    +		"nesear;":                          '\U00002928',
    +		"nexist;":                          '\U00002204',
    +		"nexists;":                         '\U00002204',
    +		"nfr;":                             '\U0001D52B',
    +		"nge;":                             '\U00002271',
    +		"ngeq;":                            '\U00002271',
    +		"ngsim;":                           '\U00002275',
    +		"ngt;":                             '\U0000226F',
    +		"ngtr;":                            '\U0000226F',
    +		"nhArr;":                           '\U000021CE',
    +		"nharr;":                           '\U000021AE',
    +		"nhpar;":                           '\U00002AF2',
    +		"ni;":                              '\U0000220B',
    +		"nis;":                             '\U000022FC',
    +		"nisd;":                            '\U000022FA',
    +		"niv;":                             '\U0000220B',
    +		"njcy;":                            '\U0000045A',
    +		"nlArr;":                           '\U000021CD',
    +		"nlarr;":                           '\U0000219A',
    +		"nldr;":                            '\U00002025',
    +		"nle;":                             '\U00002270',
    +		"nleftarrow;":                      '\U0000219A',
    +		"nleftrightarrow;":                 '\U000021AE',
    +		"nleq;":                            '\U00002270',
    +		"nless;":                           '\U0000226E',
    +		"nlsim;":                           '\U00002274',
    +		"nlt;":                             '\U0000226E',
    +		"nltri;":                           '\U000022EA',
    +		"nltrie;":                          '\U000022EC',
    +		"nmid;":                            '\U00002224',
    +		"nopf;":                            '\U0001D55F',
    +		"not;":                             '\U000000AC',
    +		"notin;":                           '\U00002209',
    +		"notinva;":                         '\U00002209',
    +		"notinvb;":                         '\U000022F7',
    +		"notinvc;":                         '\U000022F6',
    +		"notni;":                           '\U0000220C',
    +		"notniva;":                         '\U0000220C',
    +		"notnivb;":                         '\U000022FE',
    +		"notnivc;":                         '\U000022FD',
    +		"npar;":                            '\U00002226',
    +		"nparallel;":                       '\U00002226',
    +		"npolint;":                         '\U00002A14',
    +		"npr;":                             '\U00002280',
    +		"nprcue;":                          '\U000022E0',
    +		"nprec;":                           '\U00002280',
    +		"nrArr;":                           '\U000021CF',
    +		"nrarr;":                           '\U0000219B',
    +		"nrightarrow;":                     '\U0000219B',
    +		"nrtri;":                           '\U000022EB',
    +		"nrtrie;":                          '\U000022ED',
    +		"nsc;":                             '\U00002281',
    +		"nsccue;":                          '\U000022E1',
    +		"nscr;":                            '\U0001D4C3',
    +		"nshortmid;":                       '\U00002224',
    +		"nshortparallel;":                  '\U00002226',
    +		"nsim;":                            '\U00002241',
    +		"nsime;":                           '\U00002244',
    +		"nsimeq;":                          '\U00002244',
    +		"nsmid;":                           '\U00002224',
    +		"nspar;":                           '\U00002226',
    +		"nsqsube;":                         '\U000022E2',
    +		"nsqsupe;":                         '\U000022E3',
    +		"nsub;":                            '\U00002284',
    +		"nsube;":                           '\U00002288',
    +		"nsubseteq;":                       '\U00002288',
    +		"nsucc;":                           '\U00002281',
    +		"nsup;":                            '\U00002285',
    +		"nsupe;":                           '\U00002289',
    +		"nsupseteq;":                       '\U00002289',
    +		"ntgl;":                            '\U00002279',
    +		"ntilde;":                          '\U000000F1',
    +		"ntlg;":                            '\U00002278',
    +		"ntriangleleft;":                   '\U000022EA',
    +		"ntrianglelefteq;":                 '\U000022EC',
    +		"ntriangleright;":                  '\U000022EB',
    +		"ntrianglerighteq;":                '\U000022ED',
    +		"nu;":                              '\U000003BD',
    +		"num;":                             '\U00000023',
    +		"numero;":                          '\U00002116',
    +		"numsp;":                           '\U00002007',
    +		"nvDash;":                          '\U000022AD',
    +		"nvHarr;":                          '\U00002904',
    +		"nvdash;":                          '\U000022AC',
    +		"nvinfin;":                         '\U000029DE',
    +		"nvlArr;":                          '\U00002902',
    +		"nvrArr;":                          '\U00002903',
    +		"nwArr;":                           '\U000021D6',
    +		"nwarhk;":                          '\U00002923',
    +		"nwarr;":                           '\U00002196',
    +		"nwarrow;":                         '\U00002196',
    +		"nwnear;":                          '\U00002927',
    +		"oS;":                              '\U000024C8',
    +		"oacute;":                          '\U000000F3',
    +		"oast;":                            '\U0000229B',
    +		"ocir;":                            '\U0000229A',
    +		"ocirc;":                           '\U000000F4',
    +		"ocy;":                             '\U0000043E',
    +		"odash;":                           '\U0000229D',
    +		"odblac;":                          '\U00000151',
    +		"odiv;":                            '\U00002A38',
    +		"odot;":                            '\U00002299',
    +		"odsold;":                          '\U000029BC',
    +		"oelig;":                           '\U00000153',
    +		"ofcir;":                           '\U000029BF',
    +		"ofr;":                             '\U0001D52C',
    +		"ogon;":                            '\U000002DB',
    +		"ograve;":                          '\U000000F2',
    +		"ogt;":                             '\U000029C1',
    +		"ohbar;":                           '\U000029B5',
    +		"ohm;":                             '\U000003A9',
    +		"oint;":                            '\U0000222E',
    +		"olarr;":                           '\U000021BA',
    +		"olcir;":                           '\U000029BE',
    +		"olcross;":                         '\U000029BB',
    +		"oline;":                           '\U0000203E',
    +		"olt;":                             '\U000029C0',
    +		"omacr;":                           '\U0000014D',
    +		"omega;":                           '\U000003C9',
    +		"omicron;":                         '\U000003BF',
    +		"omid;":                            '\U000029B6',
    +		"ominus;":                          '\U00002296',
    +		"oopf;":                            '\U0001D560',
    +		"opar;":                            '\U000029B7',
    +		"operp;":                           '\U000029B9',
    +		"oplus;":                           '\U00002295',
    +		"or;":                              '\U00002228',
    +		"orarr;":                           '\U000021BB',
    +		"ord;":                             '\U00002A5D',
    +		"order;":                           '\U00002134',
    +		"orderof;":                         '\U00002134',
    +		"ordf;":                            '\U000000AA',
    +		"ordm;":                            '\U000000BA',
    +		"origof;":                          '\U000022B6',
    +		"oror;":                            '\U00002A56',
    +		"orslope;":                         '\U00002A57',
    +		"orv;":                             '\U00002A5B',
    +		"oscr;":                            '\U00002134',
    +		"oslash;":                          '\U000000F8',
    +		"osol;":                            '\U00002298',
    +		"otilde;":                          '\U000000F5',
    +		"otimes;":                          '\U00002297',
    +		"otimesas;":                        '\U00002A36',
    +		"ouml;":                            '\U000000F6',
    +		"ovbar;":                           '\U0000233D',
    +		"par;":                             '\U00002225',
    +		"para;":                            '\U000000B6',
    +		"parallel;":                        '\U00002225',
    +		"parsim;":                          '\U00002AF3',
    +		"parsl;":                           '\U00002AFD',
    +		"part;":                            '\U00002202',
    +		"pcy;":                             '\U0000043F',
    +		"percnt;":                          '\U00000025',
    +		"period;":                          '\U0000002E',
    +		"permil;":                          '\U00002030',
    +		"perp;":                            '\U000022A5',
    +		"pertenk;":                         '\U00002031',
    +		"pfr;":                             '\U0001D52D',
    +		"phi;":                             '\U000003C6',
    +		"phiv;":                            '\U000003D5',
    +		"phmmat;":                          '\U00002133',
    +		"phone;":                           '\U0000260E',
    +		"pi;":                              '\U000003C0',
    +		"pitchfork;":                       '\U000022D4',
    +		"piv;":                             '\U000003D6',
    +		"planck;":                          '\U0000210F',
    +		"planckh;":                         '\U0000210E',
    +		"plankv;":                          '\U0000210F',
    +		"plus;":                            '\U0000002B',
    +		"plusacir;":                        '\U00002A23',
    +		"plusb;":                           '\U0000229E',
    +		"pluscir;":                         '\U00002A22',
    +		"plusdo;":                          '\U00002214',
    +		"plusdu;":                          '\U00002A25',
    +		"pluse;":                           '\U00002A72',
    +		"plusmn;":                          '\U000000B1',
    +		"plussim;":                         '\U00002A26',
    +		"plustwo;":                         '\U00002A27',
    +		"pm;":                              '\U000000B1',
    +		"pointint;":                        '\U00002A15',
    +		"popf;":                            '\U0001D561',
    +		"pound;":                           '\U000000A3',
    +		"pr;":                              '\U0000227A',
    +		"prE;":                             '\U00002AB3',
    +		"prap;":                            '\U00002AB7',
    +		"prcue;":                           '\U0000227C',
    +		"pre;":                             '\U00002AAF',
    +		"prec;":                            '\U0000227A',
    +		"precapprox;":                      '\U00002AB7',
    +		"preccurlyeq;":                     '\U0000227C',
    +		"preceq;":                          '\U00002AAF',
    +		"precnapprox;":                     '\U00002AB9',
    +		"precneqq;":                        '\U00002AB5',
    +		"precnsim;":                        '\U000022E8',
    +		"precsim;":                         '\U0000227E',
    +		"prime;":                           '\U00002032',
    +		"primes;":                          '\U00002119',
    +		"prnE;":                            '\U00002AB5',
    +		"prnap;":                           '\U00002AB9',
    +		"prnsim;":                          '\U000022E8',
    +		"prod;":                            '\U0000220F',
    +		"profalar;":                        '\U0000232E',
    +		"profline;":                        '\U00002312',
    +		"profsurf;":                        '\U00002313',
    +		"prop;":                            '\U0000221D',
    +		"propto;":                          '\U0000221D',
    +		"prsim;":                           '\U0000227E',
    +		"prurel;":                          '\U000022B0',
    +		"pscr;":                            '\U0001D4C5',
    +		"psi;":                             '\U000003C8',
    +		"puncsp;":                          '\U00002008',
    +		"qfr;":                             '\U0001D52E',
    +		"qint;":                            '\U00002A0C',
    +		"qopf;":                            '\U0001D562',
    +		"qprime;":                          '\U00002057',
    +		"qscr;":                            '\U0001D4C6',
    +		"quaternions;":                     '\U0000210D',
    +		"quatint;":                         '\U00002A16',
    +		"quest;":                           '\U0000003F',
    +		"questeq;":                         '\U0000225F',
    +		"quot;":                            '\U00000022',
    +		"rAarr;":                           '\U000021DB',
    +		"rArr;":                            '\U000021D2',
    +		"rAtail;":                          '\U0000291C',
    +		"rBarr;":                           '\U0000290F',
    +		"rHar;":                            '\U00002964',
    +		"racute;":                          '\U00000155',
    +		"radic;":                           '\U0000221A',
    +		"raemptyv;":                        '\U000029B3',
    +		"rang;":                            '\U000027E9',
    +		"rangd;":                           '\U00002992',
    +		"range;":                           '\U000029A5',
    +		"rangle;":                          '\U000027E9',
    +		"raquo;":                           '\U000000BB',
    +		"rarr;":                            '\U00002192',
    +		"rarrap;":                          '\U00002975',
    +		"rarrb;":                           '\U000021E5',
    +		"rarrbfs;":                         '\U00002920',
    +		"rarrc;":                           '\U00002933',
    +		"rarrfs;":                          '\U0000291E',
    +		"rarrhk;":                          '\U000021AA',
    +		"rarrlp;":                          '\U000021AC',
    +		"rarrpl;":                          '\U00002945',
    +		"rarrsim;":                         '\U00002974',
    +		"rarrtl;":                          '\U000021A3',
    +		"rarrw;":                           '\U0000219D',
    +		"ratail;":                          '\U0000291A',
    +		"ratio;":                           '\U00002236',
    +		"rationals;":                       '\U0000211A',
    +		"rbarr;":                           '\U0000290D',
    +		"rbbrk;":                           '\U00002773',
    +		"rbrace;":                          '\U0000007D',
    +		"rbrack;":                          '\U0000005D',
    +		"rbrke;":                           '\U0000298C',
    +		"rbrksld;":                         '\U0000298E',
    +		"rbrkslu;":                         '\U00002990',
    +		"rcaron;":                          '\U00000159',
    +		"rcedil;":                          '\U00000157',
    +		"rceil;":                           '\U00002309',
    +		"rcub;":                            '\U0000007D',
    +		"rcy;":                             '\U00000440',
    +		"rdca;":                            '\U00002937',
    +		"rdldhar;":                         '\U00002969',
    +		"rdquo;":                           '\U0000201D',
    +		"rdquor;":                          '\U0000201D',
    +		"rdsh;":                            '\U000021B3',
    +		"real;":                            '\U0000211C',
    +		"realine;":                         '\U0000211B',
    +		"realpart;":                        '\U0000211C',
    +		"reals;":                           '\U0000211D',
    +		"rect;":                            '\U000025AD',
    +		"reg;":                             '\U000000AE',
    +		"rfisht;":                          '\U0000297D',
    +		"rfloor;":                          '\U0000230B',
    +		"rfr;":                             '\U0001D52F',
    +		"rhard;":                           '\U000021C1',
    +		"rharu;":                           '\U000021C0',
    +		"rharul;":                          '\U0000296C',
    +		"rho;":                             '\U000003C1',
    +		"rhov;":                            '\U000003F1',
    +		"rightarrow;":                      '\U00002192',
    +		"rightarrowtail;":                  '\U000021A3',
    +		"rightharpoondown;":                '\U000021C1',
    +		"rightharpoonup;":                  '\U000021C0',
    +		"rightleftarrows;":                 '\U000021C4',
    +		"rightleftharpoons;":               '\U000021CC',
    +		"rightrightarrows;":                '\U000021C9',
    +		"rightsquigarrow;":                 '\U0000219D',
    +		"rightthreetimes;":                 '\U000022CC',
    +		"ring;":                            '\U000002DA',
    +		"risingdotseq;":                    '\U00002253',
    +		"rlarr;":                           '\U000021C4',
    +		"rlhar;":                           '\U000021CC',
    +		"rlm;":                             '\U0000200F',
    +		"rmoust;":                          '\U000023B1',
    +		"rmoustache;":                      '\U000023B1',
    +		"rnmid;":                           '\U00002AEE',
    +		"roang;":                           '\U000027ED',
    +		"roarr;":                           '\U000021FE',
    +		"robrk;":                           '\U000027E7',
    +		"ropar;":                           '\U00002986',
    +		"ropf;":                            '\U0001D563',
    +		"roplus;":                          '\U00002A2E',
    +		"rotimes;":                         '\U00002A35',
    +		"rpar;":                            '\U00000029',
    +		"rpargt;":                          '\U00002994',
    +		"rppolint;":                        '\U00002A12',
    +		"rrarr;":                           '\U000021C9',
    +		"rsaquo;":                          '\U0000203A',
    +		"rscr;":                            '\U0001D4C7',
    +		"rsh;":                             '\U000021B1',
    +		"rsqb;":                            '\U0000005D',
    +		"rsquo;":                           '\U00002019',
    +		"rsquor;":                          '\U00002019',
    +		"rthree;":                          '\U000022CC',
    +		"rtimes;":                          '\U000022CA',
    +		"rtri;":                            '\U000025B9',
    +		"rtrie;":                           '\U000022B5',
    +		"rtrif;":                           '\U000025B8',
    +		"rtriltri;":                        '\U000029CE',
    +		"ruluhar;":                         '\U00002968',
    +		"rx;":                              '\U0000211E',
    +		"sacute;":                          '\U0000015B',
    +		"sbquo;":                           '\U0000201A',
    +		"sc;":                              '\U0000227B',
    +		"scE;":                             '\U00002AB4',
    +		"scap;":                            '\U00002AB8',
    +		"scaron;":                          '\U00000161',
    +		"sccue;":                           '\U0000227D',
    +		"sce;":                             '\U00002AB0',
    +		"scedil;":                          '\U0000015F',
    +		"scirc;":                           '\U0000015D',
    +		"scnE;":                            '\U00002AB6',
    +		"scnap;":                           '\U00002ABA',
    +		"scnsim;":                          '\U000022E9',
    +		"scpolint;":                        '\U00002A13',
    +		"scsim;":                           '\U0000227F',
    +		"scy;":                             '\U00000441',
    +		"sdot;":                            '\U000022C5',
    +		"sdotb;":                           '\U000022A1',
    +		"sdote;":                           '\U00002A66',
    +		"seArr;":                           '\U000021D8',
    +		"searhk;":                          '\U00002925',
    +		"searr;":                           '\U00002198',
    +		"searrow;":                         '\U00002198',
    +		"sect;":                            '\U000000A7',
    +		"semi;":                            '\U0000003B',
    +		"seswar;":                          '\U00002929',
    +		"setminus;":                        '\U00002216',
    +		"setmn;":                           '\U00002216',
    +		"sext;":                            '\U00002736',
    +		"sfr;":                             '\U0001D530',
    +		"sfrown;":                          '\U00002322',
    +		"sharp;":                           '\U0000266F',
    +		"shchcy;":                          '\U00000449',
    +		"shcy;":                            '\U00000448',
    +		"shortmid;":                        '\U00002223',
    +		"shortparallel;":                   '\U00002225',
    +		"shy;":                             '\U000000AD',
    +		"sigma;":                           '\U000003C3',
    +		"sigmaf;":                          '\U000003C2',
    +		"sigmav;":                          '\U000003C2',
    +		"sim;":                             '\U0000223C',
    +		"simdot;":                          '\U00002A6A',
    +		"sime;":                            '\U00002243',
    +		"simeq;":                           '\U00002243',
    +		"simg;":                            '\U00002A9E',
    +		"simgE;":                           '\U00002AA0',
    +		"siml;":                            '\U00002A9D',
    +		"simlE;":                           '\U00002A9F',
    +		"simne;":                           '\U00002246',
    +		"simplus;":                         '\U00002A24',
    +		"simrarr;":                         '\U00002972',
    +		"slarr;":                           '\U00002190',
    +		"smallsetminus;":                   '\U00002216',
    +		"smashp;":                          '\U00002A33',
    +		"smeparsl;":                        '\U000029E4',
    +		"smid;":                            '\U00002223',
    +		"smile;":                           '\U00002323',
    +		"smt;":                             '\U00002AAA',
    +		"smte;":                            '\U00002AAC',
    +		"softcy;":                          '\U0000044C',
    +		"sol;":                             '\U0000002F',
    +		"solb;":                            '\U000029C4',
    +		"solbar;":                          '\U0000233F',
    +		"sopf;":                            '\U0001D564',
    +		"spades;":                          '\U00002660',
    +		"spadesuit;":                       '\U00002660',
    +		"spar;":                            '\U00002225',
    +		"sqcap;":                           '\U00002293',
    +		"sqcup;":                           '\U00002294',
    +		"sqsub;":                           '\U0000228F',
    +		"sqsube;":                          '\U00002291',
    +		"sqsubset;":                        '\U0000228F',
    +		"sqsubseteq;":                      '\U00002291',
    +		"sqsup;":                           '\U00002290',
    +		"sqsupe;":                          '\U00002292',
    +		"sqsupset;":                        '\U00002290',
    +		"sqsupseteq;":                      '\U00002292',
    +		"squ;":                             '\U000025A1',
    +		"square;":                          '\U000025A1',
    +		"squarf;":                          '\U000025AA',
    +		"squf;":                            '\U000025AA',
    +		"srarr;":                           '\U00002192',
    +		"sscr;":                            '\U0001D4C8',
    +		"ssetmn;":                          '\U00002216',
    +		"ssmile;":                          '\U00002323',
    +		"sstarf;":                          '\U000022C6',
    +		"star;":                            '\U00002606',
    +		"starf;":                           '\U00002605',
    +		"straightepsilon;":                 '\U000003F5',
    +		"straightphi;":                     '\U000003D5',
    +		"strns;":                           '\U000000AF',
    +		"sub;":                             '\U00002282',
    +		"subE;":                            '\U00002AC5',
    +		"subdot;":                          '\U00002ABD',
    +		"sube;":                            '\U00002286',
    +		"subedot;":                         '\U00002AC3',
    +		"submult;":                         '\U00002AC1',
    +		"subnE;":                           '\U00002ACB',
    +		"subne;":                           '\U0000228A',
    +		"subplus;":                         '\U00002ABF',
    +		"subrarr;":                         '\U00002979',
    +		"subset;":                          '\U00002282',
    +		"subseteq;":                        '\U00002286',
    +		"subseteqq;":                       '\U00002AC5',
    +		"subsetneq;":                       '\U0000228A',
    +		"subsetneqq;":                      '\U00002ACB',
    +		"subsim;":                          '\U00002AC7',
    +		"subsub;":                          '\U00002AD5',
    +		"subsup;":                          '\U00002AD3',
    +		"succ;":                            '\U0000227B',
    +		"succapprox;":                      '\U00002AB8',
    +		"succcurlyeq;":                     '\U0000227D',
    +		"succeq;":                          '\U00002AB0',
    +		"succnapprox;":                     '\U00002ABA',
    +		"succneqq;":                        '\U00002AB6',
    +		"succnsim;":                        '\U000022E9',
    +		"succsim;":                         '\U0000227F',
    +		"sum;":                             '\U00002211',
    +		"sung;":                            '\U0000266A',
    +		"sup;":                             '\U00002283',
    +		"sup1;":                            '\U000000B9',
    +		"sup2;":                            '\U000000B2',
    +		"sup3;":                            '\U000000B3',
    +		"supE;":                            '\U00002AC6',
    +		"supdot;":                          '\U00002ABE',
    +		"supdsub;":                         '\U00002AD8',
    +		"supe;":                            '\U00002287',
    +		"supedot;":                         '\U00002AC4',
    +		"suphsol;":                         '\U000027C9',
    +		"suphsub;":                         '\U00002AD7',
    +		"suplarr;":                         '\U0000297B',
    +		"supmult;":                         '\U00002AC2',
    +		"supnE;":                           '\U00002ACC',
    +		"supne;":                           '\U0000228B',
    +		"supplus;":                         '\U00002AC0',
    +		"supset;":                          '\U00002283',
    +		"supseteq;":                        '\U00002287',
    +		"supseteqq;":                       '\U00002AC6',
    +		"supsetneq;":                       '\U0000228B',
    +		"supsetneqq;":                      '\U00002ACC',
    +		"supsim;":                          '\U00002AC8',
    +		"supsub;":                          '\U00002AD4',
    +		"supsup;":                          '\U00002AD6',
    +		"swArr;":                           '\U000021D9',
    +		"swarhk;":                          '\U00002926',
    +		"swarr;":                           '\U00002199',
    +		"swarrow;":                         '\U00002199',
    +		"swnwar;":                          '\U0000292A',
    +		"szlig;":                           '\U000000DF',
    +		"target;":                          '\U00002316',
    +		"tau;":                             '\U000003C4',
    +		"tbrk;":                            '\U000023B4',
    +		"tcaron;":                          '\U00000165',
    +		"tcedil;":                          '\U00000163',
    +		"tcy;":                             '\U00000442',
    +		"tdot;":                            '\U000020DB',
    +		"telrec;":                          '\U00002315',
    +		"tfr;":                             '\U0001D531',
    +		"there4;":                          '\U00002234',
    +		"therefore;":                       '\U00002234',
    +		"theta;":                           '\U000003B8',
    +		"thetasym;":                        '\U000003D1',
    +		"thetav;":                          '\U000003D1',
    +		"thickapprox;":                     '\U00002248',
    +		"thicksim;":                        '\U0000223C',
    +		"thinsp;":                          '\U00002009',
    +		"thkap;":                           '\U00002248',
    +		"thksim;":                          '\U0000223C',
    +		"thorn;":                           '\U000000FE',
    +		"tilde;":                           '\U000002DC',
    +		"times;":                           '\U000000D7',
    +		"timesb;":                          '\U000022A0',
    +		"timesbar;":                        '\U00002A31',
    +		"timesd;":                          '\U00002A30',
    +		"tint;":                            '\U0000222D',
    +		"toea;":                            '\U00002928',
    +		"top;":                             '\U000022A4',
    +		"topbot;":                          '\U00002336',
    +		"topcir;":                          '\U00002AF1',
    +		"topf;":                            '\U0001D565',
    +		"topfork;":                         '\U00002ADA',
    +		"tosa;":                            '\U00002929',
    +		"tprime;":                          '\U00002034',
    +		"trade;":                           '\U00002122',
    +		"triangle;":                        '\U000025B5',
    +		"triangledown;":                    '\U000025BF',
    +		"triangleleft;":                    '\U000025C3',
    +		"trianglelefteq;":                  '\U000022B4',
    +		"triangleq;":                       '\U0000225C',
    +		"triangleright;":                   '\U000025B9',
    +		"trianglerighteq;":                 '\U000022B5',
    +		"tridot;":                          '\U000025EC',
    +		"trie;":                            '\U0000225C',
    +		"triminus;":                        '\U00002A3A',
    +		"triplus;":                         '\U00002A39',
    +		"trisb;":                           '\U000029CD',
    +		"tritime;":                         '\U00002A3B',
    +		"trpezium;":                        '\U000023E2',
    +		"tscr;":                            '\U0001D4C9',
    +		"tscy;":                            '\U00000446',
    +		"tshcy;":                           '\U0000045B',
    +		"tstrok;":                          '\U00000167',
    +		"twixt;":                           '\U0000226C',
    +		"twoheadleftarrow;":                '\U0000219E',
    +		"twoheadrightarrow;":               '\U000021A0',
    +		"uArr;":                            '\U000021D1',
    +		"uHar;":                            '\U00002963',
    +		"uacute;":                          '\U000000FA',
    +		"uarr;":                            '\U00002191',
    +		"ubrcy;":                           '\U0000045E',
    +		"ubreve;":                          '\U0000016D',
    +		"ucirc;":                           '\U000000FB',
    +		"ucy;":                             '\U00000443',
    +		"udarr;":                           '\U000021C5',
    +		"udblac;":                          '\U00000171',
    +		"udhar;":                           '\U0000296E',
    +		"ufisht;":                          '\U0000297E',
    +		"ufr;":                             '\U0001D532',
    +		"ugrave;":                          '\U000000F9',
    +		"uharl;":                           '\U000021BF',
    +		"uharr;":                           '\U000021BE',
    +		"uhblk;":                           '\U00002580',
    +		"ulcorn;":                          '\U0000231C',
    +		"ulcorner;":                        '\U0000231C',
    +		"ulcrop;":                          '\U0000230F',
    +		"ultri;":                           '\U000025F8',
    +		"umacr;":                           '\U0000016B',
    +		"uml;":                             '\U000000A8',
    +		"uogon;":                           '\U00000173',
    +		"uopf;":                            '\U0001D566',
    +		"uparrow;":                         '\U00002191',
    +		"updownarrow;":                     '\U00002195',
    +		"upharpoonleft;":                   '\U000021BF',
    +		"upharpoonright;":                  '\U000021BE',
    +		"uplus;":                           '\U0000228E',
    +		"upsi;":                            '\U000003C5',
    +		"upsih;":                           '\U000003D2',
    +		"upsilon;":                         '\U000003C5',
    +		"upuparrows;":                      '\U000021C8',
    +		"urcorn;":                          '\U0000231D',
    +		"urcorner;":                        '\U0000231D',
    +		"urcrop;":                          '\U0000230E',
    +		"uring;":                           '\U0000016F',
    +		"urtri;":                           '\U000025F9',
    +		"uscr;":                            '\U0001D4CA',
    +		"utdot;":                           '\U000022F0',
    +		"utilde;":                          '\U00000169',
    +		"utri;":                            '\U000025B5',
    +		"utrif;":                           '\U000025B4',
    +		"uuarr;":                           '\U000021C8',
    +		"uuml;":                            '\U000000FC',
    +		"uwangle;":                         '\U000029A7',
    +		"vArr;":                            '\U000021D5',
    +		"vBar;":                            '\U00002AE8',
    +		"vBarv;":                           '\U00002AE9',
    +		"vDash;":                           '\U000022A8',
    +		"vangrt;":                          '\U0000299C',
    +		"varepsilon;":                      '\U000003F5',
    +		"varkappa;":                        '\U000003F0',
    +		"varnothing;":                      '\U00002205',
    +		"varphi;":                          '\U000003D5',
    +		"varpi;":                           '\U000003D6',
    +		"varpropto;":                       '\U0000221D',
    +		"varr;":                            '\U00002195',
    +		"varrho;":                          '\U000003F1',
    +		"varsigma;":                        '\U000003C2',
    +		"vartheta;":                        '\U000003D1',
    +		"vartriangleleft;":                 '\U000022B2',
    +		"vartriangleright;":                '\U000022B3',
    +		"vcy;":                             '\U00000432',
    +		"vdash;":                           '\U000022A2',
    +		"vee;":                             '\U00002228',
    +		"veebar;":                          '\U000022BB',
    +		"veeeq;":                           '\U0000225A',
    +		"vellip;":                          '\U000022EE',
    +		"verbar;":                          '\U0000007C',
    +		"vert;":                            '\U0000007C',
    +		"vfr;":                             '\U0001D533',
    +		"vltri;":                           '\U000022B2',
    +		"vopf;":                            '\U0001D567',
    +		"vprop;":                           '\U0000221D',
    +		"vrtri;":                           '\U000022B3',
    +		"vscr;":                            '\U0001D4CB',
    +		"vzigzag;":                         '\U0000299A',
    +		"wcirc;":                           '\U00000175',
    +		"wedbar;":                          '\U00002A5F',
    +		"wedge;":                           '\U00002227',
    +		"wedgeq;":                          '\U00002259',
    +		"weierp;":                          '\U00002118',
    +		"wfr;":                             '\U0001D534',
    +		"wopf;":                            '\U0001D568',
    +		"wp;":                              '\U00002118',
    +		"wr;":                              '\U00002240',
    +		"wreath;":                          '\U00002240',
    +		"wscr;":                            '\U0001D4CC',
    +		"xcap;":                            '\U000022C2',
    +		"xcirc;":                           '\U000025EF',
    +		"xcup;":                            '\U000022C3',
    +		"xdtri;":                           '\U000025BD',
    +		"xfr;":                             '\U0001D535',
    +		"xhArr;":                           '\U000027FA',
    +		"xharr;":                           '\U000027F7',
    +		"xi;":                              '\U000003BE',
    +		"xlArr;":                           '\U000027F8',
    +		"xlarr;":                           '\U000027F5',
    +		"xmap;":                            '\U000027FC',
    +		"xnis;":                            '\U000022FB',
    +		"xodot;":                           '\U00002A00',
    +		"xopf;":                            '\U0001D569',
    +		"xoplus;":                          '\U00002A01',
    +		"xotime;":                          '\U00002A02',
    +		"xrArr;":                           '\U000027F9',
    +		"xrarr;":                           '\U000027F6',
    +		"xscr;":                            '\U0001D4CD',
    +		"xsqcup;":                          '\U00002A06',
    +		"xuplus;":                          '\U00002A04',
    +		"xutri;":                           '\U000025B3',
    +		"xvee;":                            '\U000022C1',
    +		"xwedge;":                          '\U000022C0',
    +		"yacute;":                          '\U000000FD',
    +		"yacy;":                            '\U0000044F',
    +		"ycirc;":                           '\U00000177',
    +		"ycy;":                             '\U0000044B',
    +		"yen;":                             '\U000000A5',
    +		"yfr;":                             '\U0001D536',
    +		"yicy;":                            '\U00000457',
    +		"yopf;":                            '\U0001D56A',
    +		"yscr;":                            '\U0001D4CE',
    +		"yucy;":                            '\U0000044E',
    +		"yuml;":                            '\U000000FF',
    +		"zacute;":                          '\U0000017A',
    +		"zcaron;":                          '\U0000017E',
    +		"zcy;":                             '\U00000437',
    +		"zdot;":                            '\U0000017C',
    +		"zeetrf;":                          '\U00002128',
    +		"zeta;":                            '\U000003B6',
    +		"zfr;":                             '\U0001D537',
    +		"zhcy;":                            '\U00000436',
    +		"zigrarr;":                         '\U000021DD',
    +		"zopf;":                            '\U0001D56B',
    +		"zscr;":                            '\U0001D4CF',
    +		"zwj;":                             '\U0000200D',
    +		"zwnj;":                            '\U0000200C',
    +		"AElig":                            '\U000000C6',
    +		"AMP":                              '\U00000026',
    +		"Aacute":                           '\U000000C1',
    +		"Acirc":                            '\U000000C2',
    +		"Agrave":                           '\U000000C0',
    +		"Aring":                            '\U000000C5',
    +		"Atilde":                           '\U000000C3',
    +		"Auml":                             '\U000000C4',
    +		"COPY":                             '\U000000A9',
    +		"Ccedil":                           '\U000000C7',
    +		"ETH":                              '\U000000D0',
    +		"Eacute":                           '\U000000C9',
    +		"Ecirc":                            '\U000000CA',
    +		"Egrave":                           '\U000000C8',
    +		"Euml":                             '\U000000CB',
    +		"GT":                               '\U0000003E',
    +		"Iacute":                           '\U000000CD',
    +		"Icirc":                            '\U000000CE',
    +		"Igrave":                           '\U000000CC',
    +		"Iuml":                             '\U000000CF',
    +		"LT":                               '\U0000003C',
    +		"Ntilde":                           '\U000000D1',
    +		"Oacute":                           '\U000000D3',
    +		"Ocirc":                            '\U000000D4',
    +		"Ograve":                           '\U000000D2',
    +		"Oslash":                           '\U000000D8',
    +		"Otilde":                           '\U000000D5',
    +		"Ouml":                             '\U000000D6',
    +		"QUOT":                             '\U00000022',
    +		"REG":                              '\U000000AE',
    +		"THORN":                            '\U000000DE',
    +		"Uacute":                           '\U000000DA',
    +		"Ucirc":                            '\U000000DB',
    +		"Ugrave":                           '\U000000D9',
    +		"Uuml":                             '\U000000DC',
    +		"Yacute":                           '\U000000DD',
    +		"aacute":                           '\U000000E1',
    +		"acirc":                            '\U000000E2',
    +		"acute":                            '\U000000B4',
    +		"aelig":                            '\U000000E6',
    +		"agrave":                           '\U000000E0',
    +		"amp":                              '\U00000026',
    +		"aring":                            '\U000000E5',
    +		"atilde":                           '\U000000E3',
    +		"auml":                             '\U000000E4',
    +		"brvbar":                           '\U000000A6',
    +		"ccedil":                           '\U000000E7',
    +		"cedil":                            '\U000000B8',
    +		"cent":                             '\U000000A2',
    +		"copy":                             '\U000000A9',
    +		"curren":                           '\U000000A4',
    +		"deg":                              '\U000000B0',
    +		"divide":                           '\U000000F7',
    +		"eacute":                           '\U000000E9',
    +		"ecirc":                            '\U000000EA',
    +		"egrave":                           '\U000000E8',
    +		"eth":                              '\U000000F0',
    +		"euml":                             '\U000000EB',
    +		"frac12":                           '\U000000BD',
    +		"frac14":                           '\U000000BC',
    +		"frac34":                           '\U000000BE',
    +		"gt":                               '\U0000003E',
    +		"iacute":                           '\U000000ED',
    +		"icirc":                            '\U000000EE',
    +		"iexcl":                            '\U000000A1',
    +		"igrave":                           '\U000000EC',
    +		"iquest":                           '\U000000BF',
    +		"iuml":                             '\U000000EF',
    +		"laquo":                            '\U000000AB',
    +		"lt":                               '\U0000003C',
    +		"macr":                             '\U000000AF',
    +		"micro":                            '\U000000B5',
    +		"middot":                           '\U000000B7',
    +		"nbsp":                             '\U000000A0',
    +		"not":                              '\U000000AC',
    +		"ntilde":                           '\U000000F1',
    +		"oacute":                           '\U000000F3',
    +		"ocirc":                            '\U000000F4',
    +		"ograve":                           '\U000000F2',
    +		"ordf":                             '\U000000AA',
    +		"ordm":                             '\U000000BA',
    +		"oslash":                           '\U000000F8',
    +		"otilde":                           '\U000000F5',
    +		"ouml":                             '\U000000F6',
    +		"para":                             '\U000000B6',
    +		"plusmn":                           '\U000000B1',
    +		"pound":                            '\U000000A3',
    +		"quot":                             '\U00000022',
    +		"raquo":                            '\U000000BB',
    +		"reg":                              '\U000000AE',
    +		"sect":                             '\U000000A7',
    +		"shy":                              '\U000000AD',
    +		"sup1":                             '\U000000B9',
    +		"sup2":                             '\U000000B2',
    +		"sup3":                             '\U000000B3',
    +		"szlig":                            '\U000000DF',
    +		"thorn":                            '\U000000FE',
    +		"times":                            '\U000000D7',
    +		"uacute":                           '\U000000FA',
    +		"ucirc":                            '\U000000FB',
    +		"ugrave":                           '\U000000F9',
    +		"uml":                              '\U000000A8',
    +		"uuml":                             '\U000000FC',
    +		"yacute":                           '\U000000FD',
    +		"yen":                              '\U000000A5',
    +		"yuml":                             '\U000000FF',
    +	}
    +
    +	entity2 = map[string][2]rune{
    +		// TODO(nigeltao): Handle replacements that are wider than their names.
    +		// "nLt;":                     {'\u226A', '\u20D2'},
    +		// "nGt;":                     {'\u226B', '\u20D2'},
    +		"NotEqualTilde;":           {'\u2242', '\u0338'},
    +		"NotGreaterFullEqual;":     {'\u2267', '\u0338'},
    +		"NotGreaterGreater;":       {'\u226B', '\u0338'},
    +		"NotGreaterSlantEqual;":    {'\u2A7E', '\u0338'},
    +		"NotHumpDownHump;":         {'\u224E', '\u0338'},
    +		"NotHumpEqual;":            {'\u224F', '\u0338'},
    +		"NotLeftTriangleBar;":      {'\u29CF', '\u0338'},
    +		"NotLessLess;":             {'\u226A', '\u0338'},
    +		"NotLessSlantEqual;":       {'\u2A7D', '\u0338'},
    +		"NotNestedGreaterGreater;": {'\u2AA2', '\u0338'},
    +		"NotNestedLessLess;":       {'\u2AA1', '\u0338'},
    +		"NotPrecedesEqual;":        {'\u2AAF', '\u0338'},
    +		"NotRightTriangleBar;":     {'\u29D0', '\u0338'},
    +		"NotSquareSubset;":         {'\u228F', '\u0338'},
    +		"NotSquareSuperset;":       {'\u2290', '\u0338'},
    +		"NotSubset;":               {'\u2282', '\u20D2'},
    +		"NotSucceedsEqual;":        {'\u2AB0', '\u0338'},
    +		"NotSucceedsTilde;":        {'\u227F', '\u0338'},
    +		"NotSuperset;":             {'\u2283', '\u20D2'},
    +		"ThickSpace;":              {'\u205F', '\u200A'},
    +		"acE;":                     {'\u223E', '\u0333'},
    +		"bne;":                     {'\u003D', '\u20E5'},
    +		"bnequiv;":                 {'\u2261', '\u20E5'},
    +		"caps;":                    {'\u2229', '\uFE00'},
    +		"cups;":                    {'\u222A', '\uFE00'},
    +		"fjlig;":                   {'\u0066', '\u006A'},
    +		"gesl;":                    {'\u22DB', '\uFE00'},
    +		"gvertneqq;":               {'\u2269', '\uFE00'},
    +		"gvnE;":                    {'\u2269', '\uFE00'},
    +		"lates;":                   {'\u2AAD', '\uFE00'},
    +		"lesg;":                    {'\u22DA', '\uFE00'},
    +		"lvertneqq;":               {'\u2268', '\uFE00'},
    +		"lvnE;":                    {'\u2268', '\uFE00'},
    +		"nGg;":                     {'\u22D9', '\u0338'},
    +		"nGtv;":                    {'\u226B', '\u0338'},
    +		"nLl;":                     {'\u22D8', '\u0338'},
    +		"nLtv;":                    {'\u226A', '\u0338'},
    +		"nang;":                    {'\u2220', '\u20D2'},
    +		"napE;":                    {'\u2A70', '\u0338'},
    +		"napid;":                   {'\u224B', '\u0338'},
    +		"nbump;":                   {'\u224E', '\u0338'},
    +		"nbumpe;":                  {'\u224F', '\u0338'},
    +		"ncongdot;":                {'\u2A6D', '\u0338'},
    +		"nedot;":                   {'\u2250', '\u0338'},
    +		"nesim;":                   {'\u2242', '\u0338'},
    +		"ngE;":                     {'\u2267', '\u0338'},
    +		"ngeqq;":                   {'\u2267', '\u0338'},
    +		"ngeqslant;":               {'\u2A7E', '\u0338'},
    +		"nges;":                    {'\u2A7E', '\u0338'},
    +		"nlE;":                     {'\u2266', '\u0338'},
    +		"nleqq;":                   {'\u2266', '\u0338'},
    +		"nleqslant;":               {'\u2A7D', '\u0338'},
    +		"nles;":                    {'\u2A7D', '\u0338'},
    +		"notinE;":                  {'\u22F9', '\u0338'},
    +		"notindot;":                {'\u22F5', '\u0338'},
    +		"nparsl;":                  {'\u2AFD', '\u20E5'},
    +		"npart;":                   {'\u2202', '\u0338'},
    +		"npre;":                    {'\u2AAF', '\u0338'},
    +		"npreceq;":                 {'\u2AAF', '\u0338'},
    +		"nrarrc;":                  {'\u2933', '\u0338'},
    +		"nrarrw;":                  {'\u219D', '\u0338'},
    +		"nsce;":                    {'\u2AB0', '\u0338'},
    +		"nsubE;":                   {'\u2AC5', '\u0338'},
    +		"nsubset;":                 {'\u2282', '\u20D2'},
    +		"nsubseteqq;":              {'\u2AC5', '\u0338'},
    +		"nsucceq;":                 {'\u2AB0', '\u0338'},
    +		"nsupE;":                   {'\u2AC6', '\u0338'},
    +		"nsupset;":                 {'\u2283', '\u20D2'},
    +		"nsupseteqq;":              {'\u2AC6', '\u0338'},
    +		"nvap;":                    {'\u224D', '\u20D2'},
    +		"nvge;":                    {'\u2265', '\u20D2'},
    +		"nvgt;":                    {'\u003E', '\u20D2'},
    +		"nvle;":                    {'\u2264', '\u20D2'},
    +		"nvlt;":                    {'\u003C', '\u20D2'},
    +		"nvltrie;":                 {'\u22B4', '\u20D2'},
    +		"nvrtrie;":                 {'\u22B5', '\u20D2'},
    +		"nvsim;":                   {'\u223C', '\u20D2'},
    +		"race;":                    {'\u223D', '\u0331'},
    +		"smtes;":                   {'\u2AAC', '\uFE00'},
    +		"sqcaps;":                  {'\u2293', '\uFE00'},
    +		"sqcups;":                  {'\u2294', '\uFE00'},
    +		"varsubsetneq;":            {'\u228A', '\uFE00'},
    +		"varsubsetneqq;":           {'\u2ACB', '\uFE00'},
    +		"varsupsetneq;":            {'\u228B', '\uFE00'},
    +		"varsupsetneqq;":           {'\u2ACC', '\uFE00'},
    +		"vnsub;":                   {'\u2282', '\u20D2'},
    +		"vnsup;":                   {'\u2283', '\u20D2'},
    +		"vsubnE;":                  {'\u2ACB', '\uFE00'},
    +		"vsubne;":                  {'\u228A', '\uFE00'},
    +		"vsupnE;":                  {'\u2ACC', '\uFE00'},
    +		"vsupne;":                  {'\u228B', '\uFE00'},
    +	}
     }
    diff --git a/src/html/entity_test.go b/src/html/entity_test.go
    index b53f866fa2..6688ed2c43 100644
    --- a/src/html/entity_test.go
    +++ b/src/html/entity_test.go
    @@ -9,7 +9,15 @@ import (
     	"unicode/utf8"
     )
     
    +func init() {
    +	UnescapeString("") // force load of entity maps
    +}
    +
     func TestEntityLength(t *testing.T) {
    +	if len(entity) == 0 || len(entity2) == 0 {
    +		t.Fatal("maps not loaded")
    +	}
    +
     	// We verify that the length of UTF-8 encoding of each value is <= 1 + len(key).
     	// The +1 comes from the leading "&". This property implies that the length of
     	// unescaped text is <= the length of escaped text.
    diff --git a/src/html/escape.go b/src/html/escape.go
    index 8dd1f4ad2f..dae404fab1 100644
    --- a/src/html/escape.go
    +++ b/src/html/escape.go
    @@ -185,6 +185,7 @@ func EscapeString(s string) string {
     // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
     // always true.
     func UnescapeString(s string) string {
    +	populateMapsOnce.Do(populateMaps)
     	i := strings.IndexByte(s, '&')
     
     	if i < 0 {
    diff --git a/src/html/template/content.go b/src/html/template/content.go
    index 4aadf64df2..6ba87a9550 100644
    --- a/src/html/template/content.go
    +++ b/src/html/template/content.go
    @@ -169,8 +169,17 @@ func stringify(args ...interface{}) (string, contentType) {
     			return string(s), contentTypeSrcset
     		}
     	}
    -	for i, arg := range args {
    +	i := 0
    +	for _, arg := range args {
    +		// We skip untyped nil arguments for backward compatibility.
    +		// Without this they would be output as , escaped.
    +		// See issue 25875.
    +		if arg == nil {
    +			continue
    +		}
    +
     		args[i] = indirectToStringerOrError(arg)
    +		i++
     	}
    -	return fmt.Sprint(args...), contentTypePlain
    +	return fmt.Sprint(args[:i]...), contentTypePlain
     }
    diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
    index cc092f50c0..72d56f50c1 100644
    --- a/src/html/template/content_test.go
    +++ b/src/html/template/content_test.go
    @@ -447,10 +447,9 @@ func TestEscapingNilNonemptyInterfaces(t *testing.T) {
     	testData := struct{ E error }{} // any non-empty interface here will do; error is just ready at hand
     	tmpl.Execute(got, testData)
     
    -	// Use this data instead of just hard-coding "<nil>" to avoid
    -	// dependencies on the html escaper and the behavior of fmt w.r.t. nil.
    +	// A non-empty interface should print like an empty interface.
     	want := new(bytes.Buffer)
    -	data := struct{ E string }{E: fmt.Sprint(nil)}
    +	data := struct{ E interface{} }{}
     	tmpl.Execute(want, data)
     
     	if !bytes.Equal(want.Bytes(), got.Bytes()) {
    diff --git a/src/html/template/context.go b/src/html/template/context.go
    index 45be3a6a9f..7ab3d1fed6 100644
    --- a/src/html/template/context.go
    +++ b/src/html/template/context.go
    @@ -48,19 +48,19 @@ func (c context) mangle(templateName string) string {
     		return templateName
     	}
     	s := templateName + "$htmltemplate_" + c.state.String()
    -	if c.delim != 0 {
    +	if c.delim != delimNone {
     		s += "_" + c.delim.String()
     	}
    -	if c.urlPart != 0 {
    +	if c.urlPart != urlPartNone {
     		s += "_" + c.urlPart.String()
     	}
    -	if c.jsCtx != 0 {
    +	if c.jsCtx != jsCtxRegexp {
     		s += "_" + c.jsCtx.String()
     	}
    -	if c.attr != 0 {
    +	if c.attr != attrNone {
     		s += "_" + c.attr.String()
     	}
    -	if c.element != 0 {
    +	if c.element != elementNone {
     		s += "_" + c.element.String()
     	}
     	return s
    diff --git a/src/html/template/doc.go b/src/html/template/doc.go
    index 35d171c3fc..290ec81b96 100644
    --- a/src/html/template/doc.go
    +++ b/src/html/template/doc.go
    @@ -70,6 +70,9 @@ In this case it becomes
     where urlescaper, attrescaper, and htmlescaper are aliases for internal escaping
     functions.
     
    +For these internal escaping functions, if an action pipeline evaluates to
    +a nil interface value, it is treated as though it were an empty string.
    +
     Errors
     
     See the documentation of ErrorCode for details.
    diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
    index d5c258ecaa..e6c12a8a25 100644
    --- a/src/html/template/escape_test.go
    +++ b/src/html/template/escape_test.go
    @@ -35,7 +35,8 @@ func TestEscape(t *testing.T) {
     		A, E    []string
     		B, M    json.Marshaler
     		N       int
    -		Z       *int
    +		U       interface{} // untyped nil
    +		Z       *int        // typed nil
     		W       HTML
     	}{
     		F: false,
    @@ -48,6 +49,7 @@ func TestEscape(t *testing.T) {
     		N: 42,
     		B: &badMarshaler{},
     		M: &goodMarshaler{},
    +		U: nil,
     		Z: nil,
     		W: HTML(`¡Hello, !`),
     	}
    @@ -113,6 +115,16 @@ func TestEscape(t *testing.T) {
     			"{{.T}}",
     			"true",
     		},
    +		{
    +			"untypedNilValue",
    +			"{{.U}}",
    +			"",
    +		},
    +		{
    +			"typedNilValue",
    +			"{{.Z}}",
    +			"<nil>",
    +		},
     		{
     			"constant",
     			``,
    @@ -199,10 +211,15 @@ func TestEscape(t *testing.T) {
     			`